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