tools/qdoc3/cppcodeparser.cpp
branchGCC_SURGE
changeset 31 5daf16870df6
parent 30 5dc02b23752f
child 33 3e2da88830cd
equal deleted inserted replaced
27:93b982ccede2 31:5daf16870df6
    41 
    41 
    42 /*
    42 /*
    43   cppcodeparser.cpp
    43   cppcodeparser.cpp
    44 */
    44 */
    45 
    45 
    46 #include <QtCore>
       
    47 #include <qfile.h>
    46 #include <qfile.h>
    48 
    47 
    49 #include <stdio.h>
    48 #include <stdio.h>
    50 #include <errno.h>
    49 #include <errno.h>
       
    50 #include <qdebug.h>
    51 
    51 
    52 #include "codechunk.h"
    52 #include "codechunk.h"
    53 #include "config.h"
    53 #include "config.h"
    54 #include "cppcodeparser.h"
    54 #include "cppcodeparser.h"
    55 #include "tokenizer.h"
    55 #include "tokenizer.h"
    93 #define COMMAND_QMLSIGNAL               Doc::alias("qmlsignal")
    93 #define COMMAND_QMLSIGNAL               Doc::alias("qmlsignal")
    94 #define COMMAND_QMLATTACHEDSIGNAL       Doc::alias("qmlattachedsignal")
    94 #define COMMAND_QMLATTACHEDSIGNAL       Doc::alias("qmlattachedsignal")
    95 #define COMMAND_QMLMETHOD               Doc::alias("qmlmethod")
    95 #define COMMAND_QMLMETHOD               Doc::alias("qmlmethod")
    96 #define COMMAND_QMLATTACHEDMETHOD       Doc::alias("qmlattachedmethod")
    96 #define COMMAND_QMLATTACHEDMETHOD       Doc::alias("qmlattachedmethod")
    97 #define COMMAND_QMLDEFAULT              Doc::alias("default")
    97 #define COMMAND_QMLDEFAULT              Doc::alias("default")
       
    98 #define COMMAND_QMLBASICTYPE            Doc::alias("qmlbasictype")
    98 #endif
    99 #endif
    99 
   100 
   100 QStringList CppCodeParser::exampleFiles;
   101 QStringList CppCodeParser::exampleFiles;
   101 QStringList CppCodeParser::exampleDirs;
   102 QStringList CppCodeParser::exampleDirs;
   102 
   103 
   278  */
   279  */
   279 void CppCodeParser::parseHeaderFile(const Location& location,
   280 void CppCodeParser::parseHeaderFile(const Location& location,
   280                                     const QString& filePath,
   281                                     const QString& filePath,
   281                                     Tree *tree)
   282                                     Tree *tree)
   282 {
   283 {
   283     FILE *in = fopen(QFile::encodeName(filePath), "r");
   284     QFile in(filePath);
   284     if (!in) {
   285     if (!in.open(QIODevice::ReadOnly)) {
   285         location.error(tr("Cannot open C++ header file '%1'").arg(filePath));
   286         location.error(tr("Cannot open C++ header file '%1'").arg(filePath));
   286         return;
   287         return;
   287     }
   288     }
   288 
   289 
   289     reset(tree);
   290     reset(tree);
   292     tokenizer = &fileTokenizer;
   293     tokenizer = &fileTokenizer;
   293     readToken();
   294     readToken();
   294     matchDeclList(tree->root());
   295     matchDeclList(tree->root());
   295     if (!fileTokenizer.version().isEmpty())
   296     if (!fileTokenizer.version().isEmpty())
   296         tree->setVersion(fileTokenizer.version());
   297         tree->setVersion(fileTokenizer.version());
   297     fclose(in);
   298     in.close();
   298 
   299 
   299     if (fileLocation.fileName() == "qiterator.h")
   300     if (fileLocation.fileName() == "qiterator.h")
   300         parseQiteratorDotH(location, filePath);
   301         parseQiteratorDotH(location, filePath);
   301 }
   302 }
   302 
   303 
   309  */
   310  */
   310 void CppCodeParser::parseSourceFile(const Location& location,
   311 void CppCodeParser::parseSourceFile(const Location& location,
   311                                     const QString& filePath,
   312                                     const QString& filePath,
   312                                     Tree *tree)
   313                                     Tree *tree)
   313 {
   314 {
   314     FILE *in = fopen(QFile::encodeName(filePath), "r");
   315     QFile in(filePath);
   315     if (!in) {
   316     if (!in.open(QIODevice::ReadOnly)) {
   316         location.error(tr("Cannot open C++ source file '%1' (%2)").arg(filePath).arg(strerror(errno)));
   317         location.error(tr("Cannot open C++ source file '%1' (%2)").arg(filePath).arg(strerror(errno)));
   317         return;
   318         return;
   318     }
   319     }
   319 
   320 
   320     reset(tree);
   321     reset(tree);
   322     Tokenizer fileTokenizer(fileLocation, in);
   323     Tokenizer fileTokenizer(fileLocation, in);
   323     tokenizer = &fileTokenizer;
   324     tokenizer = &fileTokenizer;
   324     readToken();
   325     readToken();
   325     usedNamespaces.clear();
   326     usedNamespaces.clear();
   326     matchDocsAndStuff();
   327     matchDocsAndStuff();
   327     fclose(in);
   328     in.close();
   328 }
   329 }
   329 
   330 
   330 /*!
   331 /*!
   331   This is called after all the header files have been parsed.
   332   This is called after all the header files have been parsed.
   332   I think the most important thing it does is resolve class
   333   I think the most important thing it does is resolve class
   489                     }
   490                     }
   490                     if (j == params1.count())
   491                     if (j == params1.count())
   491                         candidates << overload;
   492                         candidates << overload;
   492                 }
   493                 }
   493 
   494 
   494                 
   495 
   495                 /*
   496                 /*
   496                     There are several functions with the correct
   497                     There are several functions with the correct
   497                     parameter count, but only one has the correct
   498                     parameter count, but only one has the correct
   498                     types, loosely compared.
   499                     types, loosely compared.
   499                 */
   500                 */
   534                            << COMMAND_QMLPROPERTY
   535                            << COMMAND_QMLPROPERTY
   535                            << COMMAND_QMLATTACHEDPROPERTY
   536                            << COMMAND_QMLATTACHEDPROPERTY
   536                            << COMMAND_QMLSIGNAL
   537                            << COMMAND_QMLSIGNAL
   537                            << COMMAND_QMLATTACHEDSIGNAL
   538                            << COMMAND_QMLATTACHEDSIGNAL
   538                            << COMMAND_QMLMETHOD
   539                            << COMMAND_QMLMETHOD
   539                            << COMMAND_QMLATTACHEDMETHOD;
   540                            << COMMAND_QMLATTACHEDMETHOD
       
   541                            << COMMAND_QMLBASICTYPE;
   540 #else
   542 #else
   541                            << COMMAND_VARIABLE;
   543                            << COMMAND_VARIABLE;
   542 #endif
   544 #endif
   543 }
   545 }
   544 
   546 
   545 /*!
   547 /*!
   546   Process the topic \a command in context \a doc with argument \a arg.  
   548   Process the topic \a command in context \a doc with argument \a arg.
   547  */
   549  */
   548 Node *CppCodeParser::processTopicCommand(const Doc& doc,
   550 Node *CppCodeParser::processTopicCommand(const Doc& doc,
   549                                          const QString& command,
   551                                          const QString& command,
   550                                          const QString& arg)
   552                                          const QString& arg)
   551 {
   553 {
   725             Node* n = tre->findNode(names[1].split("::"),Node::Class);
   727             Node* n = tre->findNode(names[1].split("::"),Node::Class);
   726             if (n)
   728             if (n)
   727                 classNode = static_cast<const ClassNode*>(n);
   729                 classNode = static_cast<const ClassNode*>(n);
   728         }
   730         }
   729         return new QmlClassNode(tre->root(), names[0], classNode);
   731         return new QmlClassNode(tre->root(), names[0], classNode);
       
   732     }
       
   733     else if (command == COMMAND_QMLBASICTYPE) {
       
   734 #if 0
       
   735         QStringList parts = arg.split(" ");
       
   736         qDebug() << command << parts;
       
   737         if (parts.size() > 1) {
       
   738             FakeNode* pageNode = static_cast<FakeNode*>(tre->root()->findNode(parts[1], Node::Fake));
       
   739             if (pageNode) {
       
   740                 qDebug() << "FOUND";
       
   741                 return new QmlBasicTypeNode(pageNode, parts[0]);
       
   742             }
       
   743         }
       
   744 #endif
       
   745         return new QmlBasicTypeNode(tre->root(), arg);
   730     }
   746     }
   731     else if ((command == COMMAND_QMLSIGNAL) ||
   747     else if ((command == COMMAND_QMLSIGNAL) ||
   732              (command == COMMAND_QMLMETHOD) ||
   748              (command == COMMAND_QMLMETHOD) ||
   733              (command == COMMAND_QMLATTACHEDSIGNAL) ||
   749              (command == COMMAND_QMLATTACHEDSIGNAL) ||
   734              (command == COMMAND_QMLATTACHEDMETHOD)) {
   750              (command == COMMAND_QMLATTACHEDMETHOD)) {
   894                                 << COMMAND_RELATES
   910                                 << COMMAND_RELATES
   895                                 << COMMAND_CONTENTSPAGE
   911                                 << COMMAND_CONTENTSPAGE
   896                                 << COMMAND_NEXTPAGE
   912                                 << COMMAND_NEXTPAGE
   897                                 << COMMAND_PREVIOUSPAGE
   913                                 << COMMAND_PREVIOUSPAGE
   898                                 << COMMAND_INDEXPAGE
   914                                 << COMMAND_INDEXPAGE
   899 #ifdef QDOC_QML        
   915 #ifdef QDOC_QML
   900                                 << COMMAND_STARTPAGE
   916                                 << COMMAND_STARTPAGE
   901                                 << COMMAND_QMLINHERITS
   917                                 << COMMAND_QMLINHERITS
   902                                 << COMMAND_QMLDEFAULT;
   918                                 << COMMAND_QMLDEFAULT;
   903 #else    
   919 #else
   904                                 << COMMAND_STARTPAGE;
   920                                 << COMMAND_STARTPAGE;
   905 #endif    
   921 #endif
   906 }
   922 }
   907 
   923 
   908 /*!
   924 /*!
   909   Process the metacommand \a command in the context of the
   925   Process the metacommand \a command in the context of the
   910   \a node associated with the topic command and the \a doc.
   926   \a node associated with the topic command and the \a doc.
  1015         setLink(node, Node::StartLink, arg);
  1031         setLink(node, Node::StartLink, arg);
  1016     }
  1032     }
  1017 #ifdef QDOC_QML
  1033 #ifdef QDOC_QML
  1018     else if (command == COMMAND_QMLINHERITS) {
  1034     else if (command == COMMAND_QMLINHERITS) {
  1019         setLink(node, Node::InheritsLink, arg);
  1035         setLink(node, Node::InheritsLink, arg);
  1020     }
  1036         if (node->subType() == Node::QmlClass) {
       
  1037             QmlClassNode::addInheritedBy(arg,node);
       
  1038         }
       
  1039    }
  1021     else if (command == COMMAND_QMLDEFAULT) {
  1040     else if (command == COMMAND_QMLDEFAULT) {
  1022         QmlPropGroupNode* qpgn = static_cast<QmlPropGroupNode*>(node);
  1041         QmlPropGroupNode* qpgn = static_cast<QmlPropGroupNode*>(node);
  1023         qpgn->setDefault();
  1042         qpgn->setDefault();
  1024     }
  1043     }
  1025 #endif
  1044 #endif
  1630     /*
  1649     /*
  1631         So far, so good. We have 'namespace Foo {'.
  1650         So far, so good. We have 'namespace Foo {'.
  1632     */
  1651     */
  1633     QString namespaceName = previousLexeme();
  1652     QString namespaceName = previousLexeme();
  1634     NamespaceNode *namespasse = 0;
  1653     NamespaceNode *namespasse = 0;
  1635     if (parent)
  1654     if (parent) {
  1636         namespasse = static_cast<NamespaceNode*>(parent->findNode(namespaceName, Node::Namespace));
  1655         namespasse = static_cast<NamespaceNode*>(parent->findNode(namespaceName, Node::Namespace));
       
  1656     }
  1637     if (!namespasse) {
  1657     if (!namespasse) {
  1638         namespasse = new NamespaceNode(parent, namespaceName);
  1658         namespasse = new NamespaceNode(parent, namespaceName);
  1639         namespasse->setAccess(access);
  1659         namespasse->setAccess(access);
  1640         namespasse->setLocation(location());
  1660         namespasse->setLocation(location());
  1641     }
  1661     }
  2097                         nodes.append(node);
  2117                         nodes.append(node);
  2098                         docs.append(nodeDoc);
  2118                         docs.append(nodeDoc);
  2099                     }
  2119                     }
  2100                     ++a;
  2120                     ++a;
  2101                 }
  2121                 }
  2102 #endif                
  2122 #endif
  2103             }
  2123             }
  2104 
  2124 
  2105             NodeList::Iterator n = nodes.begin();
  2125             NodeList::Iterator n = nodes.begin();
  2106             QList<Doc>::Iterator d = docs.begin();
  2126             QList<Doc>::Iterator d = docs.begin();
  2107             while (n != nodes.end()) {
  2127             while (n != nodes.end()) {
  2246 }
  2266 }
  2247 
  2267 
  2248 void CppCodeParser::createExampleFileNodes(FakeNode *fake)
  2268 void CppCodeParser::createExampleFileNodes(FakeNode *fake)
  2249 {
  2269 {
  2250     QString examplePath = fake->name();
  2270     QString examplePath = fake->name();
  2251 
  2271     QString proFileName = examplePath + "/" + examplePath.split("/").last() + ".pro";
  2252     // we can assume that this file always exists
       
  2253     QString proFileName = examplePath + "/" +
       
  2254         examplePath.split("/").last() + ".pro";
       
  2255 
       
  2256     QString userFriendlyFilePath;
  2272     QString userFriendlyFilePath;
       
  2273 
  2257     QString fullPath = Config::findFile(fake->doc().location(),
  2274     QString fullPath = Config::findFile(fake->doc().location(),
  2258                                         exampleFiles,
  2275                                         exampleFiles,
  2259                                         exampleDirs,
  2276                                         exampleDirs,
  2260                                         proFileName,
  2277                                         proFileName,
  2261                                         userFriendlyFilePath);
  2278                                         userFriendlyFilePath);
  2262     
  2279 
  2263     if (fullPath.isEmpty()) {
  2280     if (fullPath.isEmpty()) {
  2264         QString tmp = proFileName;
  2281         QString tmp = proFileName;
  2265         proFileName = examplePath + "/" + "qbuild.pro";
  2282         proFileName = examplePath + "/" + "qbuild.pro";
  2266         userFriendlyFilePath.clear();
  2283         userFriendlyFilePath.clear();
  2267         fullPath = Config::findFile(fake->doc().location(),
  2284         fullPath = Config::findFile(fake->doc().location(),
  2268                                     exampleFiles,
  2285                                     exampleFiles,
  2269                                     exampleDirs,
  2286                                     exampleDirs,
  2270                                     proFileName,
  2287                                     proFileName,
  2271                                     userFriendlyFilePath);
  2288                                     userFriendlyFilePath);
  2272         if (fullPath.isEmpty()) {
  2289         if (fullPath.isEmpty()) {
  2273             fake->doc().location().warning(
  2290             proFileName = examplePath + "/" + examplePath.split("/").last() + ".qmlproject";
  2274                tr("Cannot find file '%1' or '%2'").arg(tmp).arg(proFileName));
  2291             userFriendlyFilePath.clear();
  2275             return;
  2292             fullPath = Config::findFile(fake->doc().location(),
       
  2293                                         exampleFiles,
       
  2294                                         exampleDirs,
       
  2295                                         proFileName,
       
  2296                                         userFriendlyFilePath);
       
  2297             if (fullPath.isEmpty()) {
       
  2298                 fake->doc().location().warning(
       
  2299                     tr("Cannot find file '%1' or '%2'").arg(tmp).arg(proFileName));
       
  2300                 return;
       
  2301             }
  2276         }
  2302         }
  2277     }
  2303     }
  2278 
  2304 
  2279     int sizeOfBoringPartOfName = fullPath.size() - proFileName.size();
  2305     int sizeOfBoringPartOfName = fullPath.size() - proFileName.size();
  2280     fullPath.truncate(fullPath.lastIndexOf('/'));
  2306     fullPath.truncate(fullPath.lastIndexOf('/'));
  2281 
  2307 
  2282     QStringList exampleFiles = Config::getFilesHere(fullPath,exampleNameFilter);
  2308     QStringList exampleFiles = Config::getFilesHere(fullPath,exampleNameFilter);
  2283     QString imagesPath = fullPath + "/images";
  2309     QString imagesPath = fullPath + "/images";
  2284     QStringList imageFiles = Config::getFilesHere(imagesPath,exampleImageFilter);
  2310     QStringList imageFiles = Config::getFilesHere(imagesPath,exampleImageFilter);
  2285 
       
  2286 #if 0    
       
  2287     qDebug() << "examplePath:" << examplePath;
       
  2288     qDebug() << " exampleFiles" <<  exampleFiles;
       
  2289     qDebug() << "imagesPath:" << imagesPath;
       
  2290     qDebug() << "fullPath:" << fullPath;
       
  2291     qDebug() << " imageFiles" <<  imageFiles;
       
  2292 #endif    
       
  2293 
  2311 
  2294     if (!exampleFiles.isEmpty()) {
  2312     if (!exampleFiles.isEmpty()) {
  2295         // move main.cpp and to the end, if it exists
  2313         // move main.cpp and to the end, if it exists
  2296         QString mainCpp;
  2314         QString mainCpp;
  2297         QMutableStringListIterator i(exampleFiles);
  2315         QMutableStringListIterator i(exampleFiles);
  2301             if (fileName.endsWith("/main.cpp")) {
  2319             if (fileName.endsWith("/main.cpp")) {
  2302                 mainCpp = fileName;
  2320                 mainCpp = fileName;
  2303                 i.remove();
  2321                 i.remove();
  2304             }
  2322             }
  2305             else if (fileName.contains("/qrc_") || fileName.contains("/moc_")
  2323             else if (fileName.contains("/qrc_") || fileName.contains("/moc_")
  2306                     || fileName.contains("/ui_"))
  2324                 || fileName.contains("/ui_"))
  2307                 i.remove();
  2325                 i.remove();
  2308         }
  2326         }
  2309         if (!mainCpp.isEmpty())
  2327         if (!mainCpp.isEmpty())
  2310             exampleFiles.append(mainCpp);
  2328             exampleFiles.append(mainCpp);
  2311 
  2329 
  2312         // add any qmake Qt resource files and qmake project files
  2330         // add any qmake Qt resource files and qmake project files
  2313         exampleFiles += Config::getFilesHere(fullPath, "*.qrc *.pro");
  2331         exampleFiles += Config::getFilesHere(fullPath, "*.qrc *.pro qmldir");
  2314     }
  2332     }
  2315 
  2333 
  2316     foreach (const QString &exampleFile, exampleFiles)
  2334     foreach (const QString &exampleFile, exampleFiles)
  2317         (void) new FakeNode(fake,
  2335         (void) new FakeNode(fake,
  2318                             exampleFile.mid(sizeOfBoringPartOfName),
  2336                             exampleFile.mid(sizeOfBoringPartOfName),