summaryrefslogtreecommitdiff
path: root/src/qdoc/cppcodeparser.cpp
diff options
context:
space:
mode:
authorLuca Di Sera <luca.disera@qt.io>2023-03-17 17:28:09 +0100
committerLuca Di Sera <luca.disera@qt.io>2023-03-22 15:02:01 +0000
commit32fe97d2b6639b7f4ec741bb5f1854efda062054 (patch)
tree5c36bc5805dd18bd221884552754828182b7b5c9 /src/qdoc/cppcodeparser.cpp
parentb744b634f792577e1ec467801c500b84bebc995d (diff)
downloadqttools-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.cpp45
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 &macroArg)
{
+ 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)) {