diff options
author | Topi Reinio <topi.reinio@qt.io> | 2020-02-16 16:33:22 +0100 |
---|---|---|
committer | Topi Reinio <topi.reinio@qt.io> | 2020-02-18 18:20:43 +0100 |
commit | ea29dae17dd4238c259a05667ebd8ce7ca54b4fd (patch) | |
tree | b76e7a652955081f92079e776370adc2cb4cfd7f | |
parent | 9202d454511fa917d7ede2e969c738c20e835675 (diff) |
qdoc: Store and use the current namespace scope for \fn comments
Writing \fn commands for member functions of classes declared under
a namespace was error-prone as QDoc required the fully qualified
paths for the function signature, even though the documentation
comment was located under the correct namespace scope.
Store the scope by backtracking the Clang AST until we reach the
level of the translation unit, and store each encountered namespace
declaration into a list. When generating the temporary source file
for an \fn command, we can then recreate the correct namespace
hierarchy.
This does not break the existing \fn command usage as it's perfectly
valid, even if unnecessary, to provide fully qualified paths in the
function signature.
[ChangeLog][qdoc] QDoc is now aware of the namespace scope of an \fn
command without requiring fully qualified paths.
Fixes: QTBUG-82190
Change-Id: Ia446c19d130b2ef48b16b67e4dfcbdaab1f9d4f5
Reviewed-by: Paul Wicking <paul.wicking@qt.io>
-rw-r--r-- | src/qdoc/clangcodeparser.cpp | 30 | ||||
-rw-r--r-- | src/qdoc/clangcodeparser.h | 1 | ||||
-rw-r--r-- | tests/auto/qdoc/generatedoutput/testcpp.cpp | 3 |
3 files changed, 27 insertions, 7 deletions
diff --git a/src/qdoc/clangcodeparser.cpp b/src/qdoc/clangcodeparser.cpp index 89ef4f067..2f167eaad 100644 --- a/src/qdoc/clangcodeparser.cpp +++ b/src/qdoc/clangcodeparser.cpp @@ -593,6 +593,8 @@ CXChildVisitResult ClangVisitor::visitFnSignature(CXCursor cursor, CXSourceLocat bool &ignoreSignature) { switch (clang_getCursorKind(cursor)) { + case CXCursor_Namespace: + return CXChildVisit_Recurse; case CXCursor_FunctionDecl: case CXCursor_FunctionTemplate: case CXCursor_CXXMethod: @@ -1503,14 +1505,14 @@ void ClangCodeParser::parseSourceFile(const Location & /*location*/, const QStri return; } - CXCursor cur = clang_getTranslationUnitCursor(tu); + CXCursor tuCur = clang_getTranslationUnitCursor(tu); ClangVisitor visitor(qdb_, allHeaders_); - visitor.visitChildren(cur); + visitor.visitChildren(tuCur); CXToken *tokens; unsigned int numTokens = 0; const QSet<QString> &commands = topicCommands() + metaCommands(); - clang_tokenize(tu, clang_getCursorExtent(cur), &tokens, &numTokens); + clang_tokenize(tu, clang_getCursorExtent(tuCur), &tokens, &numTokens); for (unsigned int i = 0; i < numTokens; ++i) { if (clang_getTokenKind(tokens[i]) != CXToken_Comment) @@ -1519,7 +1521,8 @@ void ClangCodeParser::parseSourceFile(const Location & /*location*/, const QStri if (!comment.startsWith("/*!")) continue; - auto loc = fromCXSourceLocation(clang_getTokenLocation(tu, tokens[i])); + auto commentLoc = clang_getTokenLocation(tu, tokens[i]); + auto loc = fromCXSourceLocation(commentLoc); auto end_loc = fromCXSourceLocation(clang_getRangeEnd(clang_getTokenExtent(tu, tokens[i]))); Doc::trimCStyleComment(loc, comment); @@ -1536,7 +1539,6 @@ void ClangCodeParser::parseSourceFile(const Location & /*location*/, const QStri topic = topics[0].topic; if (topic.isEmpty()) { - CXSourceLocation commentLoc = clang_getTokenLocation(tu, tokens[i]); Node *n = nullptr; if (i + 1 < numTokens) { // Try to find the next declaration. @@ -1568,6 +1570,17 @@ void ClangCodeParser::parseSourceFile(const Location & /*location*/, const QStri } } } else { + // Store the namespace scope from lexical parents of the comment + namespaceScope_.clear(); + CXCursor cur = clang_getCursor(tu, commentLoc); + while (true) { + CXCursorKind kind = clang_getCursorKind(cur); + if (clang_isTranslationUnit(kind) || clang_isInvalid(kind)) + break; + if (kind == CXCursor_Namespace) + namespaceScope_ << fromCXString(clang_getCursorSpelling(cur)); + cur = clang_getCursorLexicalParent(cur); + } processTopicArgs(doc, topic, nodes, docs); } processMetaCommands(nodes, docs); @@ -1654,9 +1667,14 @@ Node *ClangCodeParser::parseFnArg(const Location &location, const QString &fnArg args.push_back(pchName_.constData()); } CXTranslationUnit tu; - QByteArray fn = fnArg.toUtf8(); + QByteArray fn; + for (const auto &ns : qAsConst(namespaceScope_)) + fn.prepend("namespace " + ns.toUtf8() + " {"); + fn += fnArg.toUtf8(); if (!fn.endsWith(";")) fn += "{ }"; + fn.append(namespaceScope_.size(), '}'); + const char *dummyFileName = "/fn_dummyfile.cpp"; CXUnsavedFile unsavedFile { dummyFileName, fn.constData(), static_cast<unsigned long>(fn.size()) }; diff --git a/src/qdoc/clangcodeparser.h b/src/qdoc/clangcodeparser.h index 078d307c2..9af292e67 100644 --- a/src/qdoc/clangcodeparser.h +++ b/src/qdoc/clangcodeparser.h @@ -78,6 +78,7 @@ private: QVector<QByteArray> defines_; std::vector<const char *> args_; QVector<QByteArray> moreArgs_; + QStringList namespaceScope_; }; QT_END_NAMESPACE diff --git a/tests/auto/qdoc/generatedoutput/testcpp.cpp b/tests/auto/qdoc/generatedoutput/testcpp.cpp index b703a844b..5d3055ac2 100644 --- a/tests/auto/qdoc/generatedoutput/testcpp.cpp +++ b/tests/auto/qdoc/generatedoutput/testcpp.cpp @@ -156,7 +156,8 @@ void TestDerived::virtualFun() /*! \fn TestQDoc::Test::overload() - \fn TestQDoc::Test::overload(bool b) + \fn Test::overload(bool b) + //! The second overload should match even without the fully qualified path Overloads that share a documentation comment, optionally taking a parameter \a b. |