diff options
author | Martin Smith <martin.smith@qt.io> | 2017-02-09 14:21:24 +0100 |
---|---|---|
committer | Martin Smith <martin.smith@qt.io> | 2017-08-10 07:34:24 +0000 |
commit | 7414d80fb8b1e7ea895456d2dbaee6b811aa297f (patch) | |
tree | 84256e6e6798c75ed7aeacefc38e8f19f068316e /src/qdoc/clangcodeparser.cpp | |
parent | 2cb31888282c693b7917e1a0f86f11daef854f8c (diff) | |
download | qttools-7414d80fb8b1e7ea895456d2dbaee6b811aa297f.tar.gz |
qdoc: Create and Visit the PCH always
The PCH for module QtPlatformHeaders was not being built
because there are no .cpp files there, and clangqdoc was
only building the PCH when it was asked to parse the first
.cpp file. Now it builds the PCH by a direct call from the
main.cpp file, after the headers have been gathered into a
list, but before the .cpp files are parsed.
This does reduce the qdoc error count by a few, but it does
not fix the documentation for QtPlatformHeaders. From my
debugging, it appears that visiting the PCH produces no qdoc
nodes for the C++ classes and functions, etc in the PCH.
This update also improves the selection of default include
paths when inadequate include paths are provided. That is
the case for module QtPlatformHeaders, where no include
paths are provided. The algorithm for constructing a list
of reasonable guesses is modified here.
Change-Id: I0dee8dc0279894a4482df30703657558cdb098de
Reviewed-by: Topi Reiniƶ <topi.reinio@qt.io>
Diffstat (limited to 'src/qdoc/clangcodeparser.cpp')
-rw-r--r-- | src/qdoc/clangcodeparser.cpp | 196 |
1 files changed, 116 insertions, 80 deletions
diff --git a/src/qdoc/clangcodeparser.cpp b/src/qdoc/clangcodeparser.cpp index db3461c7f..65c9b6d14 100644 --- a/src/qdoc/clangcodeparser.cpp +++ b/src/qdoc/clangcodeparser.cpp @@ -53,14 +53,17 @@ QT_BEGIN_NAMESPACE +static CXTranslationUnit_Flags flags_ = (CXTranslationUnit_Flags)0; +static CXIndex index_ = 0; + /*! Call clang_visitChildren on the given cursor with the lambda as a callback - T can be any functor that is callable with a CXCursor parametter and returns a CXChildVisitResult + T can be any functor that is callable with a CXCursor parameter and returns a CXChildVisitResult (in other word compatible with function<CXChildVisitResult(CXCursor)> */ template <typename T> bool visitChildrenLambda(CXCursor cursor, T &&lambda) { - auto visitor = [](CXCursor c, CXCursor , CXClientData client_data) -> CXChildVisitResult + CXCursorVisitor visitor = [](CXCursor c, CXCursor , CXClientData client_data) -> CXChildVisitResult { return (*static_cast<T*>(client_data))(c); }; return clang_visitChildren(cursor, visitor, &lambda); } @@ -261,8 +264,9 @@ public: isInterestingCache_[file] = isInteresting; } - if (isInteresting) + if (isInteresting) { return visitHeader(cur, loc); + } return CXChildVisit_Continue; }); @@ -870,68 +874,87 @@ void ClangCodeParser::parseHeaderFile(const Location & /*location*/, const QStri allHeaders_.insert(fi.canonicalFilePath()); } -#define INCLUDE_PRIVATE_HEADERS -/*! - Get ready to parse the C++ cpp file identified by \a filePath - and add its parsed contents to the database. \a location is - used for reporting errors. +static const char *defaultArgs_[] = { + "-std=c++14", + "-fPIC", + "-fno-exceptions", // Workaround for clang bug http://reviews.llvm.org/D17988 + "-DQ_QDOC", + "-DQT_DISABLE_DEPRECATED_BEFORE=0", + "-DQT_ANNOTATE_CLASS(type,...)=static_assert(sizeof(#__VA_ARGS__), #type);", + "-DQT_ANNOTATE_CLASS2(type,a1,a2)=static_assert(sizeof(#a1, #a2), #type);", + "-DQT_ANNOTATE_FUNCTION(a)=__attribute__((annotate(#a)))", + "-DQT_ANNOTATE_ACCESS_SPECIFIER(a)=__attribute__((annotate(#a)))", + "-Wno-constant-logical-operand", +#ifdef Q_OS_WIN + "-fms-compatibility-version=19", +#endif + "-I" CLANG_RESOURCE_DIR +}; - Call matchDocsAndStuff() to do all the parsing and tree building. +/*! + Load the default arguments and the defines into \a args. + Clear \a args first. */ -void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QString& filePath) +void ClangCodeParser::getDefaultArgs() { - const char *defaultArgs[] = { "-std=c++14", - "-fPIC", - "-fno-exceptions", // Workaround for clang bug http://reviews.llvm.org/D17988 - "-DQ_QDOC", - "-DQT_DISABLE_DEPRECATED_BEFORE=0", - "-DQT_ANNOTATE_CLASS(type,...)=static_assert(sizeof(#__VA_ARGS__), #type);", - "-DQT_ANNOTATE_CLASS2(type,a1,a2)=static_assert(sizeof(#a1, #a2), #type);", - "-DQT_ANNOTATE_FUNCTION(a)=__attribute__((annotate(#a)))", - "-DQT_ANNOTATE_ACCESS_SPECIFIER(a)=__attribute__((annotate(#a)))", - "-Wno-constant-logical-operand", -#ifdef Q_OS_WIN - "-fms-compatibility-version=19", -#endif - "-I" CLANG_RESOURCE_DIR - }; - std::vector<const char *> args(std::begin(defaultArgs), std::end(defaultArgs)); + args_.clear(); + args_.insert(args_.begin(), std::begin(defaultArgs_), std::end(defaultArgs_)); // Add the defines from the qdocconf file. for (const auto &p : qAsConst(defines_)) - args.push_back(p.constData()); + args_.push_back(p.constData()); +} - auto moreArgs = includePaths_; - if (moreArgs.isEmpty()) { - // Try to guess the include paths if none were given. +/*! + Load the include paths into \a moreArgs. + */ +void ClangCodeParser::getMoreArgs() +{ + if (includePaths_.isEmpty() || includePaths_.at(0) != QByteArray("-I")) { + /* + The include paths provided are inadequate. Make a list + of reasonable places to look for include files and use + that list instead. + */ + QList<QString> headers = allHeaders_.values(); + QString filePath = headers.at(0); auto forest = qdb_->searchOrder(); - QByteArray installDocDir = Config::installDir.toUtf8(); + QByteArray version = qdb_->version().toUtf8(); - moreArgs += "-I" + installDocDir + "/../include"; - moreArgs += "-I" + filePath.toUtf8() + "/../"; - moreArgs += "-I" + filePath.toUtf8() + "/../../"; + QString basicIncludeDir = QDir::cleanPath(QString(Config::installDir + "/../include")); + moreArgs_ += "-I" + basicIncludeDir.toLatin1(); + moreArgs_ += "-I" + QDir::cleanPath(QString(filePath + "/../")).toLatin1(); + moreArgs_ += "-I" + QDir::cleanPath(QString(filePath + "/../../")).toLatin1(); for (const auto &s : forest) { - QByteArray module = s->camelCaseModuleName().toUtf8(); - moreArgs += "-I" + installDocDir + "/../include/" + module; - moreArgs += "-I" + installDocDir + "/../include/" + module + "/" + version; - moreArgs += "-I" + installDocDir + "/../include/" + module + "/" + version + "/" + module; + QString module = basicIncludeDir +"/" + s->camelCaseModuleName(); + moreArgs_ += QString("-I" + module).toLatin1(); + moreArgs_ += QString("-I" + module + "/" + qdb_->version()).toLatin1(); + moreArgs_ += QString("-I" + module + "/" + qdb_->version() + "/" + module).toLatin1(); + } + for (int i=0; i<includePaths_.size(); ++i) { + if (!includePaths_.at(i).startsWith("-")) + moreArgs_ += "-I" + includePaths_.at(i); + else + moreArgs_ += includePaths_.at(i); } } + else { + moreArgs_ = includePaths_; + } +} - for (const auto &p : qAsConst(moreArgs)) - args.push_back(p.constData()); - - auto flags = CXTranslationUnit_Incomplete | CXTranslationUnit_SkipFunctionBodies | - CXTranslationUnit_KeepGoing; - CXIndex index = clang_createIndex(1, 0); - +/*! + Building the PCH must be possible when there are no .cpp + files, so it is moved here to its own member function, and + it is called after the list of header files is complete. + */ +void ClangCodeParser::buildPCH() +{ if (!pchFileDir_) { pchFileDir_.reset(new QTemporaryDir(QDir::tempPath() + QLatin1String("/qdoc_pch"))); if (pchFileDir_->isValid()) { const QByteArray module = qdb_->primaryTreeRoot()->tree()->camelCaseModuleName().toUtf8(); QByteArray header; -#ifdef INCLUDE_PRIVATE_HEADERS QByteArray privateHeaderDir; -#endif // Find the path to the module's header (e.g. QtGui/QtGui) to be used // as pre-compiled header for (const auto &p : qAsConst(includePaths_)) { @@ -943,7 +966,6 @@ void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QStrin } } } -#ifdef INCLUDE_PRIVATE_HEADERS // Find the path to the module's private header directory (e.g. // include/QtGui/5.8.0/QtGui/private) to use for including all // the private headers in the PCH. @@ -956,7 +978,6 @@ void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QStrin } } } -#endif if (header.isEmpty()) { QByteArray installDocDir = Config::installDir.toUtf8(); const QByteArray candidate = installDocDir + "/../include/" + module + "/" + module; @@ -967,9 +988,8 @@ void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QStrin qWarning() << "Could not find the module header in the include path for module" << module << " (include paths: "<< includePaths_ << ")"; } else { - args.push_back("-xc++"); + args_.push_back("-xc++"); CXTranslationUnit tu; -#ifdef INCLUDE_PRIVATE_HEADERS QString tmpHeader = pchFileDir_->path() + "/" + module; if (QFile::copy(header, tmpHeader) && !privateHeaderDir.isEmpty()) { privateHeaderDir = QDir::cleanPath(privateHeaderDir.constData()).toLatin1(); @@ -990,19 +1010,13 @@ void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QStrin } } } -#endif - CXErrorCode err = clang_parseTranslationUnit2(index, -#ifdef INCLUDE_PRIVATE_HEADERS + CXErrorCode err = clang_parseTranslationUnit2(index_, tmpHeader.toLatin1().data(), -#else - header.constData(), -#endif - args.data(), args.size(), nullptr, 0, - flags | CXTranslationUnit_ForSerialization, &tu); + args_.data(), args_.size(), nullptr, 0, + flags_ | CXTranslationUnit_ForSerialization, &tu); if (!err && tu) { pchName_ = pchFileDir_->path().toUtf8() + "/" + module + ".pch"; - auto error = clang_saveTranslationUnit(tu, pchName_.constData(), - clang_defaultSaveOptions(tu)); + auto error = clang_saveTranslationUnit(tu, pchName_.constData(), clang_defaultSaveOptions(tu)); if (error) { qWarning() << "Could not save PCH file for " << module << error; pchName_.clear(); @@ -1016,37 +1030,59 @@ void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QStrin } else { pchFileDir_->remove(); qWarning() << "Could not create PCH file for " -#ifdef INCLUDE_PRIVATE_HEADERS << tmpHeader -#else - << header -#endif << " error code:" << err; } - args.pop_back(); // remove the "-xc++"; + args_.pop_back(); // remove the "-xc++"; } } qdb_->resolveInheritance(); } - args.clear(); - args.insert(args.begin(), std::begin(defaultArgs), std::end(defaultArgs)); - // Add the defines from the qdocconf file. - for (const auto &p : qAsConst(defines_)) - args.push_back(p.constData()); +} + +/*! + Precompile the header files for the current module. + */ +void ClangCodeParser::precompileHeaders() +{ + getDefaultArgs(); + getMoreArgs(); + for (const auto &p : qAsConst(moreArgs_)) + args_.push_back(p.constData()); + + flags_ = (CXTranslationUnit_Flags) (CXTranslationUnit_Incomplete | CXTranslationUnit_SkipFunctionBodies | CXTranslationUnit_KeepGoing); + index_ = clang_createIndex(1, 0); + buildPCH(); + clang_disposeIndex(index_); +} + +/*! + Get ready to parse the C++ cpp file identified by \a filePath + and add its parsed contents to the database. \a location is + used for reporting errors. + + Call matchDocsAndStuff() to do all the parsing and tree building. + */ +void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QString& filePath) +{ + flags_ = (CXTranslationUnit_Flags) (CXTranslationUnit_Incomplete | CXTranslationUnit_SkipFunctionBodies | CXTranslationUnit_KeepGoing); + index_ = clang_createIndex(1, 0); + + getDefaultArgs(); if (!pchName_.isEmpty() && !filePath.endsWith(".mm")) { - args.push_back("-w"); - args.push_back("-include-pch"); - args.push_back(pchName_.constData()); + args_.push_back("-w"); + args_.push_back("-include-pch"); + args_.push_back(pchName_.constData()); } - for (const auto &p : qAsConst(moreArgs)) - args.push_back(p.constData()); + for (const auto &p : qAsConst(moreArgs_)) + args_.push_back(p.constData()); CXTranslationUnit tu; - CXErrorCode err = clang_parseTranslationUnit2(index, filePath.toLocal8Bit(), args.data(), - args.size(), nullptr, 0, flags, &tu); + CXErrorCode err = clang_parseTranslationUnit2(index_, filePath.toLocal8Bit(), args_.data(), + args_.size(), nullptr, 0, flags_, &tu); if (err || !tu) { qWarning() << "Could not parse " << filePath << " error code:" << err; - clang_disposeIndex(index); + clang_disposeIndex(index_); return; } @@ -1184,7 +1220,7 @@ void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QStrin clang_disposeTokens(tu, tokens, numTokens); clang_disposeTranslationUnit(tu); - clang_disposeIndex(index); + clang_disposeIndex(index_); } QT_END_NAMESPACE |