diff options
author | Luca Di Sera <luca.disera@qt.io> | 2023-03-17 17:28:09 +0100 |
---|---|---|
committer | Luca Di Sera <luca.disera@qt.io> | 2023-03-22 15:02:01 +0000 |
commit | 32fe97d2b6639b7f4ec741bb5f1854efda062054 (patch) | |
tree | 5c36bc5805dd18bd221884552754828182b7b5c9 /src/qdoc/cppcodeparser.cpp | |
parent | b744b634f792577e1ec467801c500b84bebc995d (diff) | |
download | qttools-32fe97d2b6639b7f4ec741bb5f1854efda062054.tar.gz |
QDoc: Remove `CppCodeParser` from the `CodeParser` hierarchy
QDoc extracts the user-provided documentation from which its output is
generated from a variety of input source file based on a project
configuration.
Those input source file can be of a variety of formats, as long as QDoc
currently supports them.
When parsing those files, QDoc extracts format specific information,
such as information about the available elements in a C++ translation
unit, and all the QDoc language comment-block that form the actual
documentation.
The format specific elements that are extracted are lowered into an
internal representation, the `Node` hierarchy, that QDoc later uses to
perform sanity checks on the user-provided documentation or to
automatically generate certain documentation.
The QDoc comment-blocks are generally processed in place, and they, too,
are converted into an internal representation, partly filling a `Node`
data partly filling a `Doc` instance, and used during later stages to
generate the final output.
It performs this process through the `CodeParser` hierarchy.
The base `CodeParser` class provides an interface to parse certain
source file based on their extension.
Child classes of `CodeParser` implements the actual parsing based on the
format that they support.
`CppCodeParser`, a direct child of `CodeParser`, implements the semantic
for topic and meta commands in a comment block.
That is, it gives meaning to commands such as `\fn` and `\example`.
`ClangCodeParser`, a direct child of `CppCodeParser` and indirect child
of `CodeParser`, implements the logic to extract information from C++
source code.
`PureDocParser`, a direct child of `CppCodeParser` and an indirect child
of `CodeParser`, implements the logic to extract QDoc comment-blocks
from a ".qdoc" file.
Finally, `QmlCodeParser`, a direct child of `CodeParser`, implements the
logic to extract information from QML source files.
Both `ClangCodeParser` and `PureDocParser`, but not `QmlCodeParser`,
depends on `CppCodeParser`.
That is, as they process the found QDoc comment-block in-place during
their parsing, they use `CppCodeParser` to perform this processing.
Indeed, `CppCodeParser` is never itself instanciated, and is only
intended to provide the shared logic for `ClangCodeParser` and
`PureDocParser`.
At the same, since `CppCodeParser` purpose is not to actually parse any
source file, it doesn't respect, meaningfully, the interface for
`CodeParser`, mostly providing stub implementation for its pure virtual
methods to satisfy the compiler.
Due to recent, purposefully made, changes, `CppCodeParser` does not
depend, mostly, on any internal-only state of `CodeParser`, while
`ClangCodeParser` and `PureDocParser` do not depend on any internal-only
state of `CppCodeParser`, instead depending only on access to some of
its methods.
Hence, `CppCodeParser`, which does not respect the `CodeParser`
interface meaningfully, can be removed from the hierarchy, simplifying
it and reducing the implicit state and interface of the other members,
additionally moving the codebase forward in the intention of removing
the `CodeParser` interface and some of the shared-mutable state that
QDoc depends on.
Thus, `CppCodeParser` does not inherit anymore from `CodeParser`.
As a consequence, `ClangCodeParser` and `PureDocParser` now inherit
directly from `CodeParser`, flattening the hierarchy depth to one.
Certain pure virtual methods that were provided directly or indirectly
by `CppCodeParser` are now implemented directly in `ClangCodeParser` and
`PureDocParser` to satisfy the `CodeParser` interface.
In particular, `ClangCodeParser` now implements an empty
`terminateParser`, as before the `terminateParser` implementation only
referred back to `CppCodeParser::terminateParser`.
Similarly, `ClangCodeParser::initializeParser` does not refer back to
`CppCodeParser::initializeParser` anymore.
`PureDocParser` now implements empty `initializeParser` and `language`
methods, as, while required by the `CodeParser` inheritance, are
completely meaningless in the scope of the class.
The methods that `CppCodeParser` inherited from `CodeParser` are thus
removed.
That is, `CppCodeParser::initializeParser`,
`CppCodeParser::terminateParser`, `CppCodeParser::language` and
`CppCodeParser::sourceFileNameFilter` are directly deleted.
`CodeParser` objects are built once and registered into a static list
owned by `CodeParser`.
Their lifetime is then managed by the `initialize`/`terminate` methods
of `CodeParser`, manually.
As `CppCodeParser` does not respect this manual management anymore, the
processing performed in `initializeParser` was moved to its constructor
and the processing performed in `terminateParser` was moved to its
destructor.
In doing so a declaration for the destructor was added to
"cppcodeparser.h" and an implementation of it was added to
"cppcodeparser.cpp", replacing the `terminateParser` implementation.
Similarly, the defaulted constructor for `CppCodeParser` was removed in
favor of a custom one and its implementation replaces the implementation
for `initializeParser`.
The implementation for `CppCodeParser` made use of the `m_qdb`, a
pointer to the `QDocDatabase` singleton, which keeps a certain amount of
state that is necessary during parsing, instance-member provided by the
`CodeParser` class.
Due to the changes in the inheritance hierarchy, those usages were
modified to obtain an instance of the database directly in their scope.
In particular, `CppCodeParser::parseOtherFuncArg`,
`CppCodeParser::parseMacroArg`, `CppCodeParser::processTopicArgs`,
`CppCodeParser::processQmlProperties`,
`CppCodeParser::processMetaCommand` and
`CppCodeParser::processTopicCommand` were modified as such.
`CppCodeParser` made use of certain static methods of `CodeParser`.
Usages of those methods were modified to directly refer to the
`CodeParser` namespace as they are not implicitly available in the
relevant scopes anymore.
In particular, `CppCodeParser::processTopicArgs`, which referenced
`CodeParser::parserForLanguage` and
`processTopicCommands`/`processMetaCommand`, which referenced
`CodeParser::isWorthWarningAbout`, were modified as such.
Both `ClangCodeParser` and `PureDocParser` made use of `CppCodeParser`
methods in the call chain for the virtual `parseSourceFile` method, the
entry point to the parsing of a source file.
All the usages are required to process the extracted QDoc comment-blocks
in-place.
Due to the hierarchy changes, both objects do not have access to the
required methods anymore.
As this dependency cannot be directly removed at this point,
`CodeParser::parseSourceFile` interface was modified to require a
`CppCodeParser` instance, to allow for the required in-place processing.
Thus, `ClangCodeParser::parseSourceFile`,
`PureDocParser::parseSourceFile` and `QmlCodeParser::parseSourceFile`
had their signature update to respect the new interface.
`QmlCodeParser` does not make use of `CppCodeParser` provided methods
and thus had no implementation change for `parseSourceFile`.
`ClangCodeParser` makes direct usages of certain `CppCodeParser` methods
in `parseSourceFile` and was thus modified to access them through the
passed in `CppCodeParser` instance.
`PureDocParser` makes use of `CppCodeParser` methods in
`processQDocComments`, the actual processing logic for the parser, as
called by `parseSourceFile`.
Hence, `PureDocParser::processQDocComments` was modified to receive an
instance of `CppCodeParser`.
The instance is passed directly by `parseSourceFile` and each call to
`CppCodeParser` method was modified to use the passed in instance.
Certain methods for `CppCodeParser` that are accessed by either
`ClangCodeParser` or `PureDocParser` were protected.
To allow the access to continue now that the classes aren't related
those methods are now public under `CppCodeParser`'s interface.
In particular, `CppCodeParser::hasTooManyTopics`,
`CppCodeParser::processTopicArgs`, `CppCodeParser::processMetaCommand`
and the two overloads of `CppCodeParser::processMetaCommands` were
modified as such.
Due to `parseSourceFile` now requiring a `CppCodeParser` instance, its
only usage, in `processQDconFile`, was modified to obtain such an
instance.
The instance is built in-place, once per call, in the smallest scope
that respects those requirements near the call to `parseSourceFile`.
Precedently, the manual lifetime management derived by `CodeParser`
would scope a `CppCodeParser` implicit instance, as provided by
`ClangCodeParser` and `PureDocParser`, as the whole of
`processQDocConf`.
As the only usages of `CppCodeParser` is through direct calls to
`parseSourceFile`, the new scope, while smaller, still ensures that the
object is long-lived enough for its usages.
All state that `CppCodeParser` depends upon, as the `CodeParsers` is
either instance based or `processQDocConf` scoped and thus no semantic
changes should derive from the instancing scope.
The change, while invasive, is not expected to change any of the output
documentation for QDoc, preserving the same semantic as before.
Change-Id: Iae448be6c6975649044aa08ed334c73faa38bddf
Reviewed-by: Paul Wicking <paul.wicking@qt.io>
Diffstat (limited to 'src/qdoc/cppcodeparser.cpp')
-rw-r--r-- | src/qdoc/cppcodeparser.cpp | 45 |
1 files changed, 22 insertions, 23 deletions
diff --git a/src/qdoc/cppcodeparser.cpp b/src/qdoc/cppcodeparser.cpp index b15c870de..469410ae6 100644 --- a/src/qdoc/cppcodeparser.cpp +++ b/src/qdoc/cppcodeparser.cpp @@ -54,12 +54,7 @@ static const QMap<QString, NodeTypeTestFunc> s_nodeTypeTestFuncMap{ { COMMAND_VARIABLE, &Node::isVariable }, }; -/*! - The constructor initializes a map of special node types - for identifying important nodes. And it initializes - some filters for identifying and excluding certain kinds of files. - */ -void CppCodeParser::initializeParser() +CppCodeParser::CppCodeParser() { Config &config = Config::instance(); QStringList exampleFilePatterns{config.get(CONFIG_EXAMPLES @@ -92,27 +87,20 @@ void CppCodeParser::initializeParser() /*! Clear the exclude directories and exclude files sets. */ -void CppCodeParser::terminateParser() +CppCodeParser::~CppCodeParser() { m_excludeDirs.clear(); m_excludeFiles.clear(); } /*! - Returns a list of extensions for source files, i.e. not - header files. - */ -QStringList CppCodeParser::sourceFileNameFilter() -{ - return QStringList(); -} - -/*! Process the topic \a command found in the \a doc with argument \a arg. */ Node *CppCodeParser::processTopicCommand(const Doc &doc, const QString &command, const ArgPair &arg) { + QDocDatabase* m_qdb = QDocDatabase::qdocDB(); + if (command == COMMAND_FN) { Q_UNREACHABLE(); } else if (s_nodeTypeMap.contains(command)) { @@ -151,7 +139,7 @@ Node *CppCodeParser::processTopicCommand(const Doc &doc, const QString &command, } } if (node == nullptr) { - if (isWorthWarningAbout(doc)) { + if (CodeParser::isWorthWarningAbout(doc)) { doc.location().warning( QStringLiteral("Cannot find '%1' specified with '\\%2' in any header file") .arg(arg.first, command)); @@ -299,6 +287,8 @@ void CppCodeParser::processQmlProperties(const Doc &doc, NodeList &nodes, DocLis group = property.left(i); } + QDocDatabase* m_qdb = QDocDatabase::qdocDB(); + NodeList sharedNodes; QmlTypeNode *qmlType = m_qdb->findQmlType(module, qmlTypeName); // Note: Constructing a QmlType node by default, as opposed to QmlValueType. @@ -370,6 +360,8 @@ void CppCodeParser::processQmlProperties(const Doc &doc, NodeList &nodes, DocLis void CppCodeParser::processMetaCommand(const Doc &doc, const QString &command, const ArgPair &argPair, Node *node) { + QDocDatabase* m_qdb = QDocDatabase::qdocDB(); + QString arg = argPair.first; if (command == COMMAND_INHEADERFILE) { // TODO: [incorrect-constructs][header-arg] @@ -410,7 +402,7 @@ void CppCodeParser::processMetaCommand(const Doc &doc, const QString &command, // qualified name of the overridden function. // If the name of the overridden function isn't // set, issue a warning. - if (fn->overridesThis().isEmpty() && isWorthWarningAbout(doc)) { + if (fn->overridesThis().isEmpty() && CodeParser::isWorthWarningAbout(doc)) { doc.location().warning( QStringLiteral("Cannot find base function for '\\%1' in %2()") .arg(COMMAND_REIMP, node->name()), @@ -463,11 +455,11 @@ void CppCodeParser::processMetaCommand(const Doc &doc, const QString &command, } } } else if (command == COMMAND_NEXTPAGE) { - setLink(node, Node::NextLink, arg); + CodeParser::setLink(node, Node::NextLink, arg); } else if (command == COMMAND_PREVIOUSPAGE) { - setLink(node, Node::PreviousLink, arg); + CodeParser::setLink(node, Node::PreviousLink, arg); } else if (command == COMMAND_STARTPAGE) { - setLink(node, Node::StartLink, arg); + CodeParser::setLink(node, Node::StartLink, arg); } else if (command == COMMAND_QMLINHERITS) { if (node->name() == arg) doc.location().warning(QStringLiteral("%1 tries to inherit itself").arg(arg)); @@ -657,6 +649,8 @@ FunctionNode *CppCodeParser::parseOtherFuncArg(const QString &topic, const Locat } funcName = colonSplit.last(); + QDocDatabase* m_qdb = QDocDatabase::qdocDB(); + Aggregate *aggregate = m_qdb->findQmlType(moduleName, elementName); if (aggregate == nullptr) return nullptr; @@ -687,6 +681,8 @@ FunctionNode *CppCodeParser::parseOtherFuncArg(const QString &topic, const Locat */ FunctionNode *CppCodeParser::parseMacroArg(const Location &location, const QString ¯oArg) { + QDocDatabase* m_qdb = QDocDatabase::qdocDB(); + QStringList leftParenSplit = macroArg.split('('); if (leftParenSplit.isEmpty()) return nullptr; @@ -812,6 +808,9 @@ bool CppCodeParser::isQMLPropertyTopic(const QString &t) void CppCodeParser::processTopicArgs(const Doc &doc, const QString &topic, NodeList &nodes, DocList &docs) { + + QDocDatabase* m_qdb = QDocDatabase::qdocDB(); + if (isQMLPropertyTopic(topic)) { processQmlProperties(doc, nodes, docs); } else { @@ -820,7 +819,7 @@ void CppCodeParser::processTopicArgs(const Doc &doc, const QString &topic, NodeL if (args.size() == 1) { if (topic == COMMAND_FN) { if (Config::instance().showInternal() || !doc.isInternal()) - node = parserForLanguage("Clang")->parseFnArg(doc.location(), args[0].first, args[0].second); + node = CodeParser::parserForLanguage("Clang")->parseFnArg(doc.location(), args[0].first, args[0].second); } else if (topic == COMMAND_MACRO) { node = parseMacroArg(doc.location(), args[0].first); } else if (isQMLMethodTopic(topic)) { @@ -840,7 +839,7 @@ void CppCodeParser::processTopicArgs(const Doc &doc, const QString &topic, NodeL node = nullptr; if (topic == COMMAND_FN) { if (Config::instance().showInternal() || !doc.isInternal()) - node = parserForLanguage("Clang")->parseFnArg(doc.location(), arg.first, arg.second); + node = CodeParser::parserForLanguage("Clang")->parseFnArg(doc.location(), arg.first, arg.second); } else if (topic == COMMAND_MACRO) { node = parseMacroArg(doc.location(), arg.first); } else if (isQMLMethodTopic(topic)) { |