Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cppcodeparser.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
5
6#include "access.h"
7#include "classnode.h"
11#include "config.h"
12#include "examplenode.h"
14#include "functionnode.h"
15#include "generator.h"
16#include "headernode.h"
17#include "namespacenode.h"
18#include "qdocdatabase.h"
19#include "qmltypenode.h"
22
23#include <QtCore/qdebug.h>
24#include <QtCore/qmap.h>
25
26#include <algorithm>
27
28using namespace Qt::Literals::StringLiterals;
29
30QT_BEGIN_NAMESPACE
31
32/*
33 All these can appear in a C++ namespace. Don't add
34 anything that can't be in a C++ namespace.
35 */
36static const QMap<QString, Node::NodeType> s_nodeTypeMap{
37 { COMMAND_NAMESPACE, Node::Namespace }, { COMMAND_NAMESPACE, Node::Namespace },
38 { COMMAND_CLASS, Node::Class }, { COMMAND_STRUCT, Node::Struct },
39 { COMMAND_UNION, Node::Union }, { COMMAND_ENUM, Node::Enum },
40 { COMMAND_TYPEALIAS, Node::TypeAlias }, { COMMAND_TYPEDEF, Node::Typedef },
41 { COMMAND_PROPERTY, Node::Property }, { COMMAND_VARIABLE, Node::Variable }
42};
43
44typedef bool (Node::*NodeTypeTestFunc)() const;
46 { COMMAND_NAMESPACE, &Node::isNamespace }, { COMMAND_CLASS, &Node::isClassNode },
47 { COMMAND_STRUCT, &Node::isStruct }, { COMMAND_UNION, &Node::isUnion },
48 { COMMAND_ENUM, &Node::isEnumType }, { COMMAND_TYPEALIAS, &Node::isTypeAlias },
49 { COMMAND_TYPEDEF, &Node::isTypedef }, { COMMAND_PROPERTY, &Node::isProperty },
50 { COMMAND_VARIABLE, &Node::isVariable },
51};
52
55{
56 Config &config = Config::instance();
57 QStringList exampleFilePatterns{config.get(CONFIG_EXAMPLES
58 + Config::dot
59 + CONFIG_FILEEXTENSIONS).asStringList()};
60
61 if (!exampleFilePatterns.isEmpty())
62 m_exampleNameFilter = exampleFilePatterns.join(' ');
63 else
64 m_exampleNameFilter = "*.cpp *.h *.js *.xq *.svg *.xml *.ui";
65
66 QStringList exampleImagePatterns{config.get(CONFIG_EXAMPLES
67 + Config::dot
68 + CONFIG_IMAGEEXTENSIONS).asStringList()};
69
70 if (!exampleImagePatterns.isEmpty())
71 m_exampleImageFilter = exampleImagePatterns.join(' ');
72 else
73 m_exampleImageFilter = "*.png";
74
75 m_showLinkErrors = !config.get(CONFIG_NOLINKERRORS).asBool();
76}
77
78/*!
79 Process the topic \a command found in the \a doc with argument \a arg.
80 */
81Node *CppCodeParser::processTopicCommand(const Doc &doc, const QString &command,
82 const ArgPair &arg)
83{
85
86 if (command == COMMAND_FN) {
87 Q_UNREACHABLE();
88 } else if (s_nodeTypeMap.contains(command)) {
89 /*
90 We should only get in here if the command refers to
91 something that can appear in a C++ namespace,
92 i.e. a class, another namespace, an enum, a typedef,
93 a property or a variable. I think these are handled
94 this way to allow the writer to refer to the entity
95 without including the namespace qualifier.
96 */
97 Node::NodeType type = s_nodeTypeMap[command];
98 QStringList words = arg.first.split(QLatin1Char(' '));
99 QStringList path;
100 qsizetype idx = 0;
101 Node *node = nullptr;
102
103 if (type == Node::Variable && words.size() > 1)
104 idx = words.size() - 1;
105 path = words[idx].split("::");
106
107 node = database->findNodeByNameAndType(path, s_nodeTypeTestFuncMap[command]);
108 // Allow representing a type alias as a class
109 if (node == nullptr && command == COMMAND_CLASS) {
110 node = database->findNodeByNameAndType(path, &Node::isTypeAlias);
111 if (node) {
112 auto access = node->access();
113 auto loc = node->location();
114 auto templateDecl = node->templateDecl();
115 node = new ClassNode(Node::Class, node->parent(), node->name());
116 node->setAccess(access);
117 node->setLocation(loc);
118 node->setTemplateDecl(templateDecl);
119 }
120 }
121 if (node == nullptr) {
123 doc.location().warning(
124 QStringLiteral("Cannot find '%1' specified with '\\%2' in any header file")
125 .arg(arg.first, command));
126 }
127 } else if (node->isAggregate()) {
128 if (type == Node::Namespace) {
129 auto *ns = static_cast<NamespaceNode *>(node);
130 ns->markSeen();
131 ns->setWhereDocumented(ns->tree()->camelCaseModuleName());
132 }
133 }
134 return node;
135 } else if (command == COMMAND_EXAMPLE) {
137 auto *en = new ExampleNode(database->primaryTreeRoot(), arg.first);
138 en->setLocation(doc.startLocation());
139 setExampleFileLists(en);
140 return en;
141 }
142 } else if (command == COMMAND_EXTERNALPAGE) {
143 auto *epn = new ExternalPageNode(database->primaryTreeRoot(), arg.first);
144 epn->setLocation(doc.startLocation());
145 return epn;
146 } else if (command == COMMAND_HEADERFILE) {
147 auto *hn = new HeaderNode(database->primaryTreeRoot(), arg.first);
148 hn->setLocation(doc.startLocation());
149 return hn;
150 } else if (command == COMMAND_GROUP) {
151 CollectionNode *cn = database->addGroup(arg.first);
153 cn->markSeen();
154 return cn;
155 } else if (command == COMMAND_MODULE) {
156 CollectionNode *cn = database->addModule(arg.first);
158 cn->markSeen();
159 return cn;
160 } else if (command == COMMAND_QMLMODULE) {
161 QStringList blankSplit = arg.first.split(QLatin1Char(' '));
162 CollectionNode *cn = database->addQmlModule(blankSplit[0]);
163 cn->setLogicalModuleInfo(blankSplit);
165 cn->markSeen();
166 return cn;
167 } else if (command == COMMAND_PAGE) {
168 auto *pn = new PageNode(database->primaryTreeRoot(), arg.first.split(' ').front());
169 pn->setLocation(doc.startLocation());
170 return pn;
171 } else if (command == COMMAND_QMLTYPE ||
172 command == COMMAND_QMLVALUETYPE ||
173 command == COMMAND_QMLBASICTYPE) {
174 auto nodeType = (command == COMMAND_QMLTYPE) ? Node::QmlType : Node::QmlValueType;
175 QString qmid;
176 if (auto args = doc.metaCommandArgs(COMMAND_INQMLMODULE); !args.isEmpty())
177 qmid = args.first().first;
178 auto *qcn = database->findQmlTypeInPrimaryTree(qmid, arg.first);
179 // A \qmlproperty may have already constructed a placeholder type
180 // without providing a module identifier; allow such cases
181 if (!qcn && !qmid.isEmpty())
182 qcn = database->findQmlTypeInPrimaryTree(QString(), arg.first);
183 if (!qcn || qcn->nodeType() != nodeType)
184 qcn = new QmlTypeNode(database->primaryTreeRoot(), arg.first, nodeType);
185 if (!qmid.isEmpty())
186 database->addToQmlModule(qmid, qcn);
187 qcn->setLocation(doc.startLocation());
188 return qcn;
189 } else if ((command == COMMAND_QMLSIGNAL) || (command == COMMAND_QMLMETHOD)
190 || (command == COMMAND_QMLATTACHEDSIGNAL) || (command == COMMAND_QMLATTACHEDMETHOD)) {
191 Q_UNREACHABLE();
192 }
193 return nullptr;
194}
195
196/*!
197 A QML property argument has the form...
198
199 <type> <QML-type>::<name>
200 <type> <QML-module>::<QML-type>::<name>
201
202 This function splits the argument into one of those
203 two forms. The three part form is the old form, which
204 was used before the creation of Qt Quick 2 and Qt
205 Components. A <QML-module> is the QML equivalent of a
206 C++ namespace. So this function splits \a arg on "::"
207 and stores the parts in \a type, \a module, \a qmlTypeName,
208 and \a name, and returns \c true. If any part other than
209 \a module is not found, a qdoc warning is emitted and
210 false is returned.
211
212 \note The two QML types \e{Component} and \e{QtObject}
213 never have a module qualifier.
214 */
215bool CppCodeParser::splitQmlPropertyArg(const QString &arg, QString &type, QString &module,
216 QString &qmlTypeName, QString &name,
217 const Location &location)
218{
219 QStringList blankSplit = arg.split(QLatin1Char(' '));
220 if (blankSplit.size() > 1) {
221 type = blankSplit[0];
222 QStringList colonSplit(blankSplit[1].split("::"));
223 if (colonSplit.size() == 3) {
224 module = colonSplit[0];
225 qmlTypeName = colonSplit[1];
226 name = colonSplit[2];
227 return true;
228 }
229 if (colonSplit.size() == 2) {
230 module.clear();
231 qmlTypeName = colonSplit[0];
232 name = colonSplit[1];
233 return true;
234 }
235 location.warning(
236 QStringLiteral("Unrecognizable QML module/component qualifier for %1").arg(arg));
237 } else {
238 location.warning(QStringLiteral("Missing property type for %1").arg(arg));
239 }
240 return false;
241}
242
244{
245 const Doc &doc = untied.documentation;
246 const TopicList &topics = doc.topicsUsed();
247 if (topics.isEmpty())
248 return {};
249
250 QString arg;
251 QString type;
252 QString group;
253 QString qmlModule;
254 QString property;
255 QString qmlTypeName;
256
257 std::vector<TiedDocumentation> tied{};
258
259 Topic topic = topics.at(0);
260 arg = topic.m_args;
261 if (splitQmlPropertyArg(arg, type, qmlModule, qmlTypeName, property, doc.location())) {
262 qsizetype i = property.indexOf('.');
263 if (i != -1)
264 group = property.left(i);
265 }
266
268
269 NodeList sharedNodes;
270 QmlTypeNode *qmlType = database->findQmlTypeInPrimaryTree(qmlModule, qmlTypeName);
271 // Note: Constructing a QmlType node by default, as opposed to QmlValueType.
272 // This may lead to unexpected behavior if documenting \qmlvaluetype's properties
273 // before the type itself.
274 if (qmlType == nullptr) {
275 qmlType = new QmlTypeNode(database->primaryTreeRoot(), qmlTypeName, Node::QmlType);
277 if (!qmlModule.isEmpty())
278 database->addToQmlModule(qmlModule, qmlType);
279 }
280
281 for (const auto &topicCommand : topics) {
282 QString cmd = topicCommand.m_topic;
283 arg = topicCommand.m_args;
284 if ((cmd == COMMAND_QMLPROPERTY) || (cmd == COMMAND_QMLATTACHEDPROPERTY)) {
285 bool attached = cmd.contains(QLatin1String("attached"));
286 if (splitQmlPropertyArg(arg, type, qmlModule, qmlTypeName, property, doc.location())) {
287 if (qmlType != database->findQmlTypeInPrimaryTree(qmlModule, qmlTypeName)) {
288 doc.startLocation().warning(
289 QStringLiteral(
290 "All properties in a group must belong to the same type: '%1'")
291 .arg(arg));
292 continue;
293 }
294 QmlPropertyNode *existingProperty = qmlType->hasQmlProperty(property, attached);
295 if (existingProperty) {
296 processMetaCommands(doc, existingProperty);
297 if (!doc.body().isEmpty()) {
298 doc.startLocation().warning(
299 QStringLiteral("QML property documented multiple times: '%1'")
300 .arg(arg), QStringLiteral("also seen here: %1")
301 .arg(existingProperty->location().toString()));
302 }
303 continue;
304 }
305 auto *qpn = new QmlPropertyNode(qmlType, property, type, attached);
306 qpn->setLocation(doc.startLocation());
307 qpn->setGenus(Node::QML);
308
309 tied.emplace_back(TiedDocumentation{doc, qpn});
310
311 sharedNodes << qpn;
312 }
313 } else {
314 doc.startLocation().warning(
315 QStringLiteral("Command '\\%1'; not allowed with QML property commands")
316 .arg(cmd));
317 }
318 }
319
320 // Construct a SharedCommentNode (scn) if multiple topics generated
321 // valid nodes. Note that it's important to do this *after* constructing
322 // the topic nodes - which need to be written to index before the related
323 // scn.
324 if (sharedNodes.size() > 1) {
325 auto *scn = new SharedCommentNode(qmlType, sharedNodes.size(), group);
326 scn->setLocation(doc.startLocation());
327
328 tied.emplace_back(TiedDocumentation{doc, scn});
329
330 for (const auto n : sharedNodes)
331 scn->append(n);
332 scn->sort();
333 }
334
335 return tied;
336}
337
338/*!
339 Process the metacommand \a command in the context of the
340 \a node associated with the topic command and the \a doc.
341 \a arg is the argument to the metacommand.
342
343 \a node is guaranteed to be non-null.
344 */
345void CppCodeParser::processMetaCommand(const Doc &doc, const QString &command,
346 const ArgPair &argPair, Node *node)
347{
349
350 QString arg = argPair.first;
351 if (command == COMMAND_INHEADERFILE) {
352 // TODO: [incorrect-constructs][header-arg]
353 // The emptiness check for arg is required as,
354 // currently, DocParser fancies passing (without any warning)
355 // incorrect constructs doen the chain, such as an
356 // "\inheaderfile" command with no argument.
357 //
358 // As it is the case here, we require further sanity checks to
359 // preserve some of the semantic for the later phases.
360 // This generally has a ripple effect on the whole codebase,
361 // making it more complex and increasesing the surface of bugs.
362 //
363 // The following emptiness check should be removed as soon as
364 // DocParser is enhanced with correct semantics.
365 if (node->isAggregate() && !arg.isEmpty())
366 static_cast<Aggregate *>(node)->setIncludeFile(arg);
367 else
368 doc.location().warning(QStringLiteral("Ignored '\\%1'").arg(COMMAND_INHEADERFILE));
369 } else if (command == COMMAND_COMPARES) {
370 processComparesCommand(node, arg, doc.location());
371 } else if (command == COMMAND_COMPARESWITH) {
372 if (!node->isClassNode())
373 doc.location().warning(
374 u"Found \\%1 command outside of \\%2 context."_s
376 } else if (command == COMMAND_OVERLOAD) {
377 /*
378 Note that this might set the overload flag of the
379 primary function. This is ok because the overload
380 flags and overload numbers will be resolved later
381 in Aggregate::normalizeOverloads().
382 */
383 if (node->isFunction())
384 static_cast<FunctionNode *>(node)->setOverloadFlag();
385 else if (node->isSharedCommentNode())
386 static_cast<SharedCommentNode *>(node)->setOverloadFlags();
387 else
388 doc.location().warning(QStringLiteral("Ignored '\\%1'").arg(COMMAND_OVERLOAD));
389 } else if (command == COMMAND_REIMP) {
390 if (node->parent() && !node->parent()->isInternal()) {
391 if (node->isFunction()) {
392 auto *fn = static_cast<FunctionNode *>(node);
393 // The clang visitor class will have set the
394 // qualified name of the overridden function.
395 // If the name of the overridden function isn't
396 // set, issue a warning.
398 doc.location().warning(
399 QStringLiteral("Cannot find base function for '\\%1' in %2()")
400 .arg(COMMAND_REIMP, node->name()),
401 QStringLiteral("The function either doesn't exist in any "
402 "base class with the same signature or it "
403 "exists but isn't virtual."));
404 }
406 } else {
407 doc.location().warning(
408 QStringLiteral("Ignored '\\%1' in %2").arg(COMMAND_REIMP, node->name()));
409 }
410 }
411 } else if (command == COMMAND_RELATES) {
412 // REMARK: Generates warnings only; Node instances are
413 // adopted from the root namespace to other Aggregates
414 // in a post-processing step, Aggregate::resolveRelates(),
415 // after all topic commands are processed.
416 if (node->isAggregate()) {
417 doc.location().warning("Invalid '\\%1' not allowed in '\\%2'"_L1
418 .arg(COMMAND_RELATES, node->nodeTypeString()));
419 } else if (!node->isRelatedNonmember() && node->parent()->isClassNode()) {
420 if (!doc.isInternal()) {
421 doc.location().warning("Invalid '\\%1' ('%2' must be global)"_L1
422 .arg(COMMAND_RELATES, node->name()));
423 }
424 }
425 } else if (command == COMMAND_NEXTPAGE) {
426 CodeParser::setLink(node, Node::NextLink, arg);
427 } else if (command == COMMAND_PREVIOUSPAGE) {
428 CodeParser::setLink(node, Node::PreviousLink, arg);
429 } else if (command == COMMAND_STARTPAGE) {
430 CodeParser::setLink(node, Node::StartLink, arg);
431 } else if (command == COMMAND_QMLINHERITS) {
432 if (node->name() == arg)
433 doc.location().warning(QStringLiteral("%1 tries to inherit itself").arg(arg));
434 else if (node->isQmlType()) {
435 auto *qmlType = static_cast<QmlTypeNode *>(node);
436 qmlType->setQmlBaseName(arg);
437 }
438 } else if (command == COMMAND_QMLNATIVETYPE || command == COMMAND_QMLINSTANTIATES) {
439 if (command == COMMAND_QMLINSTANTIATES)
440 doc.location().report(
441 u"\\nativetype is deprecated and will be removed in a future version. Use \\nativetype instead."_s);
442 // TODO: COMMAND_QMLINSTANTIATES is deprecated since 6.8. Its remains should be removed no later than Qt 7.0.0.
443 processQmlNativeTypeCommand(node, command, arg, doc.location());
444 } else if (command == COMMAND_DEFAULT) {
445 if (!node->isQmlProperty()) {
446 doc.location().warning(QStringLiteral("Ignored '\\%1', applies only to '\\%2'")
447 .arg(command, COMMAND_QMLPROPERTY));
448 } else if (arg.isEmpty()) {
449 doc.location().warning(QStringLiteral("Expected an argument for '\\%1' (maybe you meant '\\%2'?)")
450 .arg(command, COMMAND_QMLDEFAULT));
451 } else {
452 static_cast<QmlPropertyNode *>(node)->setDefaultValue(arg);
453 }
454 } else if (command == COMMAND_QMLDEFAULT) {
455 node->markDefault();
456 } else if (command == COMMAND_QMLENUMERATORSFROM) {
457 if (!node->isQmlProperty()) {
458 doc.location().warning("Ignored '\\%1', applies only to '\\%2'"_L1
459 .arg(command, COMMAND_QMLPROPERTY));
460 } else if (!static_cast<QmlPropertyNode*>(node)->setEnumNode(argPair.first, argPair.second)) {
461 doc.location().warning("Failed to find C++ enumeration '%2' passed to \\%1"_L1
462 .arg(command, arg), "Use \\value commands instead"_L1);
463 }
464 } else if (command == COMMAND_QMLREADONLY) {
465 node->markReadOnly(true);
466 } else if (command == COMMAND_QMLREQUIRED) {
467 if (!node->isQmlProperty())
468 doc.location().warning(QStringLiteral("Ignored '\\%1'").arg(COMMAND_QMLREQUIRED));
469 else
470 static_cast<QmlPropertyNode *>(node)->setRequired();
471 } else if ((command == COMMAND_QMLABSTRACT) || (command == COMMAND_ABSTRACT)) {
472 if (node->isQmlType())
473 node->setAbstract(true);
474 } else if (command == COMMAND_DEPRECATED) {
475 node->setDeprecated(argPair.second);
476 } else if (command == COMMAND_INGROUP || command == COMMAND_INPUBLICGROUP) {
477 // Note: \ingroup and \inpublicgroup are the same (and now recognized as such).
478 database->addToGroup(arg, node);
479 } else if (command == COMMAND_INMODULE) {
480 database->addToModule(arg, node);
481 } else if (command == COMMAND_INQMLMODULE) {
482 // Handled when parsing topic commands
483 } else if (command == COMMAND_OBSOLETE) {
485 } else if (command == COMMAND_NONREENTRANT) {
487 } else if (command == COMMAND_PRELIMINARY) {
488 // \internal wins.
489 if (!node->isInternal())
491 } else if (command == COMMAND_INTERNAL) {
492 if (!Config::instance().showInternal())
494 } else if (command == COMMAND_REENTRANT) {
496 } else if (command == COMMAND_SINCE) {
497 node->setSince(arg);
498 } else if (command == COMMAND_WRAPPER) {
499 node->setWrapper();
500 } else if (command == COMMAND_THREADSAFE) {
502 } else if (command == COMMAND_TITLE) {
503 if (!node->setTitle(arg))
504 doc.location().warning(QStringLiteral("Ignored '\\%1'").arg(COMMAND_TITLE));
505 else if (node->isExample())
506 database->addExampleNode(static_cast<ExampleNode *>(node));
507 } else if (command == COMMAND_SUBTITLE) {
508 if (!node->setSubtitle(arg))
509 doc.location().warning(QStringLiteral("Ignored '\\%1'").arg(COMMAND_SUBTITLE));
510 } else if (command == COMMAND_QTVARIABLE) {
511 node->setQtVariable(arg);
512 if (!node->isModule() && !node->isQmlModule())
513 doc.location().warning(
514 QStringLiteral(
515 "Command '\\%1' is only meaningful in '\\module' and '\\qmlmodule'.")
516 .arg(COMMAND_QTVARIABLE));
517 } else if (command == COMMAND_QTCMAKEPACKAGE) {
518 if (node->isModule())
519 node->setCMakeComponent(arg);
520 else
521 doc.location().warning(
522 QStringLiteral("Command '\\%1' is only meaningful in '\\module'.")
524 } else if (command == COMMAND_QTCMAKETARGETITEM) {
525 if (node->isModule())
526 node->setCMakeTargetItem(QLatin1String("Qt6::") + arg);
527 else
528 doc.location().warning(
529 QStringLiteral("Command '\\%1' is only meaningful in '\\module'.")
531 } else if (command == COMMAND_CMAKEPACKAGE) {
532 if (node->isModule())
533 node->setCMakePackage(arg);
534 else
535 doc.location().warning(
536 QStringLiteral("Command '\\%1' is only meaningful in '\\module'.")
538 } else if (command == COMMAND_CMAKECOMPONENT) {
539 if (node->isModule())
540 node->setCMakeComponent(arg);
541 else
542 doc.location().warning(
543 QStringLiteral("Command '\\%1' is only meaningful in '\\module'.")
545 } else if (command == COMMAND_CMAKETARGETITEM) {
546 if (node->isModule())
547 node->setCMakeTargetItem(arg);
548 else
549 doc.location().warning(
550 QStringLiteral("Command '\\%1' is only meaningful in '\\module'.")
552 } else if (command == COMMAND_MODULESTATE ) {
553 if (!node->isModule() && !node->isQmlModule()) {
554 doc.location().warning(
555 QStringLiteral(
556 "Command '\\%1' is only meaningful in '\\module' and '\\qmlmodule'.")
557 .arg(COMMAND_MODULESTATE));
558 } else {
559 static_cast<CollectionNode*>(node)->setState(arg);
560 }
561 } else if (command == COMMAND_NOAUTOLIST) {
562 if (!node->isCollectionNode() && !node->isExample()) {
563 doc.location().warning(
564 QStringLiteral(
565 "Command '\\%1' is only meaningful in '\\module', '\\qmlmodule', `\\group` and `\\example`.")
566 .arg(COMMAND_NOAUTOLIST));
567 } else {
568 static_cast<PageNode*>(node)->setNoAutoList(true);
569 }
570 } else if (command == COMMAND_ATTRIBUTION) {
571 // TODO: This condition is not currently exact enough, as it
572 // will allow any non-aggregate `PageNode` to use the command,
573 // For example, an `ExampleNode`.
574 //
575 // The command is intended only for internal usage by
576 // "qattributionscanner" and should only work on `PageNode`s
577 // that are generated from a "\page" command.
578 //
579 // It is already possible to provide a more restricted check,
580 // albeit in a somewhat dirty way. It is not expected that
581 // this warning will have any particular use.
582 // If it so happens that a case where the too-broad scope of
583 // the warning is a problem or hides a bug, modify the
584 // condition to be restrictive enough.
585 // Otherwise, wait until a more torough look at QDoc's
586 // internal representations an way to enable "Attribution
587 // Pages" is performed before looking at the issue again.
588 if (!node->isTextPageNode()) {
589 doc.location().warning(u"Command '\\%1' is only meaningful in '\\%2'"_s.arg(COMMAND_ATTRIBUTION, COMMAND_PAGE));
590 } else { static_cast<PageNode*>(node)->markAttribution(); }
591 }
592}
593
594/*!
595 \internal
596 Processes the argument \a arg that's passed to the \\compares command,
597 and sets the comparison category of the \a node accordingly.
598
599 If the argument is invalid, issue a warning at the location the command
600 appears through \a loc.
601*/
602void CppCodeParser::processComparesCommand(Node *node, const QString &arg, const Location &loc)
603{
604 if (!node->isClassNode()) {
605 loc.warning(u"Found \\%1 command outside of \\%2 context."_s.arg(COMMAND_COMPARES,
607 return;
608 }
609
610 if (auto category = comparisonCategoryFromString(arg.toStdString());
611 category != ComparisonCategory::None) {
612 node->setComparisonCategory(category);
613 } else {
614 loc.warning(u"Invalid argument to \\%1 command: `%2`"_s.arg(COMMAND_COMPARES, arg),
615 u"Valid arguments are `strong`, `weak`, `partial`, or `equality`."_s);
616 }
617}
618
619/*!
620 The topic command has been processed, and now \a doc and
621 \a node are passed to this function to get the metacommands
622 from \a doc and process them one at a time. \a node is the
623 node where \a doc resides.
624 */
626{
627 std::vector<Node*> nodes_to_process{};
628 if (node->isSharedCommentNode()) {
629 auto scn = static_cast<SharedCommentNode*>(node);
630
631 nodes_to_process.reserve(scn->count() + 1);
632 std::copy(scn->collective().cbegin(), scn->collective().cend(), std::back_inserter(nodes_to_process));
633 }
634
635 // REMARK: Ordering is important here. If node is a
636 // SharedCommentNode it MUST be processed after all its child
637 // nodes.
638 // Failure to do so can incur in incorrect warnings.
639 // For example, if a shared documentation has a "\relates" command.
640 // When the command is processed for the SharedCommentNode it will
641 // apply to all its child nodes.
642 // If a child node is processed after the SharedCommentNode that
643 // contains it, that "\relates" command will be considered applied
644 // already, resulting in a warning.
645 nodes_to_process.push_back(node);
646
647 const QStringList metaCommandsUsed = doc.metaCommandsUsed().values();
648 for (const auto &command : metaCommandsUsed) {
649 const ArgList args = doc.metaCommandArgs(command);
650 for (const auto &arg : args) {
651 std::for_each(nodes_to_process.cbegin(), nodes_to_process.cend(), [this, doc, command, arg](auto node){
652 processMetaCommand(doc, command, arg, node);
653 });
654 }
655 }
656}
657
658/*!
659 Parse QML signal/method topic commands.
660 */
661FunctionNode *CppCodeParser::parseOtherFuncArg(const QString &topic, const Location &location,
662 const QString &funcArg)
663{
664 QString funcName;
665 QString returnType;
666
667 qsizetype leftParen = funcArg.indexOf(QChar('('));
668 if (leftParen > 0)
669 funcName = funcArg.left(leftParen);
670 else
671 funcName = funcArg;
672 qsizetype firstBlank = funcName.indexOf(QChar(' '));
673 if (firstBlank > 0) {
674 returnType = funcName.left(firstBlank);
675 funcName = funcName.right(funcName.size() - firstBlank - 1);
676 }
677
678 QStringList colonSplit(funcName.split("::"));
679 if (colonSplit.size() < 2) {
680 QString msg = "Unrecognizable QML module/component qualifier for " + funcArg;
681 location.warning(msg.toLatin1().data());
682 return nullptr;
683 }
684 QString moduleName;
685 QString elementName;
686 if (colonSplit.size() > 2) {
687 moduleName = colonSplit[0];
688 elementName = colonSplit[1];
689 } else {
690 elementName = colonSplit[0];
691 }
692 funcName = colonSplit.last();
693
695
696 auto *aggregate = database->findQmlTypeInPrimaryTree(moduleName, elementName);
697 // Note: Constructing a QmlType node by default, as opposed to QmlValueType.
698 // This may lead to unexpected behavior if documenting \qmlvaluetype's methods
699 // before the type itself.
700 if (!aggregate) {
701 aggregate = new QmlTypeNode(database->primaryTreeRoot(), elementName, Node::QmlType);
702 aggregate->setLocation(location);
703 if (!moduleName.isEmpty())
704 database->addToQmlModule(moduleName, aggregate);
705 }
706
707 QString params;
708 QStringList leftParenSplit = funcArg.split('(');
709 if (leftParenSplit.size() > 1) {
710 QStringList rightParenSplit = leftParenSplit[1].split(')');
711 if (!rightParenSplit.empty())
712 params = rightParenSplit[0];
713 }
714
715 FunctionNode::Metaness metaness = FunctionNode::getMetanessFromTopic(topic);
716 bool attached = topic.contains(QLatin1String("attached"));
717 auto *fn = new FunctionNode(metaness, aggregate, funcName, attached);
718 fn->setAccess(Access::Public);
719 fn->setLocation(location);
720 fn->setReturnType(returnType);
721 fn->setParameters(params);
722 return fn;
723}
724
725/*!
726 Parse the macro arguments in \a macroArg ad hoc, without using
727 any actual parser. If successful, return a pointer to the new
728 FunctionNode for the macro. Otherwise return null. \a location
729 is used for reporting errors.
730 */
731FunctionNode *CppCodeParser::parseMacroArg(const Location &location, const QString &macroArg)
732{
734
735 QStringList leftParenSplit = macroArg.split('(');
736 if (leftParenSplit.isEmpty())
737 return nullptr;
738 QString macroName;
739 FunctionNode *oldMacroNode = nullptr;
740 QStringList blankSplit = leftParenSplit[0].split(' ');
741 if (!blankSplit.empty()) {
742 macroName = blankSplit.last();
743 oldMacroNode = database->findMacroNode(macroName);
744 }
745 QString returnType;
746 if (blankSplit.size() > 1) {
747 blankSplit.removeLast();
748 returnType = blankSplit.join(' ');
749 }
750 QString params;
751 if (leftParenSplit.size() > 1) {
752 const QString &afterParen = leftParenSplit.at(1);
753 qsizetype rightParen = afterParen.indexOf(')');
754 if (rightParen >= 0)
755 params = afterParen.left(rightParen);
756 }
757 int i = 0;
758 while (i < macroName.size() && !macroName.at(i).isLetter())
759 i++;
760 if (i > 0) {
761 returnType += QChar(' ') + macroName.left(i);
762 macroName = macroName.mid(i);
763 }
765 if (params.isEmpty())
767 auto *macro = new FunctionNode(metaness, database->primaryTreeRoot(), macroName);
768 macro->setAccess(Access::Public);
769 macro->setLocation(location);
770 macro->setReturnType(returnType);
771 macro->setParameters(params);
772 if (oldMacroNode && macro->parent() == oldMacroNode->parent()
773 && compare(macro, oldMacroNode) == 0) {
774 location.warning(QStringLiteral("\\macro %1 documented more than once")
775 .arg(macroArg), QStringLiteral("also seen here: %1")
776 .arg(oldMacroNode->doc().location().toString()));
777 }
778 return macro;
779}
780
781void CppCodeParser::setExampleFileLists(ExampleNode *en)
782{
783 Config &config = Config::instance();
784 QString fullPath = config.getExampleProjectFile(en->name());
785 if (fullPath.isEmpty()) {
786 QString details = QLatin1String("Example directories: ")
787 + config.getCanonicalPathList(CONFIG_EXAMPLEDIRS).join(QLatin1Char(' '));
788 en->location().warning(
789 QStringLiteral("Cannot find project file for example '%1'").arg(en->name()),
790 details);
791 return;
792 }
793
794 QDir exampleDir(QFileInfo(fullPath).dir());
795
796 const auto& [excludeDirs, excludeFiles] = config.getExcludedPaths();
797
798 QStringList exampleFiles = Config::getFilesHere(exampleDir.path(), m_exampleNameFilter,
799 Location(), excludeDirs, excludeFiles);
800 // Search for all image files under the example project, excluding doc/images directory.
801 QSet<QString> excludeDocDirs(excludeDirs);
802 excludeDocDirs.insert(exampleDir.path() + QLatin1String("/doc/images"));
803 QStringList imageFiles = Config::getFilesHere(exampleDir.path(), m_exampleImageFilter,
804 Location(), excludeDocDirs, excludeFiles);
805 if (!exampleFiles.isEmpty()) {
806 // move main.cpp to the end, if it exists
807 QString mainCpp;
808
809 const auto isGeneratedOrMainCpp = [&mainCpp](const QString &fileName) {
810 if (fileName.endsWith("/main.cpp")) {
811 if (mainCpp.isEmpty())
812 mainCpp = fileName;
813 return true;
814 }
815 return fileName.contains("/qrc_") || fileName.contains("/moc_")
816 || fileName.contains("/ui_");
817 };
818
819 exampleFiles.erase(
820 std::remove_if(exampleFiles.begin(), exampleFiles.end(), isGeneratedOrMainCpp),
821 exampleFiles.end());
822
823 if (!mainCpp.isEmpty())
824 exampleFiles.append(mainCpp);
825
826 // Add any resource and project files
827 exampleFiles += Config::getFilesHere(exampleDir.path(),
828 QLatin1String("*.qrc *.pro *.qmlproject *.pyproject CMakeLists.txt qmldir"),
829 Location(), excludeDirs, excludeFiles);
830 }
831
832 const qsizetype pathLen = exampleDir.path().size() - en->name().size();
833 for (auto &file : exampleFiles)
834 file = file.mid(pathLen);
835 for (auto &file : imageFiles)
836 file = file.mid(pathLen);
837
838 en->setFiles(exampleFiles, fullPath.mid(pathLen));
839 en->setImages(imageFiles);
840}
841
842/*!
843 returns true if \a t is \e {qmlsignal}, \e {qmlmethod},
844 \e {qmlattachedsignal}, or \e {qmlattachedmethod}.
845 */
846bool CppCodeParser::isQMLMethodTopic(const QString &t)
847{
850}
851
852/*!
853 Returns true if \a t is \e {qmlproperty}, \e {qmlpropertygroup},
854 or \e {qmlattachedproperty}.
855 */
856bool CppCodeParser::isQMLPropertyTopic(const QString &t)
857{
859}
860
861std::pair<std::vector<TiedDocumentation>, std::vector<FnMatchError>>
862CppCodeParser::processTopicArgs(const UntiedDocumentation &untied)
863{
864 const Doc &doc = untied.documentation;
865
866 if (doc.topicsUsed().isEmpty())
867 return {};
868
869 QDocDatabase *database = QDocDatabase::qdocDB();
870
871 const QString topic = doc.topicsUsed().first().m_topic;
872
873 std::vector<TiedDocumentation> tied{};
874 std::vector<FnMatchError> errors{};
875
876 if (isQMLPropertyTopic(topic)) {
877 auto tied_qml = processQmlProperties(untied);
878 tied.insert(tied.end(), tied_qml.begin(), tied_qml.end());
879 } else {
880 ArgList args = doc.metaCommandArgs(topic);
881 Node *node = nullptr;
882 if (args.size() == 1) {
883 if (topic == COMMAND_FN) {
884 if (Config::instance().showInternal() || !doc.isInternal()) {
885 auto result = fn_parser(doc.location(), args[0].first, args[0].second, untied.context);
886 if (auto *error = std::get_if<FnMatchError>(&result))
887 errors.emplace_back(*error);
888 else
889 node = std::get<Node*>(result);
890 }
891 } else if (topic == COMMAND_MACRO) {
892 node = parseMacroArg(doc.location(), args[0].first);
893 } else if (isQMLMethodTopic(topic)) {
894 node = parseOtherFuncArg(topic, doc.location(), args[0].first);
895 } else if (topic == COMMAND_DONTDOCUMENT) {
896 database->primaryTree()->addToDontDocumentMap(args[0].first);
897 } else {
898 node = processTopicCommand(doc, topic, args[0]);
899 }
900 if (node != nullptr) {
901 tied.emplace_back(TiedDocumentation{doc, node});
902 }
903 } else if (args.size() > 1) {
904 QList<SharedCommentNode *> sharedCommentNodes;
905 for (const auto &arg : std::as_const(args)) {
906 node = nullptr;
907 if (topic == COMMAND_FN) {
908 if (Config::instance().showInternal() || !doc.isInternal()) {
909 auto result = fn_parser(doc.location(), arg.first, arg.second, untied.context);
910 if (auto *error = std::get_if<FnMatchError>(&result))
911 errors.emplace_back(*error);
912 else
913 node = std::get<Node*>(result);
914 }
915 } else if (topic == COMMAND_MACRO) {
916 node = parseMacroArg(doc.location(), arg.first);
917 } else if (isQMLMethodTopic(topic)) {
918 node = parseOtherFuncArg(topic, doc.location(), arg.first);
919 } else {
920 node = processTopicCommand(doc, topic, arg);
921 }
922 if (node != nullptr) {
923 bool found = false;
924 for (SharedCommentNode *scn : sharedCommentNodes) {
925 if (scn->parent() == node->parent()) {
926 scn->append(node);
927 found = true;
928 break;
929 }
930 }
931 if (!found) {
932 auto *scn = new SharedCommentNode(node);
933 sharedCommentNodes.append(scn);
934 tied.emplace_back(TiedDocumentation{doc, scn});
935 }
936 }
937 }
938 for (auto *scn : sharedCommentNodes)
939 scn->sort();
940 }
941 }
942 return std::make_pair(tied, errors);
943}
944
945/*!
946 For each node that is part of C++ API and produces a documentation
947 page, this function ensures that the node belongs to a module.
948 */
950{
951 if (n->physicalModuleName().isEmpty()) {
952 if (n->isInAPI() && !n->name().isEmpty()) {
953 switch (n->nodeType()) {
954 case Node::Class:
955 case Node::Struct:
956 case Node::Union:
957 case Node::Namespace:
958 case Node::HeaderFile:
959 break;
960 default:
961 return;
962 }
963 n->setPhysicalModuleName(Generator::defaultModuleName());
964 QDocDatabase::qdocDB()->addToModule(Generator::defaultModuleName(), n);
965 n->doc().location().warning(
966 QStringLiteral("Documentation for %1 '%2' has no \\inmodule command; "
967 "using project name by default: %3")
968 .arg(Node::nodeTypeString(n->nodeType()), n->name(),
969 n->physicalModuleName()));
970 }
971 }
972}
973
974void CppCodeParser::processMetaCommands(const std::vector<TiedDocumentation> &tied)
975{
976 for (auto [doc, node] : tied) {
977 processMetaCommands(doc, node);
978 node->setDoc(doc);
979 checkModuleInclusion(node);
980 if (node->isAggregate()) {
981 auto *aggregate = static_cast<Aggregate *>(node);
982
983 if (!aggregate->includeFile()) {
984 Aggregate *parent = aggregate;
985 while (parent->physicalModuleName().isEmpty() && (parent->parent() != nullptr))
986 parent = parent->parent();
987
988 if (parent == aggregate)
989 // TODO: Understand if the name can be empty.
990 // In theory it should not be possible as
991 // there would be no aggregate to refer to
992 // such that this code is never reached.
993 //
994 // If the name can be empty, this would
995 // endanger users of the include file down the
996 // line, forcing them to ensure that, further
997 // to there being an actual include file, that
998 // include file is not an empty string, such
999 // that we would require a different way to
1000 // generate the include file here.
1001 aggregate->setIncludeFile(aggregate->name());
1002 else if (aggregate->includeFile())
1003 aggregate->setIncludeFile(*parent->includeFile());
1004 }
1005 }
1006 }
1007}
1008
1009void CppCodeParser::processQmlNativeTypeCommand(Node *node, const QString &cmd, const QString &arg, const Location &location)
1010{
1011 Q_ASSERT(node);
1012 if (!node->isQmlNode()) {
1013 location.warning(
1014 QStringLiteral("Command '\\%1' is only meaningful in '\\%2'")
1015 .arg(cmd, COMMAND_QMLTYPE));
1016 return;
1017 }
1018
1019 auto qmlNode = static_cast<QmlTypeNode *>(node);
1020
1022 auto classNode = database->findClassNode(arg.split(u"::"_s));
1023
1024 if (!classNode) {
1025 if (m_showLinkErrors) {
1026 location.warning(
1027 QStringLiteral("C++ class %2 not found: \\%1 %2")
1028 .arg(cmd, arg));
1029 }
1030 return;
1031 }
1032
1033 if (qmlNode->classNode()) {
1034 location.warning(
1035 QStringLiteral("QML type %1 documented with %2 as its native type. Replacing %2 with %3")
1036 .arg(qmlNode->name(), qmlNode->classNode()->name(), arg));
1037 }
1038
1039 qmlNode->setClassNode(classNode);
1040 classNode->insertQmlNativeType(qmlNode);
1041}
1042
1043QT_END_NAMESPACE
The ClassNode represents a C++ class.
Definition classnode.h:21
static bool isWorthWarningAbout(const Doc &doc)
Test for whether a doc comment warrants warnings.
A class for holding the members of a collection of doc pages.
bool asBool() const
Returns this config variable as a boolean.
Definition config.cpp:263
The Config class contains the configuration variables for controlling how qdoc produces documentation...
Definition config.h:84
static bool generateExamples
Definition config.h:164
const ExcludedPaths & getExcludedPaths()
Definition config.cpp:1405
std::vector< TiedDocumentation > processQmlProperties(const UntiedDocumentation &untied)
bool splitQmlPropertyArg(const QString &arg, QString &type, QString &module, QString &element, QString &name, const Location &location)
A QML property argument has the form...
FunctionNode * parseOtherFuncArg(const QString &topic, const Location &location, const QString &funcArg)
Parse QML signal/method topic commands.
FunctionNode * parseMacroArg(const Location &location, const QString &macroArg)
Parse the macro arguments in macroArg ad hoc, without using any actual parser.
void processMetaCommand(const Doc &doc, const QString &command, const ArgPair &argLocPair, Node *node)
Process the metacommand command in the context of the node associated with the topic command and the ...
CppCodeParser(FnCommandParser &&parser)
static bool isQMLMethodTopic(const QString &t)
returns true if t is {qmlsignal}, {qmlmethod}, {qmlattachedsignal}, or {qmlattachedmethod}...
void processMetaCommands(const std::vector< TiedDocumentation > &tied)
static bool isQMLPropertyTopic(const QString &t)
Returns true if t is {qmlproperty}, {qmlpropertygroup}, or {qmlattachedproperty}.
virtual Node * processTopicCommand(const Doc &doc, const QString &command, const ArgPair &arg)
Process the topic command found in the doc with argument arg.
void processMetaCommands(const Doc &doc, Node *node)
The topic command has been processed, and now doc and node are passed to this function to get the met...
Definition doc.h:31
const Location & location() const
Returns the starting location of a qdoc comment.
Definition doc.cpp:90
bool isInternal() const
Returns true if the set of metacommands used in the doc comment contains {internal}...
Definition doc.cpp:219
const Location & startLocation() const
Returns the starting location of a qdoc comment.
Definition doc.cpp:99
TopicList topicsUsed() const
Returns a reference to the list of topic commands used in the current qdoc comment.
Definition doc.cpp:238
The ExternalPageNode represents an external documentation page.
This node is used to represent any kind of function being documented.
void setReimpFlag()
Sets the function node's reimp flag to true, which means the {\reimp} command was used in the qdoc co...
void setOverloadFlag()
const QString & overridesThis() const
The Location class provides a way to mark a location in a file.
Definition location.h:15
Location()
Constructs an empty location.
Definition location.cpp:40
This class represents a C++ namespace.
Tree * tree() const override
Returns a pointer to the Tree that contains this NamespaceNode.
void markSeen()
Sets the data member that indicates that the {\namespace} command this NamespaceNode represents has b...
void markInternal()
Sets the node's access to Private and its status to Internal.
Definition node.h:236
const Doc & doc() const
Returns a reference to the node's Doc data member.
Definition node.h:271
bool isQmlNode() const
Returns true if this node's Genus value is QML.
Definition node.h:153
void setAccess(Access t)
Sets the node's access type to t.
Definition node.h:203
NodeType
An unsigned char value that identifies an object as a particular subclass of Node.
Definition node.h:54
@ Variable
Definition node.h:69
@ Struct
Definition node.h:58
@ QmlValueType
Definition node.h:75
@ Union
Definition node.h:59
@ HeaderFile
Definition node.h:60
@ QmlType
Definition node.h:72
@ Namespace
Definition node.h:56
@ Class
Definition node.h:57
bool isFunction(Genus g=DontCare) const
Returns true if this is a FunctionNode and its Genus is set to g.
Definition node.h:135
bool isQmlType() const
Returns true if the node type is QmlType or QmlValueType.
Definition node.h:155
bool isSharedCommentNode() const
Returns true if the node type is SharedComment.
Definition node.h:158
virtual bool isInternal() const
Returns true if the node's status is Internal, or if its parent is a class with Internal status.
Definition node.cpp:849
virtual bool isTextPageNode() const
Returns true if the node is a PageNode but not an Aggregate.
Definition node.h:187
Aggregate * parent() const
Returns the node's parent pointer.
Definition node.h:244
void setLocation(const Location &t)
Sets the node's declaration location, its definition location, or both, depending on the suffix of th...
Definition node.cpp:886
virtual bool isAggregate() const
Returns true if this node is an aggregate, which means it inherits Aggregate and can therefore have c...
Definition node.h:170
NodeType nodeType() const
Returns this node's type.
Definition node.h:121
void setTemplateDecl(std::optional< RelaxedTemplateDeclaration > t)
Definition node.h:211
virtual void markReadOnly(bool)
If this node is a QmlPropertyNode, then the property's read-only flag is set to flag.
Definition node.h:242
void setComparisonCategory(const ComparisonCategory &category)
Definition node.h:216
const Location & location() const
If this node's definition location is empty, this function returns this node's declaration location.
Definition node.h:267
Access access() const
Returns the node's Access setting, which can be Public, Protected, or Private.
Definition node.h:264
virtual void setWrapper()
If this node is a ClassNode or a QmlTypeNode, the node's wrapper flag data member is set to true.
Definition node.h:223
virtual void markDefault()
If this node is a QmlPropertyNode, it is marked as the default property.
Definition node.h:241
bool isInAPI() const
Definition node.h:272
bool isTypeAlias() const
Returns true if the node type is Typedef.
Definition node.h:159
bool isModule() const
Returns true if the node type is Module.
Definition node.h:142
@ ThreadSafe
Definition node.h:101
@ NonReentrant
Definition node.h:99
@ Reentrant
Definition node.h:100
virtual void setAbstract(bool)
If this node is a ClassNode or a QmlTypeNode, the node's abstract flag data member is set to b.
Definition node.h:222
LinkType
An unsigned char value that probably should be moved out of the Node base class.
Definition node.h:112
bool isRelatedNonmember() const
Returns true if this is a related nonmember of something.
Definition node.h:156
virtual bool isClassNode() const
Returns true if this is an instance of ClassNode.
Definition node.h:177
void setStatus(Status t)
Sets the node's status to t.
Definition node.cpp:560
virtual bool isCollectionNode() const
Returns true if this is an instance of CollectionNode.
Definition node.h:178
void setThreadSafeness(ThreadSafeness t)
Sets the node's thread safeness to t.
Definition node.h:207
@ Deprecated
Definition node.h:90
@ Preliminary
Definition node.h:91
bool isQmlModule() const
Returns true if the node type is QmlModule.
Definition node.h:152
bool isExample() const
Returns true if the node type is Example.
Definition node.h:133
bool isQmlProperty() const
Returns true if the node type is QmlProperty.
Definition node.h:154
A PageNode is a Node that generates a documentation page.
Definition pagenode.h:18
void setNoAutoList(bool b)
Sets the no auto-list flag to b.
Definition pagenode.h:42
void markAttribution()
Definition pagenode.h:49
This class provides exclusive access to the qdoc database, which consists of a forrest of trees and a...
void addExampleNode(ExampleNode *n)
static QDocDatabase * qdocDB()
Creates the singleton.
NamespaceNode * primaryTreeRoot()
Returns a pointer to the root node of the primary tree.
ClassNode * classNode() override
If this is a QmlTypeNode, this function returns the pointer to the C++ ClassNode that this QML type r...
Definition qmltypenode.h:26
void setClassNode(ClassNode *cn) override
If this is a QmlTypeNode, this function sets the C++ class node to cn.
Definition qmltypenode.h:27
void setOverloadFlags()
Searches the shared comment node's member nodes for function nodes.
const QString & camelCaseModuleName() const
Definition tree.h:71
#define COMMAND_ENUM
Definition codeparser.h:23
#define COMMAND_HEADERFILE
Definition codeparser.h:28
#define COMMAND_EXTERNALPAGE
Definition codeparser.h:25
#define COMMAND_QMLINHERITS
Definition codeparser.h:56
#define COMMAND_MODULE
Definition codeparser.h:36
#define COMMAND_MODULESTATE
Definition codeparser.h:37
#define COMMAND_INTERNAL
Definition codeparser.h:34
#define COMMAND_NONREENTRANT
Definition codeparser.h:41
#define COMMAND_QMLSIGNAL
Definition codeparser.h:65
#define COMMAND_OBSOLETE
Definition codeparser.h:42
#define COMMAND_INMODULE
Definition codeparser.h:31
#define COMMAND_STRUCT
Definition codeparser.h:74
#define COMMAND_DEPRECATED
Definition codeparser.h:21
#define COMMAND_PRELIMINARY
Definition codeparser.h:45
#define COMMAND_PROPERTY
Definition codeparser.h:47
#define COMMAND_NEXTPAGE
Definition codeparser.h:39
#define COMMAND_RELATES
Definition codeparser.h:72
#define COMMAND_WRAPPER
Definition codeparser.h:84
#define COMMAND_CLASS
Definition codeparser.h:14
#define COMMAND_NAMESPACE
Definition codeparser.h:38
#define COMMAND_CMAKETARGETITEM
Definition codeparser.h:17
#define COMMAND_REENTRANT
Definition codeparser.h:70
#define COMMAND_QMLMODULE
Definition codeparser.h:59
#define COMMAND_QMLPROPERTY
Definition codeparser.h:61
#define COMMAND_TITLE
Definition codeparser.h:78
#define COMMAND_STARTPAGE
Definition codeparser.h:76
#define COMMAND_QMLDEFAULT
Definition codeparser.h:54
#define COMMAND_SINCE
Definition codeparser.h:73
#define COMMAND_QMLABSTRACT
Definition codeparser.h:48
#define COMMAND_QMLNATIVETYPE
Definition codeparser.h:60
#define COMMAND_FN
Definition codeparser.h:26
#define COMMAND_OVERLOAD
Definition codeparser.h:43
#define COMMAND_QTVARIABLE
Definition codeparser.h:69
#define COMMAND_QTCMAKEPACKAGE
Definition codeparser.h:67
#define COMMAND_NOAUTOLIST
Definition codeparser.h:40
#define COMMAND_QMLATTACHEDPROPERTY
Definition codeparser.h:50
#define COMMAND_UNION
Definition codeparser.h:83
#define COMMAND_COMPARESWITH
Definition codeparser.h:19
#define COMMAND_QTCMAKETARGETITEM
Definition codeparser.h:68
#define COMMAND_MACRO
Definition codeparser.h:35
#define COMMAND_GROUP
Definition codeparser.h:27
#define COMMAND_REIMP
Definition codeparser.h:71
#define COMMAND_VARIABLE
Definition codeparser.h:81
#define COMMAND_INHEADERFILE
Definition codeparser.h:30
#define COMMAND_PREVIOUSPAGE
Definition codeparser.h:46
#define COMMAND_QMLBASICTYPE
Definition codeparser.h:88
#define COMMAND_PAGE
Definition codeparser.h:44
#define COMMAND_EXAMPLE
Definition codeparser.h:24
#define COMMAND_COMPARES
Definition codeparser.h:18
#define COMMAND_DEFAULT
Definition codeparser.h:20
#define COMMAND_THREADSAFE
Definition codeparser.h:77
#define COMMAND_TYPEDEF
Definition codeparser.h:80
#define COMMAND_QMLMETHOD
Definition codeparser.h:58
#define COMMAND_DONTDOCUMENT
Definition codeparser.h:22
#define COMMAND_CMAKECOMPONENT
Definition codeparser.h:16
#define COMMAND_QMLREADONLY
Definition codeparser.h:63
#define COMMAND_QMLENUMERATORSFROM
Definition codeparser.h:55
#define COMMAND_INPUBLICGROUP
Definition codeparser.h:32
#define COMMAND_QMLREQUIRED
Definition codeparser.h:64
#define COMMAND_ABSTRACT
Definition codeparser.h:13
#define COMMAND_QMLVALUETYPE
Definition codeparser.h:52
#define COMMAND_ATTRIBUTION
Definition codeparser.h:85
#define COMMAND_INQMLMODULE
Definition codeparser.h:33
#define COMMAND_QMLINSTANTIATES
Definition codeparser.h:57
#define COMMAND_TYPEALIAS
Definition codeparser.h:79
#define COMMAND_CMAKEPACKAGE
Definition codeparser.h:15
#define COMMAND_INGROUP
Definition codeparser.h:29
#define COMMAND_QMLTYPE
Definition codeparser.h:66
#define COMMAND_QMLATTACHEDMETHOD
Definition codeparser.h:49
#define COMMAND_SUBTITLE
Definition codeparser.h:75
#define COMMAND_QMLATTACHEDSIGNAL
Definition codeparser.h:51
#define CONFIG_FILEEXTENSIONS
Definition config.h:394
#define CONFIG_EXAMPLES
Definition config.h:336
#define CONFIG_EXAMPLEDIRS
Definition config.h:335
#define CONFIG_NOLINKERRORS
Definition config.h:367
#define CONFIG_IMAGEEXTENSIONS
Definition config.h:395
static const QMap< QString, NodeTypeTestFunc > s_nodeTypeTestFuncMap
bool(Node::* NodeTypeTestFunc)() const
static void checkModuleInclusion(Node *n)
For each node that is part of C++ API and produces a documentation page, this function ensures that t...
std::pair< QString, QString > ArgPair
Definition doc.h:26
QList< Node * > NodeList
Definition node.h:41
Definition topic.h:9
QList< Topic > TopicList
Definition topic.h:25