summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTopi Reinio <topi.reinio@qt.io>2020-02-16 16:33:22 +0100
committerTopi Reinio <topi.reinio@qt.io>2020-02-18 18:20:43 +0100
commitea29dae17dd4238c259a05667ebd8ce7ca54b4fd (patch)
treeb76e7a652955081f92079e776370adc2cb4cfd7f
parent9202d454511fa917d7ede2e969c738c20e835675 (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.cpp30
-rw-r--r--src/qdoc/clangcodeparser.h1
-rw-r--r--tests/auto/qdoc/generatedoutput/testcpp.cpp3
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.