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
qdocindexfiles.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 "atom.h"
8#include "classnode.h"
11#include "config.h"
12#include "enumnode.h"
13#include "qmlenumnode.h"
14#include "examplenode.h"
16#include "functionnode.h"
17#include "generator.h"
18#include "genustypes.h"
19#include "headernode.h"
22#include "location.h"
23#include "utilities.h"
24#include "textutils.h"
25#include "propertynode.h"
26#include "qdocdatabase.h"
29#include "typedefnode.h"
30#include "variablenode.h"
31
32#include <QtCore/qxmlstream.h>
33
34#include <algorithm>
35
37
47
48/*!
49 \class QDocIndexFiles
50
51 This class imports QDoc index files and serializes index sections for
52 module indexes and WebXML output.
53 */
54
55/*!
56 \struct QDocIndexFiles::ReadState
57 \internal
58 \brief Holds state for one index file import.
59
60 A new state is created for each file. Deferred base-class resolution,
61 related nodes, and shared documentation remain isolated from other imports.
62*/
63
64/*!
65 \variable QDocIndexFiles::ReadState::project
66 \brief The project name declared by the imported index.
67*/
68
69/*!
70 \variable QDocIndexFiles::ReadState::bases
71 \brief Classes and their base-class names awaiting resolution.
72*/
73
74/*!
75 \variable QDocIndexFiles::ReadState::relatedNodes
76 \brief Related non-member nodes used to resolve references during import.
77*/
78
79/*!
80 \variable QDocIndexFiles::ReadState::sharedDocNodes
81 \brief Shared documentation nodes keyed by property group name.
82*/
83
84/*!
85 \struct QDocIndexFiles::WriteState
86 \internal
87 \brief Holds state for one index file export.
88
89 A standalone index export creates a fresh state. WebXML owns a separate
90 state across the pages it serializes. Neither inherits related-node
91 numbering from an earlier import or output operation.
92*/
93
94/*!
95 \variable QDocIndexFiles::WriteState::root
96 \brief The primary tree root whose traversal completes an index export.
97
98 WebXML leaves this null because it serializes individual pages.
99*/
100
101/*!
102 \variable QDocIndexFiles::WriteState::relatedNodes
103 \brief Related non-member nodes numbered across this serialization operation.
104*/
105
106QDocIndexFiles *QDocIndexFiles::s_qdocIndexFiles = nullptr;
107
108/*!
109 Constructs the singleton QDocIndexFiles.
110 */
111QDocIndexFiles::QDocIndexFiles()
112{
114}
115
116/*!
117 Destroys the singleton QDocIndexFiles.
118 */
119QDocIndexFiles::~QDocIndexFiles()
120{
121 m_qdb = nullptr;
122}
123
124/*!
125 Creates the singleton. Allows only one instance of the class
126 to be created. Returns a pointer to the singleton.
127 */
128QDocIndexFiles *QDocIndexFiles::qdocIndexFiles()
129{
130 if (s_qdocIndexFiles == nullptr)
131 s_qdocIndexFiles = new QDocIndexFiles;
132 return s_qdocIndexFiles;
133}
134
135/*!
136 Destroys the singleton.
137 */
138void QDocIndexFiles::destroyQDocIndexFiles()
139{
140 if (s_qdocIndexFiles != nullptr) {
141 delete s_qdocIndexFiles;
142 s_qdocIndexFiles = nullptr;
143 }
144}
145
146/*!
147 Reads and parses the list of index files in \a indexFiles.
148 */
149void QDocIndexFiles::readIndexes(const QStringList &indexFiles)
150{
151 for (const QString &file : indexFiles) {
152 qCDebug(lcQdoc) << "Loading index file: " << file;
153 readIndexFile(file);
154 }
155}
156
157/*!
158 Reads and parses the index file at \a path, with a fresh import state.
159 */
160void QDocIndexFiles::readIndexFile(const QString &path)
161{
162 ReadState state;
163
164 QFile file(path);
165 if (!file.open(QFile::ReadOnly)) {
166 qWarning() << "Could not read index file" << path;
167 return;
168 }
169
170 QXmlStreamReader reader(&file);
171 reader.setNamespaceProcessing(false);
172
173 if (!reader.readNextStartElement())
174 return;
175
176 if (reader.name() != QLatin1String("INDEX"))
177 return;
178
179 QXmlStreamAttributes attrs = reader.attributes();
180
181 QString indexUrl {attrs.value(QLatin1String("url")).toString()};
182
183 // Decide how we link to nodes loaded from this index file:
184 // If building a set that will be installed AND the URL of
185 // the dependency is identical to ours, assume that also
186 // the dependent html files are available under the same
187 // directory tree. Otherwise, link using the full index URL.
188 if (!Config::installDir.isEmpty() && indexUrl == Config::instance().get(CONFIG_URL).asString()) {
189 // Generate a relative URL between the install dir and the index file
190 // when the --installdir command line option is set.
191 QDir installDir(path.section('/', 0, -3) + '/' + Generator::outputSubdir());
192 indexUrl = installDir.relativeFilePath(path).section('/', 0, -2);
193 }
194 state.project = attrs.value(QLatin1String("project")).toString();
195 QString indexTitle = attrs.value(QLatin1String("indexTitle")).toString();
196
197 NamespaceNode *root = m_qdb->newIndexTree(state.project);
198 if (!root) {
199 qWarning() << "Issue parsing index tree" << path;
200 return;
201 }
202
203 root->tree()->setIndexTitle(indexTitle);
204
205 // Scan all elements in the XML file, constructing a map that contains
206 // base classes for each class found.
207 while (reader.readNextStartElement()) {
208 readIndexSection(reader, root, indexUrl, state);
209 }
210
211 // Now that all the base classes have been found for this index,
212 // arrange them into an inheritance hierarchy.
213 resolveIndex(state);
214}
215
216/*!
217 Reads an element from the index file and creates the appropriate nodes
218 under \a current. The \a indexUrl supplies imported link locations;
219 \a state retains deferred relationships and shared documentation for this
220 file's remaining elements.
221 */
222void QDocIndexFiles::readIndexSection(QXmlStreamReader &reader, Node *current,
223 const QString &indexUrl, ReadState &state)
224{
225 QXmlStreamAttributes attributes = reader.attributes();
226 QStringView elementName = reader.name();
227
228 QString name = attributes.value(QLatin1String("name")).toString();
229 QString href = attributes.value(QLatin1String("href")).toString();
230 Node *node{nullptr};
231 Location location;
232 Aggregate *parent = nullptr;
233 bool hasReadChildren = false;
234
235 if (current->isAggregate())
236 parent = static_cast<Aggregate *>(current);
237
238 if (attributes.hasAttribute(QLatin1String("related"))) {
239 bool isIntTypeRelatedValue = false;
240 int relatedIndex = attributes.value(QLatin1String("related")).toInt(&isIntTypeRelatedValue);
241 if (isIntTypeRelatedValue) {
242 if (adoptRelatedNode(parent, relatedIndex, state)) {
243 reader.skipCurrentElement();
244 return;
245 }
246 } else {
247 QList<Node *>::iterator nodeIterator =
248 std::find_if(state.relatedNodes.begin(), state.relatedNodes.end(), [&](const Node *relatedNode) {
249 return (name == relatedNode->name() && href == relatedNode->url().section(QLatin1Char('/'), -1));
250 });
251
252 if (nodeIterator != state.relatedNodes.end() && parent) {
253 parent->adoptChild(*nodeIterator);
254 reader.skipCurrentElement();
255 return;
256 }
257 }
258 }
259
260 QString filePath;
261 int lineNo = 0;
262 if (attributes.hasAttribute(QLatin1String("filepath"))) {
263 filePath = attributes.value(QLatin1String("filepath")).toString();
264 lineNo = attributes.value("lineno").toInt();
265 }
266 if (parent && elementName == QLatin1String("namespace")) {
267 auto *namespaceNode = new NamespaceNode(parent, name);
268 node = namespaceNode;
269 if (!indexUrl.isEmpty())
270 location = Location(indexUrl + QLatin1Char('/') + name.toLower() + ".html");
271 else if (!indexUrl.isNull())
272 location = Location(name.toLower() + ".html");
273 } else if (parent && (elementName == QLatin1String("class") || elementName == QLatin1String("struct")
274 || elementName == QLatin1String("union"))) {
276 if (elementName == QLatin1String("class"))
277 type = NodeType::Class;
278 else if (elementName == QLatin1String("struct"))
279 type = NodeType::Struct;
280 else if (elementName == QLatin1String("union"))
281 type = NodeType::Union;
282 node = new ClassNode(type, parent, name);
283 if (attributes.hasAttribute(QLatin1String("bases"))) {
284 QString bases = attributes.value(QLatin1String("bases")).toString();
285 if (!bases.isEmpty())
286 state.bases.append(
287 std::pair<ClassNode *, QString>(static_cast<ClassNode *>(node), bases));
288 }
289 if (!indexUrl.isEmpty())
290 location = Location(indexUrl + QLatin1Char('/') + name.toLower() + ".html");
291 else if (!indexUrl.isNull())
292 location = Location(name.toLower() + ".html");
293 bool abstract = false;
294 if (attributes.value(QLatin1String("abstract")) == QLatin1String("true"))
295 abstract = true;
296 node->setAbstract(abstract);
297 } else if (parent && elementName == QLatin1String("header")) {
298 node = new HeaderNode(parent, name);
299
300 if (attributes.hasAttribute(QLatin1String("location")))
301 name = attributes.value(QLatin1String("location")).toString();
302
303 if (!indexUrl.isEmpty())
304 location = Location(indexUrl + QLatin1Char('/') + name);
305 else if (!indexUrl.isNull())
306 location = Location(name);
307 } else if (parent && ((elementName == QLatin1String("qmlclass") || elementName == QLatin1String("qmlvaluetype")
308 || elementName == QLatin1String("qmlbasictype")))) {
309 auto *qmlTypeNode = new QmlTypeNode(parent, name,
310 elementName == QLatin1String("qmlclass") ? NodeType::QmlType : NodeType::QmlValueType);
311 QString logicalModuleName = attributes.value(QLatin1String("qml-module-name")).toString();
312 if (!logicalModuleName.isEmpty())
313 m_qdb->addToQmlModule(logicalModuleName, qmlTypeNode);
314 bool abstract = false;
315 if (attributes.value(QLatin1String("abstract")) == QLatin1String("true"))
316 abstract = true;
317 qmlTypeNode->setAbstract(abstract);
318 if (attributes.value(QLatin1String("singleton")) == QLatin1String("true"))
319 qmlTypeNode->setSingleton();
320 else if (attributes.value(QLatin1String("uncreatable")) == QLatin1String("true"))
321 qmlTypeNode->setUncreatable();
322 QString qmlFullBaseName = attributes.value(QLatin1String("qml-base-type")).toString();
323 if (!qmlFullBaseName.isEmpty()) {
324 qmlTypeNode->setQmlBaseName(qmlFullBaseName);
325 }
326 if (attributes.hasAttribute(QLatin1String("location")))
327 name = attributes.value("location").toString();
328 if (!indexUrl.isEmpty())
329 location = Location(indexUrl + QLatin1Char('/') + name);
330 else if (!indexUrl.isNull())
331 location = Location(name);
332 node = qmlTypeNode;
333 } else if (parent && elementName == QLatin1String("qmlproperty")) {
334 // Find the associated property group, if defined.
335 QString propertyGroup = attributes.value("inpropertygroup").toString();
336
337 if (attributes.value("propertygroup") == "true") {
338 // A node representing a property group defines the name of the group.
339 propertyGroup = attributes.value("fullname").toString();
340 } else {
341 QString type = attributes.value(QLatin1String("type")).toString();
342 bool attached = false;
343 if (attributes.value(QLatin1String("attached")) == QLatin1String("true"))
344 attached = true;
345 bool readonly = false;
346 if (attributes.value(QLatin1String("writable")) == QLatin1String("false"))
347 readonly = true;
348 auto *qmlPropertyNode = new QmlPropertyNode(parent, name, std::move(type), attached);
349 qmlPropertyNode->markReadOnly(readonly);
350 if (attributes.value(QLatin1String("required")) == QLatin1String("true"))
351 qmlPropertyNode->setRequired();
352
353 node = qmlPropertyNode;
354 }
355
356 if (!propertyGroup.isEmpty()) {
357 // Handle the relevant property group by obtaining or creating a
358 // shared comment node.
359 SharedCommentNode *scn = state.sharedDocNodes.value(propertyGroup);
360 if (!scn) {
361 scn = new SharedCommentNode(static_cast<QmlTypeNode *>(parent), 0, propertyGroup.split(".").last());
362 state.sharedDocNodes[propertyGroup] = scn;
363 }
364 if (node) {
365 // Regular properties are appended to the shared comment node.
366 scn->append(node);
367 } else {
368 node = scn;
369 hasReadChildren = true;
370 }
371 }
372 } else if (elementName == QLatin1String("group")) {
373 auto *collectionNode = m_qdb->addGroup(name);
374 collectionNode->setTitle(attributes.value(QLatin1String("title")).toString());
375 collectionNode->setSubtitle(attributes.value(QLatin1String("subtitle")).toString());
376 if (attributes.value(QLatin1String("seen")) == QLatin1String("true"))
377 collectionNode->markSeen();
378 node = collectionNode;
379 } else if (elementName == QLatin1String("module")) {
380 auto *collectionNode = m_qdb->addModule(name);
381 collectionNode->setTitle(attributes.value(QLatin1String("title")).toString());
382 collectionNode->setSubtitle(attributes.value(QLatin1String("subtitle")).toString());
383 if (attributes.value(QLatin1String("seen")) == QLatin1String("true"))
384 collectionNode->markSeen();
385 node = collectionNode;
386 } else if (elementName == QLatin1String("concept")) {
387 auto *collectionNode = m_qdb->addConcept(name);
388 collectionNode->setTitle(attributes.value(QLatin1String("title")).toString());
389 collectionNode->setSubtitle(attributes.value(QLatin1String("subtitle")).toString());
390 if (attributes.value(QLatin1String("seen")) == QLatin1String("true"))
391 collectionNode->markSeen();
392 node = collectionNode;
393 } else if (elementName == QLatin1String("qmlmodule")) {
394 auto *collectionNode = m_qdb->addQmlModule(name);
395 const QStringList info = QStringList()
396 << name
397 << QString(attributes.value(QLatin1String("qml-module-version")).toString());
398 collectionNode->setLogicalModuleInfo(info);
399 collectionNode->setTitle(attributes.value(QLatin1String("title")).toString());
400 collectionNode->setSubtitle(attributes.value(QLatin1String("subtitle")).toString());
401 if (attributes.value(QLatin1String("seen")) == QLatin1String("true"))
402 collectionNode->markSeen();
403 node = collectionNode;
404 } else if (elementName == QLatin1String("page")) {
405 QDocAttr subtype = QDocAttrNone;
406 QString attr = attributes.value(QLatin1String("subtype")).toString();
407 if (attr == QLatin1String("attribution")) {
408 subtype = QDocAttrAttribution;
409 } else if (attr == QLatin1String("example")) {
410 subtype = QDocAttrExample;
411 } else if (attr == QLatin1String("file")) {
412 subtype = QDocAttrFile;
413 } else if (attr == QLatin1String("image")) {
414 subtype = QDocAttrImage;
415 } else if (attr == QLatin1String("page")) {
416 subtype = QDocAttrDocument;
417 } else if (attr == QLatin1String("externalpage")) {
418 subtype = QDocAttrExternalPage;
419 } else
420 goto done;
421
422 if (current->isExample()) {
423 auto *exampleNode = static_cast<ExampleNode *>(current);
424 if (subtype == QDocAttrFile) {
425 exampleNode->appendFile(name);
426 goto done;
427 } else if (subtype == QDocAttrImage) {
428 exampleNode->appendImage(name);
429 goto done;
430 }
431 } else if (parent) {
432 PageNode *pageNode = nullptr;
433 if (subtype == QDocAttrExample)
434 pageNode = new ExampleNode(parent, name);
435 else if (subtype == QDocAttrExternalPage)
436 pageNode = new ExternalPageNode(parent, name);
437 else {
438 pageNode = new PageNode(parent, name);
439 if (subtype == QDocAttrAttribution) pageNode->markAttribution();
440 }
441
442 pageNode->setTitle(attributes.value(QLatin1String("title")).toString());
443
444 if (attributes.hasAttribute(QLatin1String("location")))
445 name = attributes.value(QLatin1String("location")).toString();
446
447 if (!indexUrl.isEmpty())
448 location = Location(indexUrl + QLatin1Char('/') + name);
449 else if (!indexUrl.isNull())
450 location = Location(name);
451
452 node = pageNode;
453 }
454 } else if (parent && (elementName == QLatin1String("enum") || elementName == QLatin1String("qmlenum"))) {
455 EnumNode *enumNode;
456 if (elementName == QLatin1String("enum"))
457 enumNode = new EnumNode(parent, name, attributes.hasAttribute("scoped"));
458 else
459 enumNode = new QmlEnumNode(parent, name);
460
461 if (!indexUrl.isEmpty())
462 location = Location(indexUrl + QLatin1Char('/') + parent->name().toLower() + ".html");
463 else if (!indexUrl.isNull())
464 location = Location(parent->name().toLower() + ".html");
465
466 if (attributes.value("anonymous") == "true")
467 enumNode->setAnonymous(true);
468
469 while (reader.readNextStartElement()) {
470 QXmlStreamAttributes childAttributes = reader.attributes();
471 if (reader.name() == QLatin1String("value")) {
472 EnumItem item(childAttributes.value(QLatin1String("name")).toString(),
473 childAttributes.value(QLatin1String("value")).toString(),
474 childAttributes.value(QLatin1String("since")).toString()
475 );
476 enumNode->addItem(item);
477 } else if (reader.name() == QLatin1String("keyword")) {
478 insertTarget(TargetRec::Keyword, childAttributes, enumNode);
479 } else if (reader.name() == QLatin1String("target")) {
480 insertTarget(TargetRec::Target, childAttributes, enumNode);
481 }
482 reader.skipCurrentElement();
483 }
484
485 node = enumNode;
486
487 hasReadChildren = true;
488 } else if (parent && elementName == QLatin1String("typedef")) {
489 TypedefNode *typedefNode;
490 if (attributes.hasAttribute("aliasedtype"))
491 typedefNode = new TypeAliasNode(parent, name, attributes.value(QLatin1String("aliasedtype")).toString());
492 else
493 typedefNode = new TypedefNode(parent, name);
494
495 // Associate the typedef with an enum, if specified.
496 if (attributes.hasAttribute("enum")) {
497 auto path = attributes.value(QLatin1String("enum")).toString();
498 const Node *enode = m_qdb->findNodeForTarget(path, typedefNode);
499 if (enode && enode->isEnumType()) {
500 const EnumNode *n = static_cast<const EnumNode *>(enode);
501 const_cast<EnumNode *>(n)->setFlagsType(typedefNode);
502 }
503 }
504 node = typedefNode;
505
506 if (!indexUrl.isEmpty())
507 location = Location(indexUrl + QLatin1Char('/') + parent->name().toLower() + ".html");
508 else if (!indexUrl.isNull())
509 location = Location(parent->name().toLower() + ".html");
510 } else if (parent && elementName == QLatin1String("property")) {
511 auto *propNode = new PropertyNode(parent, name);
512 node = propNode;
513 if (attributes.value(QLatin1String("bindable")) == QLatin1String("true"))
514 propNode->setPropertyType(PropertyNode::PropertyType::BindableProperty);
515
516 propNode->setWritable(attributes.value(QLatin1String("writable")) != QLatin1String("false"));
517 propNode->setDataType(attributes.value(QLatin1String("dataType")).toString());
518
519 if (attributes.value(QLatin1String("constant")) == QLatin1String("true"))
520 propNode->setConstant();
521
522 if (!indexUrl.isEmpty())
523 location = Location(indexUrl + QLatin1Char('/') + parent->name().toLower() + ".html");
524 else if (!indexUrl.isNull())
525 location = Location(parent->name().toLower() + ".html");
526
527 } else if (parent && elementName == QLatin1String("function")) {
528 QString t = attributes.value(QLatin1String("meta")).toString();
529 bool attached = false;
530 Metaness metaness = Metaness::Plain;
531 if (!t.isEmpty())
532 metaness = FunctionNode::getMetaness(t);
533 if (attributes.value(QLatin1String("attached")) == QLatin1String("true"))
534 attached = true;
535 auto *fn = new FunctionNode(metaness, parent, name, attached);
536
537 fn->setReturnType(attributes.value(QLatin1String("type")).toString());
538
539 const auto &declaredTypeAttr = attributes.value(QLatin1String("declaredtype"));
540 if (!declaredTypeAttr.isEmpty())
541 fn->setDeclaredReturnType(declaredTypeAttr.toString());
542
543 if (fn->isCppNode()) {
544 fn->setVirtualness(attributes.value(QLatin1String("virtual")).toString());
545 fn->setConst(attributes.value(QLatin1String("const")) == QLatin1String("true"));
546 fn->setStatic(attributes.value(QLatin1String("static")) == QLatin1String("true"));
547 fn->setFinal(attributes.value(QLatin1String("final")) == QLatin1String("true"));
548 fn->setOverride(attributes.value(QLatin1String("override")) == QLatin1String("true"));
549
550 if (attributes.value(QLatin1String("explicit")) == QLatin1String("true"))
551 fn->markExplicit();
552
553 if (attributes.value(QLatin1String("constexpr")) == QLatin1String("true"))
554 fn->markConstexpr();
555
556 if (attributes.value(QLatin1String("explicitly-defaulted")) == QLatin1String("true"))
557 fn->markExplicitlyDefaulted();
558
559 if (attributes.value(QLatin1String("deleted")) == QLatin1String("true"))
560 fn->markDeletedAsWritten();
561 if (attributes.value(QLatin1String("hidden-friend")) == QLatin1String("true"))
562 fn->setHiddenFriend(true);
563
564 if (attributes.value(QLatin1String("noexcept")) == QLatin1String("true")) {
565 fn->markNoexcept(attributes.value("noexcept_expression").toString());
566 }
567
568 if (attributes.hasAttribute(QLatin1String("trailing_requires")))
569 fn->setTrailingRequiresClause(attributes.value(QLatin1String("trailing_requires")).toString());
570
571 qsizetype refness = attributes.value(QLatin1String("refness")).toUInt();
572 if (refness == 1)
573 fn->setRef(true);
574 else if (refness == 2)
575 fn->setRefRef(true);
576 /*
577 Theoretically, this should ensure that each function
578 node receives the same overload number and overload
579 flag it was written with, and it should be unnecessary
580 to call normalizeOverloads() for index nodes.
581 */
582 if (attributes.value(QLatin1String("overload")) == QLatin1String("true"))
583 fn->setOverloadNumber(attributes.value(QLatin1String("overload-number")).toUInt());
584 else
585 fn->setOverloadNumber(0);
586 }
587
588 /*
589 Note: The "signature" attribute was written to the
590 index file, but it is not read back in. That is ok
591 because we reconstruct the parameter list and the
592 return type, from which the signature was built in
593 the first place and from which it can be rebuilt.
594 */
595 while (reader.readNextStartElement()) {
596 QXmlStreamAttributes childAttributes = reader.attributes();
597 if (reader.name() == QLatin1String("parameter")) {
598 QString type = childAttributes.value(QLatin1String("type")).toString();
599 QString name = childAttributes.value(QLatin1String("name")).toString();
600 QString default_ = childAttributes.value(QLatin1String("default")).toString();
601 fn->parameters().append(type, name, default_);
602 } else if (reader.name() == QLatin1String("keyword")) {
603 insertTarget(TargetRec::Keyword, childAttributes, fn);
604 } else if (reader.name() == QLatin1String("target")) {
605 insertTarget(TargetRec::Target, childAttributes, fn);
606 }
607 reader.skipCurrentElement();
608 }
609
610 node = fn;
611 if (!indexUrl.isEmpty())
612 location = Location(indexUrl + QLatin1Char('/') + parent->name().toLower() + ".html");
613 else if (!indexUrl.isNull())
614 location = Location(parent->name().toLower() + ".html");
615
616 hasReadChildren = true;
617 } else if (parent && elementName == QLatin1String("variable")) {
618 auto *varNode = new VariableNode(parent, name);
619 varNode->setLeftType(attributes.value("type").toString());
620 varNode->setStatic((attributes.value("static").toString() == "true") ? true : false);
621 node = varNode;
622 if (!indexUrl.isEmpty())
623 location = Location(indexUrl + QLatin1Char('/') + parent->name().toLower() + ".html");
624 else if (!indexUrl.isNull())
625 location = Location(parent->name().toLower() + ".html");
626 } else if (elementName == QLatin1String("keyword")) {
627 insertTarget(TargetRec::Keyword, attributes, current);
628 goto done;
629 } else if (elementName == QLatin1String("target")) {
630 insertTarget(TargetRec::Target, attributes, current);
631 goto done;
632 } else if (elementName == QLatin1String("contents")) {
633 insertTarget(TargetRec::Contents, attributes, current);
634 goto done;
635 } else if (parent && elementName == QLatin1String("proxy")) {
636 node = new ProxyNode(parent, name);
637 if (!indexUrl.isEmpty())
638 location = Location(indexUrl + QLatin1Char('/') + name.toLower() + ".html");
639 else if (!indexUrl.isNull())
640 location = Location(name.toLower() + ".html");
641 } else {
642 goto done;
643 }
644
645 if (node) {
646 // Read attributes for the requisites table.
647 if (node->isCollectionNode()) {
648 auto *cn = static_cast<CollectionNode *>(node);
649 if (attributes.hasAttribute(QLatin1String("cmakepackage")))
650 cn->setCMakePackage(attributes.value(QLatin1String("cmakepackage")).toString());
651 if (attributes.hasAttribute(QLatin1String("cmakecomponent")))
652 cn->setCMakeComponent(attributes.value(QLatin1String("cmakecomponent")).toString());
653 if (attributes.hasAttribute(QLatin1String("cmaketargetitem")))
654 cn->setCMakeTargetItem(attributes.value(QLatin1String("cmaketargetitem")).toString());
655 if (attributes.hasAttribute(QLatin1String("qtvariable")))
656 cn->setQtVariable(attributes.value(QLatin1String("qtvariable")).toString());
657 }
658 if (node->isAggregate() && attributes.hasAttribute(QLatin1String("includefile"))) {
659 auto *agg = static_cast<Aggregate *>(node);
660 agg->setIncludeFile(attributes.value(QLatin1String("includefile")).toString());
661 }
662
663 if (!href.isEmpty()) {
664 node->setUrl(href);
665 // Include the index URL if it exists
666 if (!node->isExternalPage() && !indexUrl.isEmpty())
667 node->setUrl(indexUrl + QLatin1Char('/') + href);
668 }
669
670 const QString access = attributes.value(QLatin1String("access")).toString();
671 if (access == "protected")
672 node->setAccess(Access::Protected);
673 else if (access == "private")
674 node->setAccess(Access::Private);
675 else
676 node->setAccess(Access::Public);
677
678 if (attributes.hasAttribute(QLatin1String("related"))) {
680 state.relatedNodes << node;
681 }
682
683 if (attributes.hasAttribute(QLatin1String("threadsafety"))) {
684 QString threadSafety = attributes.value(QLatin1String("threadsafety")).toString();
685 if (threadSafety == QLatin1String("non-reentrant"))
687 else if (threadSafety == QLatin1String("reentrant"))
689 else if (threadSafety == QLatin1String("thread safe"))
691 else
693 } else
695
696 const QString category = attributes.value(QLatin1String("comparison_category")).toString();
697 node->setComparisonCategory(comparisonCategoryFromString(category.toStdString()));
698
699 QString status = attributes.value(QLatin1String("status")).toString();
700 // TODO: "obsolete" is kept for backward compatibility, remove in the near future
701 if (status == QLatin1String("obsolete") || status == QLatin1String("deprecated"))
703 else if (status == QLatin1String("preliminary"))
705 else if (status == QLatin1String("internal"))
707 else if (status == QLatin1String("internal-auto"))
709 else if (status == QLatin1String("ignored"))
711 else
713
714 QString physicalModuleName = attributes.value(QLatin1String("module")).toString();
715 if (!physicalModuleName.isEmpty())
716 m_qdb->addToModule(physicalModuleName, node);
717
718 QString since = attributes.value(QLatin1String("since")).toString();
719 if (!since.isEmpty()) {
720 node->setSince(since);
721 }
722
723 if (attributes.hasAttribute(QLatin1String("documented"))) {
724 if (attributes.value(QLatin1String("documented")) == QLatin1String("true"))
725 node->setHadDoc();
726 }
727
728 QString groupsAttr = attributes.value(QLatin1String("groups")).toString();
729 if (!groupsAttr.isEmpty()) {
730 const QStringList groupNames = groupsAttr.split(QLatin1Char(','));
731 for (const auto &group : groupNames) {
732 m_qdb->addToGroup(group, node);
733 }
734 }
735
736 // Create some content for the node.
737 QSet<QString> emptySet;
738 Location t(filePath);
739 if (!filePath.isEmpty()) {
740 t.setLineNo(lineNo);
741 node->setLocation(t);
742 location = t;
743 }
744 Doc doc(location, location, QString(), emptySet, emptySet); // placeholder
745 if (attributes.value(QLatin1String("auto-generated")) == QLatin1String("true"))
747 node->setDoc(doc);
748 node->setIndexNodeFlag(); // Important: This node came from an index file.
749 QString briefAttr = attributes.value(QLatin1String("brief")).toString();
750 if (!briefAttr.isEmpty()) {
751 node->setReconstitutedBrief(briefAttr);
752 }
753
754 if (const auto sortKey = attributes.value(QLatin1String("sortkey")).toString(); !sortKey.isEmpty()) {
756 if (auto *metaMap = node->doc().metaTagMap())
757 metaMap->insert("sortkey", sortKey);
758 }
759 if (!hasReadChildren) {
760 bool useParent = (elementName == QLatin1String("namespace") && name.isEmpty());
761 while (reader.readNextStartElement()) {
762 if (useParent)
763 readIndexSection(reader, parent, indexUrl, state);
764 else
765 readIndexSection(reader, node, indexUrl, state);
766 }
767 }
768 }
769
770done:
771 while (!reader.isEndElement()) {
772 if (reader.readNext() == QXmlStreamReader::Invalid) {
773 break;
774 }
775 }
776}
777
778void QDocIndexFiles::insertTarget(TargetRec::TargetType type,
779 const QXmlStreamAttributes &attributes, Node *node)
780{
781 int priority;
782 switch (type) {
784 priority = 1;
785 break;
787 priority = 2;
788 break;
790 priority = 3;
791 break;
792 default:
793 return;
794 }
795
796 QString name = attributes.value(QLatin1String("name")).toString();
797 QString title = attributes.value(QLatin1String("title")).toString();
798 m_qdb->insertTarget(name, title, type, node, priority);
799}
800
801/*!
802 This function tries to resolve class inheritance recorded in \a state
803 immediately after its index file is read. It is not always possible to
804 resolve a class inheritance at this point, because the base
805 class might be in an index file that hasn't been read yet, or
806 it might be in one of the header files that will be read for
807 the current module. These cases will be resolved after all
808 the index files and header and source files have been read,
809 just prior to beginning the generate phase for the current
810 module.
811
812 I don't think this is completely correct because it always
813 sets the access to public.
814 */
815void QDocIndexFiles::resolveIndex(ReadState &state)
816{
817 for (const auto &pair : std::as_const(state.bases)) {
818 const QStringList bases = pair.second.split(QLatin1Char(','));
819 for (const auto &base : bases) {
820 QStringList basePath = base.split(QString("::"));
821 Node *n = m_qdb->findClassNode(basePath);
822 if (n)
823 pair.first->addResolvedBaseClass(Access::Public, static_cast<ClassNode *>(n));
824 else
825 pair.first->addUnresolvedBaseClass(Access::Public, basePath);
826 }
827 }
828}
829
830static QString getAccessString(Access t)
831{
832
833 switch (t) {
834 case Access::Public:
835 return QLatin1String("public");
836 case Access::Protected:
837 return QLatin1String("protected");
838 case Access::Private:
839 return QLatin1String("private");
840 default:
841 break;
842 }
843 return QLatin1String("public");
844}
845
847{
848 switch (t) {
850 return QLatin1String("deprecated");
852 return QLatin1String("preliminary");
853 case Status::Active:
854 return QLatin1String("active");
855 case Status::Internal:
856 return QLatin1String("internal");
858 return QLatin1String("internal-auto");
860 return QLatin1String("ignored");
861 default:
862 break;
863 }
864 return QLatin1String("active");
865}
866
868{
869 switch (t) {
871 return QLatin1String("non-reentrant");
872 case Node::Reentrant:
873 return QLatin1String("reentrant");
874 case Node::ThreadSafe:
875 return QLatin1String("thread safe");
877 default:
878 break;
879 }
880 return QLatin1String("unspecified");
881}
882
883/*!
884 Returns the index of \a node in \a state's related non-member list,
885 adding it if necessary. The numbering lasts for this serialization
886 operation.
887*/
888int QDocIndexFiles::indexForNode(Node *node, WriteState &state)
889{
890 qsizetype i = state.relatedNodes.indexOf(node);
891 if (i == -1) {
892 i = state.relatedNodes.size();
893 state.relatedNodes << node;
894 }
895 return i;
896}
897
898/*!
899 Write an attribute to the current element using the \a writer for the
900 attribute with the given \a name if the \a value is not an empty string.
901*/
902static void writeNonEmpty(QXmlStreamWriter &writer, const QString &name, const QString &value)
903{
904 if (!value.isEmpty())
905 writer.writeAttribute(name, value);
906}
907
908/*!
909 Adopts the related non-member node identified by \a index to the
910 parent \a adoptiveParent. Looks up the index in the current import's
911 \a state. Returns \c true if successful.
912*/
913bool QDocIndexFiles::adoptRelatedNode(Aggregate *adoptiveParent, int index, ReadState &state)
914{
915 Node *related = state.relatedNodes.value(index);
916
917 if (adoptiveParent && related) {
918 adoptiveParent->adoptChild(related);
919 return true;
920 }
921
922 return false;
923}
924
925/*!
926 Write canonicalized versions of \\target and \\keyword identifiers
927 that appear in the documentation of \a node into the index using
928 \a writer, so that they can be used as link targets in external
929 documentation sets.
930*/
931void QDocIndexFiles::writeTargets(QXmlStreamWriter &writer, Node *node)
932{
933 if (node->doc().hasTargets()) {
934 for (const Atom *target : std::as_const(node->doc().targets())) {
935 const QString &title = target->string();
936 const QString name = target->count() >= 2 ? target->string(1)
937 : TextUtils::asAsciiPrintable(title);
938 writer.writeStartElement("target");
939 writer.writeAttribute("name", node->isExternalPage() ? title : name);
940 if (name != title)
941 writer.writeAttribute("title", title);
942 writer.writeEndElement(); // target
943 }
944 }
945 if (node->doc().hasKeywords()) {
946 for (const Atom *keyword : std::as_const(node->doc().keywords())) {
947 const QString &title = keyword->string();
948 const QString &name{TextUtils::asAsciiPrintable(title)};
949 writer.writeStartElement("keyword");
950 writer.writeAttribute("name", name);
951 if (name != title)
952 writer.writeAttribute("title", title);
953 writer.writeEndElement(); // keyword
954 }
955 }
956}
957
958/*!
959 Generate the index section with the given \a writer for the \a node
960 specified, returning true if an element was written, and returning
961 false if an element is not written.
962
963 The \a context supplies document locations and, for inline example entries,
964 example-file locations, along with inclusion and source-location policy.
965 The \a state numbers related nodes across the current output operation.
966 If supplied, \a post extends the section before it closes.
967
968 \note Function nodes are processed in generateFunctionSection()
969 */
970bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter &writer, Node *node,
971 const IndexSerializationContext &context, WriteState &state,
972 IndexSectionWriter *post)
973{
974 Q_ASSERT(context.documentLocation);
975 /*
976 Don't include index nodes in a new index file.
977 */
978 if (node->isIndexNode())
979 return false;
980
981 QString nodeName;
982 QString logicalModuleName;
983 QString logicalModuleVersion;
984 QString qmlFullBaseName;
985 QString baseNameAttr;
986 QString moduleNameAttr;
987 QString moduleVerAttr;
988
989 switch (node->nodeType()) {
991 nodeName = "namespace";
992 break;
993 case NodeType::Class:
994 nodeName = "class";
995 break;
996 case NodeType::Struct:
997 nodeName = "struct";
998 break;
999 case NodeType::Union:
1000 nodeName = "union";
1001 break;
1003 nodeName = "header";
1004 break;
1005 case NodeType::QmlEnum:
1006 nodeName = "qmlenum";
1007 break;
1008 case NodeType::QmlType:
1010 nodeName = (node->nodeType() == NodeType::QmlType) ? "qmlclass" : "qmlvaluetype";
1011 logicalModuleName = node->logicalModuleName();
1012 baseNameAttr = "qml-base-type";
1013 moduleNameAttr = "qml-module-name";
1014 moduleVerAttr = "qml-module-version";
1015 qmlFullBaseName = node->qmlFullBaseName();
1016 break;
1017 case NodeType::Page:
1018 case NodeType::Example:
1020 nodeName = "page";
1021 break;
1022 case NodeType::Group:
1023 nodeName = "group";
1024 break;
1025 case NodeType::Module:
1026 nodeName = "module";
1027 break;
1028 case NodeType::Concept:
1029 nodeName = "concept";
1030 break;
1032 nodeName = "qmlmodule";
1033 moduleNameAttr = "qml-module-name";
1034 moduleVerAttr = "qml-module-version";
1035 logicalModuleName = node->logicalModuleName();
1036 logicalModuleVersion = node->logicalModuleVersion();
1037 break;
1038 case NodeType::Enum:
1039 nodeName = "enum";
1040 break;
1042 case NodeType::Typedef:
1043 nodeName = "typedef";
1044 break;
1045 case NodeType::Property:
1046 nodeName = "property";
1047 break;
1048 case NodeType::Variable:
1049 nodeName = "variable";
1050 break;
1052 if (!node->isPropertyGroup())
1053 return false;
1054 // Add an entry for property groups so that they can be linked to
1055 nodeName = "qmlproperty";
1056 break;
1058 nodeName = "qmlproperty";
1059 break;
1060 case NodeType::Proxy:
1061 nodeName = "proxy";
1062 break;
1063 case NodeType::Function: // Now processed in generateFunctionSection()
1064 default:
1065 return false;
1066 }
1067
1068 QString objName = node->name();
1069 // Special case: only the root node should have an empty name.
1070 if (objName.isEmpty() && node != m_qdb->primaryTreeRoot())
1071 return false;
1072
1073 writer.writeStartElement(nodeName);
1074
1075 if (!node->isTextPageNode() && !node->isCollectionNode() && !node->isHeader()) {
1077 writer.writeAttribute("threadsafety", getThreadSafenessString(node->threadSafeness()));
1078 }
1079
1080 writer.writeAttribute("name", objName);
1081
1082 if (node->isPropertyGroup())
1083 writer.writeAttribute("propertygroup", "true");
1085 writer.writeAttribute("inpropertygroup", node->sharedCommentNode()->fullDocumentName());
1086
1087 // Write module and base type info for QML types
1088 if (!moduleNameAttr.isEmpty()) {
1089 if (!logicalModuleName.isEmpty())
1090 writer.writeAttribute(moduleNameAttr, logicalModuleName);
1091 if (!logicalModuleVersion.isEmpty())
1092 writer.writeAttribute(moduleVerAttr, logicalModuleVersion);
1093 }
1094 if (!baseNameAttr.isEmpty() && !qmlFullBaseName.isEmpty())
1095 writer.writeAttribute(baseNameAttr, qmlFullBaseName);
1096 else if (!baseNameAttr.isEmpty()) {
1097 const auto &qmlBase = static_cast<QmlTypeNode *>(node)->qmlBaseName();
1098 writeNonEmpty(writer, baseNameAttr, qmlBase);
1099 }
1100
1101 QString href;
1102 if (!node->isExternalPage()) {
1103 QString fullName = node->fullDocumentName();
1104 if (fullName != objName)
1105 writer.writeAttribute("fullname", fullName);
1106 href = context.documentLocation(node);
1107 } else
1108 href = node->name();
1109 if (node->isQmlNode()) {
1110 Aggregate *p = node->parent();
1111 if (p && p->isQmlType() && p->isAbstract())
1112 href.clear();
1113 }
1114 writeNonEmpty(writer, "href", href);
1115
1116 writer.writeAttribute("status", getStatusString(node->status()));
1117 if (!node->isTextPageNode() && !node->isCollectionNode() && !node->isHeader()) {
1118 writer.writeAttribute("access", getAccessString(node->access()));
1119 if (node->isAbstract())
1120 writer.writeAttribute("abstract", "true");
1121 }
1122 const Location &declLocation = node->declLocation();
1123 writeNonEmpty(writer, "location", declLocation.fileName());
1124 if (context.storeLocationInfo && !declLocation.filePath().isEmpty()) {
1125 writer.writeAttribute("filepath", declLocation.filePath());
1126 writer.writeAttribute("lineno", QString("%1").arg(declLocation.lineNo()));
1127 }
1128
1129 if (node->isRelatedNonmember())
1130 writer.writeAttribute("related", QString::number(indexForNode(node, state)));
1131
1132 writeNonEmpty(writer, "since", node->since());
1133
1134 if (node->hasDoc())
1135 writer.writeAttribute("documented", "true");
1136
1137 QStringList groups = m_qdb->groupNamesForNode(node);
1138 if (!groups.isEmpty())
1139 writer.writeAttribute("groups", groups.join(QLatin1Char(',')));
1140
1141 if (const auto *metamap = node->doc().metaTagMap(); metamap)
1142 if (const auto sortKey = metamap->value("sortkey"); !sortKey.isEmpty())
1143 writer.writeAttribute("sortkey", sortKey);
1144
1145 // Write attributes for the requisites table.
1146 if (node->isCollectionNode() && node->isModule()) {
1147 auto *cn = static_cast<CollectionNode *>(node);
1148 writeNonEmpty(writer, "cmakepackage", cn->cmakePackage());
1149 writeNonEmpty(writer, "cmakecomponent", cn->cmakeComponent());
1150 writeNonEmpty(writer, "cmaketargetitem", cn->cmakeTargetItem());
1151 writeNonEmpty(writer, "qtvariable", cn->qtVariable());
1152 }
1153
1154 if (node->isAggregate() && node->genus() == Genus::CPP && (!node->parent() || !node->parent()->isClassNode())) {
1155 auto *agg = static_cast<Aggregate *>(node);
1156 if (agg->includeFile())
1157 writer.writeAttribute("includefile", *agg->includeFile());
1158 }
1159
1160 QString brief = node->doc().trimmedBriefText(node->name()).toString();
1161 switch (node->nodeType()) {
1162 case NodeType::Class:
1163 case NodeType::Struct:
1164 case NodeType::Union: {
1165 // Classes contain information about their base classes.
1166 const auto *classNode = static_cast<const ClassNode *>(node);
1167 const QList<RelatedClass> &bases = classNode->baseClasses();
1168 QSet<QString> baseStrings;
1169 for (const auto &related : bases) {
1170 ClassNode *n = related.m_node;
1171 if (n)
1172 baseStrings.insert(n->fullName());
1173 else if (!related.m_path.isEmpty())
1174 baseStrings.insert(related.m_path.join(QLatin1String("::")));
1175 }
1176 if (!baseStrings.isEmpty()) {
1177 QStringList baseStringsAsList = baseStrings.values();
1178 baseStringsAsList.sort();
1179 writer.writeAttribute("bases", baseStringsAsList.join(QLatin1Char(',')));
1180 }
1181 writeNonEmpty(writer, "module", node->physicalModuleName());
1182 writeNonEmpty(writer, "brief", brief);
1183 if (auto category = node->comparisonCategory(); category != ComparisonCategory::None)
1184 writer.writeAttribute("comparison_category", comparisonCategoryAsString(category));
1185 } break;
1186 case NodeType::HeaderFile: {
1187 const auto *headerNode = static_cast<const HeaderNode *>(node);
1188 writeNonEmpty(writer, "module", headerNode->physicalModuleName());
1189 writeNonEmpty(writer, "brief", brief);
1190 writer.writeAttribute("title", headerNode->title());
1191 writer.writeAttribute("fulltitle", headerNode->fullTitle());
1192 writer.writeAttribute("subtitle", headerNode->subtitle());
1193 } break;
1194 case NodeType::Namespace: {
1195 const auto *namespaceNode = static_cast<const NamespaceNode *>(node);
1196 writeNonEmpty(writer, "module", namespaceNode->physicalModuleName());
1197 writeNonEmpty(writer, "brief", brief);
1198 writeNonEmpty(writer, "whereDocumented", namespaceNode->whereDocumented());
1199 } break;
1201 case NodeType::QmlType: {
1202 const auto *qmlTypeNode = static_cast<const QmlTypeNode *>(node);
1203 writeNonEmpty(writer, "title", qmlTypeNode->title());
1204 writeNonEmpty(writer, "fulltitle", qmlTypeNode->fullTitle());
1205 writeNonEmpty(writer, "subtitle", qmlTypeNode->subtitle());
1206 if (qmlTypeNode->isSingleton())
1207 writer.writeAttribute("singleton", "true");
1208 if (qmlTypeNode->isUncreatable())
1209 writer.writeAttribute("uncreatable", "true");
1210 writeNonEmpty(writer, "brief", brief);
1211 if (ClassNode *cn = qmlTypeNode->classNode()) {
1212 writer.writeAttribute("class", cn->fullDocumentName());
1213 }
1214 } break;
1215 case NodeType::Page:
1216 case NodeType::Example:
1218 if (node->isExample())
1219 writer.writeAttribute("subtype", "example");
1220 else if (node->isExternalPage())
1221 writer.writeAttribute("subtype", "externalpage");
1222 else
1223 writer.writeAttribute("subtype", (static_cast<PageNode*>(node)->isAttribution() ? "attribution" : "page"));
1224
1225 const auto *pageNode = static_cast<const PageNode *>(node);
1226 writeNonEmpty(writer, "title", pageNode->title());
1227 writeNonEmpty(writer, "fulltitle", pageNode->fullTitle());
1228 writeNonEmpty(writer, "subtitle", pageNode->subtitle());
1229 writeNonEmpty(writer, "brief", brief);
1230 } break;
1231 case NodeType::Group:
1232 case NodeType::Module:
1234 case NodeType::Concept: {
1235 const auto *collectionNode = static_cast<const CollectionNode *>(node);
1236 writer.writeAttribute("seen", collectionNode->wasSeen() ? "true" : "false");
1237 writeNonEmpty(writer, "title", collectionNode->title());
1238 writeNonEmpty(writer, "subtitle", collectionNode->subtitle());
1239 writeNonEmpty(writer, "module", collectionNode->physicalModuleName());
1240 writeNonEmpty(writer, "brief", brief);
1241 } break;
1242 case NodeType::QmlProperty: {
1243 auto *qmlPropertyNode = static_cast<QmlPropertyNode *>(node);
1244 writer.writeAttribute("type", qmlPropertyNode->dataType());
1245 writer.writeAttribute("attached", qmlPropertyNode->isAttached() ? "true" : "false");
1246 writer.writeAttribute("writable", qmlPropertyNode->isReadOnly() ? "false" : "true");
1247 if (qmlPropertyNode->isRequired())
1248 writer.writeAttribute("required", "true");
1249 writeNonEmpty(writer, "brief", brief);
1250 } break;
1251 case NodeType::Property: {
1252 const auto *propertyNode = static_cast<const PropertyNode *>(node);
1253
1254 if (propertyNode->propertyType() == PropertyNode::PropertyType::BindableProperty)
1255 writer.writeAttribute("bindable", "true");
1256
1257 if (!propertyNode->isWritable())
1258 writer.writeAttribute("writable", "false");
1259
1260 if (propertyNode->isConstant())
1261 writer.writeAttribute("constant", "true");
1262
1263 writer.writeAttribute("dataType", propertyNode->dataType());
1264
1265 writeNonEmpty(writer, "brief", brief);
1266 // Property access function names
1267 for (qsizetype i{0}; i < (qsizetype)PropertyNode::FunctionRole::NumFunctionRoles; ++i) {
1268 auto role{(PropertyNode::FunctionRole)i};
1269 for (const auto *fnNode : propertyNode->functions(role)) {
1270 writer.writeStartElement(PropertyNode::roleName(role));
1271 writer.writeAttribute("name", fnNode->name());
1272 writer.writeEndElement();
1273 }
1274 }
1275 } break;
1276 case NodeType::Variable: {
1277 const auto *variableNode = static_cast<const VariableNode *>(node);
1278 writer.writeAttribute("type", variableNode->dataType());
1279 writer.writeAttribute("static", variableNode->isStatic() ? "true" : "false");
1280 writeNonEmpty(writer, "brief", brief);
1281 } break;
1282 case NodeType::QmlEnum:
1283 case NodeType::Enum: {
1284 const auto *enumNode = static_cast<const EnumNode *>(node);
1285 if (enumNode->isScoped())
1286 writer.writeAttribute("scoped", "true");
1287 if (enumNode->flagsType())
1288 writer.writeAttribute("typedef", enumNode->flagsType()->fullDocumentName());
1289 if (enumNode->isAnonymous())
1290 writer.writeAttribute("anonymous", "true");
1291 const auto &items = enumNode->items();
1292 for (const auto &item : items) {
1293 writer.writeStartElement("value");
1294 writer.writeAttribute("name", item.name());
1295 if (node->isEnumType(Genus::CPP))
1296 writer.writeAttribute("value", item.value());
1297 writeNonEmpty(writer, "since", item.since());
1298 writer.writeEndElement(); // value
1299 }
1300 } break;
1301 case NodeType::Typedef: {
1302 const auto *typedefNode = static_cast<const TypedefNode *>(node);
1303 if (typedefNode->associatedEnum())
1304 writer.writeAttribute("enum", typedefNode->associatedEnum()->fullDocumentName());
1305 } break;
1307 writer.writeAttribute("aliasedtype", static_cast<const TypeAliasNode *>(node)->aliasedType());
1308 break;
1309 case NodeType::Function: // Now processed in generateFunctionSection()
1310 default:
1311 break;
1312 }
1313
1314 writeTargets(writer, node);
1315
1316 /*
1317 Some nodes have a table of contents. For these, we close
1318 the opening tag, create sub-elements for the items in the
1319 table of contents, and then add a closing tag for the
1320 element. Elements for all other nodes are closed in the
1321 opening tag.
1322 */
1323 if (node->isPageNode() || node->isCollectionNode()) {
1325 for (int i = 0; i < node->doc().tableOfContents().size(); ++i) {
1326 Atom *item = node->doc().tableOfContents()[i];
1327 int level = node->doc().tableOfContentsLevels()[i];
1328 QString title = Text::sectionHeading(item).toString();
1329 writer.writeStartElement("contents");
1330 writer.writeAttribute("name", Tree::refForAtom(item));
1331 writer.writeAttribute("title", title);
1332 writer.writeAttribute("level", QString::number(level));
1333 writer.writeEndElement(); // contents
1334 }
1335 }
1336 }
1337 // Some callers serialize example files and images separately.
1338 if (node->isExample()
1340 Q_ASSERT(context.exampleFileLocation);
1341 const auto *exampleNode = static_cast<const ExampleNode *>(node);
1342 const auto &files = exampleNode->files();
1343 const auto &images = exampleNode->images();
1344 for (const QString &file : files) {
1345 writer.writeStartElement("page");
1346 writer.writeAttribute("name", file);
1347 writer.writeAttribute("href", context.exampleFileLocation(file));
1348 writer.writeAttribute("status", "active");
1349 writer.writeAttribute("subtype", "file");
1350 writer.writeAttribute("title", "");
1351 writer.writeAttribute("fulltitle", Utilities::exampleFileTitle(file, Utilities::ExampleFileKind::File));
1352 writer.writeAttribute("subtitle", file);
1353 writer.writeEndElement(); // page
1354 }
1355 for (const QString &file : images) {
1356 writer.writeStartElement("page");
1357 writer.writeAttribute("name", file);
1358 writer.writeAttribute("href", context.exampleFileLocation(file));
1359 writer.writeAttribute("status", "active");
1360 writer.writeAttribute("subtype", "image");
1361 writer.writeAttribute("title", "");
1362 writer.writeAttribute("fulltitle", Utilities::exampleFileTitle(file, Utilities::ExampleFileKind::Image));
1363 writer.writeAttribute("subtitle", file);
1364 writer.writeEndElement(); // page
1365 }
1366 }
1367 // Append to the section if the callback object was set
1368 if (post)
1369 post->append(writer, node);
1370
1371 return true;
1372}
1373
1374/*!
1375 Writes a <function> element for \a fn using \a writer. The \a context
1376 supplies its href and inclusion policy, \a state numbers related nodes,
1377 and \a post, if supplied, extends the element before it closes.
1378 */
1379void QDocIndexFiles::generateFunctionSection(QXmlStreamWriter &writer, FunctionNode *fn,
1380 const IndexSerializationContext &context, WriteState &state,
1381 IndexSectionWriter *post)
1382{
1383 const NodeContext nodeContext = fn->createContext();
1384 if (!InclusionFilter::isPubliclyVisible(context.inclusionPolicy, nodeContext))
1385 return;
1386
1387 const QString objName = fn->name();
1388 writer.writeStartElement("function");
1389 writer.writeAttribute("name", objName);
1390
1391 const QString fullName = fn->fullDocumentName();
1392 if (fullName != objName)
1393 writer.writeAttribute("fullname", fullName);
1394 const QString href = context.documentLocation(fn);
1395 writeNonEmpty(writer, "href", href);
1397 writer.writeAttribute("threadsafety", getThreadSafenessString(fn->threadSafeness()));
1398 writer.writeAttribute("status", getStatusString(fn->status()));
1399 writer.writeAttribute("access", getAccessString(fn->access()));
1400
1401 const Location &declLocation = fn->declLocation();
1402 writeNonEmpty(writer, "location", declLocation.fileName());
1403 if (context.storeLocationInfo && !declLocation.filePath().isEmpty()) {
1404 writer.writeAttribute("filepath", declLocation.filePath());
1405 writer.writeAttribute("lineno", QString("%1").arg(declLocation.lineNo()));
1406 }
1407
1408 if (fn->hasDoc())
1409 writer.writeAttribute("documented", "true");
1410 if (fn->hasDoc() && fn->doc().isAutoGenerated())
1411 writer.writeAttribute("auto-generated", "true");
1412 if (fn->isRelatedNonmember())
1413 writer.writeAttribute("related", QString::number(indexForNode(fn, state)));
1414 writeNonEmpty(writer, "since", fn->since());
1415
1416 const QString brief = fn->doc().trimmedBriefText(fn->name()).toString();
1417 writer.writeAttribute("meta", fn->metanessString());
1418 if (fn->isCppNode()) {
1419 if (!fn->isNonvirtual())
1420 writer.writeAttribute("virtual", fn->virtualness());
1421
1422 if (fn->isConst())
1423 writer.writeAttribute("const", "true");
1424 if (fn->isStatic())
1425 writer.writeAttribute("static", "true");
1426 if (fn->isFinal())
1427 writer.writeAttribute("final", "true");
1428 if (fn->isOverride())
1429 writer.writeAttribute("override", "true");
1430 if (fn->isExplicit())
1431 writer.writeAttribute("explicit", "true");
1432 if (fn->isConstexpr())
1433 writer.writeAttribute("constexpr", "true");
1435 writer.writeAttribute("explicitly-defaulted", "true");
1437 writer.writeAttribute("deleted", "true");
1438 if (fn->isHiddenFriend())
1439 writer.writeAttribute("hidden-friend", "true");
1440
1441 if (auto noexcept_info = fn->getNoexcept()) {
1442 writer.writeAttribute("noexcept", "true");
1443 writeNonEmpty(writer, "noexcept_expression", *noexcept_info);
1444 }
1445
1446 if (const auto &trailing_requires = fn->trailingRequiresClause(); trailing_requires && !trailing_requires->isEmpty())
1447 writer.writeAttribute("trailing_requires", *trailing_requires);
1448
1449 /*
1450 This ensures that for functions that have overloads,
1451 the first function written is the one that is not an
1452 overload, and the overloads follow it immediately in
1453 the index file numbered from 1 to n.
1454 */
1455 if (fn->isOverload() && (fn->overloadNumber() > 0)) {
1456 writer.writeAttribute("overload", "true");
1457 writer.writeAttribute("overload-number", QString::number(fn->overloadNumber()));
1458 }
1459 if (fn->isRef())
1460 writer.writeAttribute("refness", QString::number(1));
1461 else if (fn->isRefRef())
1462 writer.writeAttribute("refness", QString::number(2));
1464 QStringList associatedProperties;
1465 for (const auto *node : fn->associatedProperties()) {
1466 associatedProperties << node->name();
1467 }
1468 associatedProperties.sort();
1469 writer.writeAttribute("associated-property",
1470 associatedProperties.join(QLatin1Char(',')));
1471 }
1472 } else {
1473 if (fn->isAttached())
1474 writer.writeAttribute("attached", "true");
1475 }
1476
1477 const auto &return_type = fn->returnType();
1478 if (!return_type.isEmpty())
1479 writer.writeAttribute("type", std::move(return_type));
1480
1481 const auto &declared_return_type = fn->declaredReturnType();
1482 if (declared_return_type.has_value())
1483 writer.writeAttribute("declaredtype", declared_return_type.value());
1484
1485 if (fn->isCppNode()) {
1486 writeNonEmpty(writer, "brief", brief);
1487
1488 /*
1489 Note: The "signature" attribute is written to the
1490 index file, but it is not read back in by qdoc. However,
1491 we need it for the webxml generator.
1492 */
1493 const QString signature = appendAttributesToSignature(fn);
1494 writer.writeAttribute("signature", signature);
1495
1496 QStringList groups = m_qdb->groupNamesForNode(fn);
1497 if (!groups.isEmpty())
1498 writer.writeAttribute("groups", groups.join(QLatin1Char(',')));
1499 }
1500
1501 for (int i = 0; i < fn->parameters().count(); ++i) {
1502 const Parameter &parameter = fn->parameters().at(i);
1503 writer.writeStartElement("parameter");
1504 writer.writeAttribute("type", parameter.type());
1505 writer.writeAttribute("name", parameter.name());
1506 writer.writeAttribute("default", parameter.defaultValue());
1507 writer.writeEndElement(); // parameter
1508 }
1509
1510 writeTargets(writer, fn);
1511
1512 // Append to the section if the callback object was set
1513 if (post)
1514 post->append(writer, fn);
1515
1516 writer.writeEndElement(); // function
1517}
1518
1519/*!
1520 \internal
1521
1522 Constructs the signature to be written to an index file for the function
1523 represented by FunctionNode \a fn.
1524
1525 'const' is already part of FunctionNode::signature(), which forms the basis
1526 for the signature returned by this method. The method adds, where
1527 applicable, the C++ keywords "final", "override", "= 0", or trailing
1528 requires clauses to the signature carried by the FunctionNode itself.
1529 */
1530QString QDocIndexFiles::appendAttributesToSignature(const FunctionNode *fn) const noexcept
1531{
1532 QString signature = fn->signature(Node::SignatureReturnType);
1533
1534 if (fn->isFinal())
1535 signature += " final";
1536 if (fn->isOverride())
1537 signature += " override";
1538 if (fn->isPureVirtual())
1539 signature += " = 0";
1540 if (const auto &req = fn->trailingRequiresClause(); req && !req->isEmpty())
1541 signature += " requires " + *req;
1542
1543 return signature;
1544}
1545
1546/*!
1547 Outputs a <function> element to the index for each FunctionNode in
1548 an \a aggregate, using \a writer.
1549 The \a aggregate has a function map that contains all the
1550 function nodes (a vector of overloads) indexed by function
1551 name.
1552
1553 If a function element represents an overload, it has an
1554 \c overload attribute set to \c true and an \c {overload-number}
1555 attribute set to the function's overload number.
1556
1557 The \a context supplies publication locations and inclusion policy.
1558 The \a state preserves related-node numbering across the aggregate;
1559 \a post, if supplied, extends each function element.
1560 */
1561void QDocIndexFiles::generateFunctionSections(QXmlStreamWriter &writer, Aggregate *aggregate,
1562 const IndexSerializationContext &context, WriteState &state,
1563 IndexSectionWriter *post)
1564{
1565 for (auto functions : std::as_const(aggregate->functionMap())) {
1566 std::for_each(functions.begin(), functions.end(),
1567 [this, &writer, &context, &state, post](FunctionNode *fn) {
1568 generateFunctionSection(writer, fn, context, state, post);
1569 }
1570 );
1571 }
1572}
1573
1575{
1576 auto children = aggregate->nonFunctionChildren();
1577 std::sort(children.begin(), children.end(), Node::nodeLessThan);
1578 return children;
1579}
1580
1581/*!
1582 Generates a section for \a node and recursively serializes its children
1583 using \a writer. The \a context supplies publication locations and
1584 inclusion policy. The \a state preserves related-node numbering and
1585 identifies the primary root whose traversal ends with collection and
1586 proxy sections. If supplied, \a post extends each section.
1587*/
1588void QDocIndexFiles::generateIndexSections(QXmlStreamWriter &writer, Node *node,
1589 const IndexSerializationContext &context, WriteState &state,
1590 IndexSectionWriter *post)
1591{
1592 Q_ASSERT(context.documentLocation);
1593
1594 /*
1595 Note that groups, modules, QML modules, and proxies are written
1596 after all the other nodes.
1597 */
1598 if (node->isCollectionNode() || node->isGroup() || node->isModule() ||
1600 return;
1601
1602 const NodeContext nodeContext = node->createContext();
1603 if (!InclusionFilter::isPubliclyVisible(context.inclusionPolicy, nodeContext))
1604 return;
1605
1606 if (generateIndexSection(writer, node, context, state, post)) {
1607 if (node->isAggregate()) {
1608 auto *aggregate = static_cast<Aggregate *>(node);
1609 // First write the function children, then write the nonfunction children.
1610 generateFunctionSections(writer, aggregate, context, state, post);
1611 auto nonFunctionChildren = sortedNonFunctionChildren(aggregate);
1612 for (auto *node : nonFunctionChildren)
1613 generateIndexSections(writer, node, context, state, post);
1614 }
1615
1616 if (node == state.root) {
1617 /*
1618 We wait until the end of the index file to output the group, module,
1619 QML module, and proxy nodes. By outputting them at the end, when we read
1620 the index file back in, all the group/module/proxy member
1621 nodes will have already been created. It is then only necessary to
1622 create the collection node and add each member to its member list.
1623 */
1624 const CNMap &groups = m_qdb->groups();
1625 if (!groups.isEmpty()) {
1626 for (auto it = groups.constBegin(); it != groups.constEnd(); ++it) {
1627 if (generateIndexSection(writer, it.value(), context, state, post))
1628 writer.writeEndElement();
1629 }
1630 }
1631
1632 const CNMap &modules = m_qdb->modules();
1633 if (!modules.isEmpty()) {
1634 for (auto it = modules.constBegin(); it != modules.constEnd(); ++it) {
1635 if (generateIndexSection(writer, it.value(), context, state, post))
1636 writer.writeEndElement();
1637 }
1638 }
1639
1640 const CNMap &qmlModules = m_qdb->qmlModules();
1641 if (!qmlModules.isEmpty()) {
1642 for (auto it = qmlModules.constBegin(); it != qmlModules.constEnd(); ++it) {
1643 if (generateIndexSection(writer, it.value(), context, state, post))
1644 writer.writeEndElement();
1645 }
1646 }
1647
1648 const CNMap &concepts = m_qdb->concepts();
1649 if (!concepts.isEmpty()) {
1650 for (auto it = concepts.constBegin(); it != concepts.constEnd(); ++it) {
1651 if (generateIndexSection(writer, it.value(), context, state, post))
1652 writer.writeEndElement();
1653 }
1654 }
1655
1656 for (auto *p : m_qdb->primaryTree()->proxies()) {
1657 if (generateIndexSection(writer, p, context, state, post)) {
1658 auto aggregate = static_cast<Aggregate *>(p);
1659 generateFunctionSections(writer, aggregate, context, state, post);
1660 auto nonFunctionChildren = sortedNonFunctionChildren(aggregate);
1661 for (auto *n : nonFunctionChildren)
1662 generateIndexSections(writer, n, context, state, post);
1663 writer.writeEndElement();
1664 }
1665 }
1666 }
1667
1668 writer.writeEndElement();
1669 }
1670}
1671
1672/*!
1673 Writes a qdoc module index in XML to a file named \a fileName.
1674 \a url is the \c url attribute of the <INDEX> element.
1675 \a title is the \c title attribute of the <INDEX> element.
1676 \a context supplies publication locations, the project identity, and
1677 serialization policy. A fresh write state keeps this export's related-node
1678 numbering independent of earlier output.
1679 */
1680void QDocIndexFiles::generateIndex(const QString &fileName, const QString &url,
1681 const QString &title, const IndexSerializationContext &context)
1682{
1683 Q_ASSERT(context.documentLocation);
1684
1685 QFile file(fileName);
1686 if (!file.open(QFile::WriteOnly | QFile::Text))
1687 return;
1688
1689 qCDebug(lcQdoc) << "Writing index file:" << fileName;
1690
1691 // Related-node numbering belongs to this export, not earlier WebXML output.
1692 WriteState state;
1693 state.root = m_qdb->primaryTreeRoot();
1694
1695 QXmlStreamWriter writer(&file);
1696 writer.setAutoFormatting(true);
1697 writer.writeStartDocument();
1698 writer.writeDTD("<!DOCTYPE QDOCINDEX>");
1699
1700 writer.writeStartElement("INDEX");
1701 writer.writeAttribute("url", url);
1702 writer.writeAttribute("title", title);
1703 writer.writeAttribute("version", m_qdb->version());
1704 writer.writeAttribute("project", context.project);
1705
1706 writeNonEmpty(writer, "indexTitle", state.root->tree()->indexTitle());
1707
1708 generateIndexSections(writer, state.root, context, state);
1709
1710 writer.writeEndElement(); // INDEX
1711 writer.writeEndElement(); // QDOCINDEX
1712 writer.writeEndDocument();
1713 file.close();
1714}
1715
1716QT_END_NAMESPACE
NodeList nonFunctionChildren() const
Returns a copy of the child nodes of this aggregate that are not function nodes, in the order they ap...
void adoptChild(Node *child)
This Aggregate becomes the adoptive parent of child.
The Atom class is the fundamental unit for representing documents internally.
Definition atom.h:19
The ClassNode represents a C++ class.
Definition classnode.h:23
Definition doc.h:32
bool hasTableOfContents() const
Definition doc.cpp:287
bool hasKeywords() const
Definition doc.cpp:292
bool hasTargets() const
Definition doc.cpp:297
void markAutoGenerated()
Marks this documentation as auto-generated by QDoc.
Definition doc.cpp:252
QStringMultiMap * metaTagMap() const
Definition doc.cpp:342
void constructExtra() const
Definition doc.cpp:352
void setFlagsType(TypedefNode *typedefNode)
Definition enumnode.cpp:81
void addItem(const EnumItem &item)
Add item to the enum type's item list.
Definition enumnode.cpp:23
void setAnonymous(bool anonymous)
Definition enumnode.h:43
The ExternalPageNode represents an external documentation page.
This node is used to represent any kind of function being documented.
signed short overloadNumber() const
Returns the overload number for this function.
bool isOverride() const
bool isPureVirtual() const override
bool isConstexpr() const
bool isRef() const
bool isNonvirtual() const
bool isHiddenFriend() const
bool isExplicit() const
bool isOverload() const
bool isConst() const
bool isRefRef() const
bool isAttached() const override
Returns true if the QML property or QML method node is marked as attached.
bool isDeletedAsWritten() const
bool isStatic() const override
Returns true if the FunctionNode represents a static function.
bool isFinal() const
bool isExplicitlyDefaulted() const
Parameters & parameters()
bool hasAssociatedProperties() const
static bool isPubliclyVisible(const InclusionPolicy &policy, const NodeContext &context)
virtual void append(QXmlStreamWriter &writer, Node *node)=0
The Location class provides a way to mark a location in a file.
Definition location.h:20
int lineNo() const
Returns the current line number.
Definition location.h:50
void setLineNo(int no)
Definition location.h:42
Location & operator=(const Location &other)
The assignment operator does a deep copy of the entire state of other into this Location.
Definition location.cpp:79
This class represents a C++ namespace.
Tree * tree() const override
Returns a pointer to the Tree that contains this NamespaceNode.
A PageNode is a Node that generates a documentation page.
Definition pagenode.h:19
void markAttribution()
Definition pagenode.h:50
The Parameter class describes one function parameter.
Definition parameter.h:14
This class describes one instance of using the Q_PROPERTY macro.
A class for representing an Aggregate that is documented in a different module.
Definition proxynode.h:14
This class provides exclusive access to the qdoc database, which consists of a forrest of trees and a...
static QDocDatabase * qdocDB()
Creates the singleton.
const CNMap & qmlModules()
Returns a const reference to the collection of all QML module nodes in the primary tree.
NamespaceNode * primaryTreeRoot()
Returns a pointer to the root node of the primary tree.
const CNMap & modules()
Returns a const reference to the collection of all module nodes in the primary tree.
const CNMap & concepts()
const CNMap & groups()
Returns a const reference to the collection of all group nodes in the primary tree.
This class imports QDoc index files and serializes index sections for module indexes and WebXML outpu...
Status
Specifies the status of the QQmlIncubator.
bool isPropertyGroup() const override
Returns true if the node is a SharedCommentNode for documenting multiple C++ properties or multiple Q...
void append(Node *node)
Definition text.h:12
static Text sectionHeading(const Atom *sectionBegin)
Definition text.cpp:157
static std::string comparisonCategoryAsString(ComparisonCategory category)
#define CONFIG_URL
Definition config.h:460
NodeType
Definition genustypes.h:165
@ SharedComment
Definition genustypes.h:188
Metaness
Specifies the kind of function a FunctionNode represents.
Definition genustypes.h:242
Combined button and popup list for selecting options.
QList< Node * > NodeList
Definition node.h:45
QMap< QString, CollectionNode * > CNMap
Definition node.h:52
static QString getAccessString(Access t)
static NodeList sortedNonFunctionChildren(const Aggregate *aggregate)
static QString getThreadSafenessString(Node::ThreadSafeness t)
static QString getStatusString(Status t)
@ QDocAttrFile
@ QDocAttrAttribution
@ QDocAttrImage
@ QDocAttrExternalPage
@ QDocAttrExample
@ QDocAttrNone
@ QDocAttrDocument
static void writeNonEmpty(QXmlStreamWriter &writer, const QString &name, const QString &value)
Write an attribute to the current element using the writer for the attribute with the given name if t...
@ Deprecated
Definition status.h:12
@ Active
Definition status.h:14
@ Preliminary
Definition status.h:13
@ InternalAuto
Definition status.h:16
@ DontDocument
Definition status.h:17
@ Internal
Definition status.h:15
The Node class is the base class for all the nodes in QDoc's parse tree.
bool isExternalPage() const
Returns true if the node type is ExternalPage.
Definition node.h:100
const Doc & doc() const
Returns a reference to the node's Doc data member.
Definition node.h:239
bool isQmlNode() const
Returns true if this node's Genus value is QML.
Definition node.h:121
void setHadDoc()
Definition node.h:185
bool isGroup() const
Returns true if the node type is Group.
Definition node.h:105
void setAccess(Access t)
Sets the node's access type to t.
Definition node.h:172
void setIndexNodeFlag(bool isIndexNode=true)
Sets a flag in this Node that indicates the node was created for something in an index file.
Definition node.h:184
virtual bool isAbstract() const
Returns true if the ClassNode or QmlTypeNode is marked abstract.
Definition node.h:137
SharedCommentNode * sharedCommentNode()
Definition node.h:252
ComparisonCategory comparisonCategory() const
Definition node.h:187
bool isQmlType() const
Returns true if the node type is QmlType or QmlValueType.
Definition node.h:123
bool isHeader() const
Returns true if the node type is HeaderFile.
Definition node.h:106
NodeType nodeType() const override
Returns this node's type.
Definition node.h:82
Genus genus() const override
Returns this node's Genus.
Definition node.h:85
virtual bool isPageNode() const
Returns true if this node represents something that generates a documentation page.
Definition node.h:150
bool isEnumType() const
Returns true if the node type is Enum.
Definition node.h:94
virtual bool isTextPageNode() const
Returns true if the node is a PageNode but not an Aggregate.
Definition node.h:155
Aggregate * parent() const
Returns the node's parent pointer, that is, the aggregate under which the node is documented.
Definition node.h:211
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:909
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:138
virtual void setRelatedNonmember(bool b)
Sets a flag in the node indicating whether this node is a related nonmember of something.
Definition node.h:188
void setComparisonCategory(const ComparisonCategory &category)
Definition node.h:186
bool isProxyNode() const
Returns true if the node type is Proxy.
Definition node.h:115
ThreadSafeness threadSafeness() const
Returns the thread safeness value for whatever this node represents.
Definition node.cpp:845
virtual Tree * tree() const
Returns a pointer to the Tree this node is in.
Definition node.cpp:899
const Location & declLocation() const
Returns the Location where this node's declaration was seen.
Definition node.h:233
NodeContext createContext() const
Definition node.cpp:175
void setDoc(const Doc &doc, bool replace=false)
Sets this Node's Doc to doc.
Definition node.cpp:560
bool isModule() const
Returns true if the node type is Module.
Definition node.h:108
virtual bool isPropertyGroup() const
Returns true if the node is a SharedCommentNode for documenting multiple C++ properties or multiple Q...
Definition node.h:153
ThreadSafeness
An unsigned char that specifies the degree of thread-safeness of the element.
Definition node.h:58
@ ThreadSafe
Definition node.h:62
@ NonReentrant
Definition node.h:60
@ UnspecifiedSafeness
Definition node.h:59
@ Reentrant
Definition node.h:61
bool isSharingComment() const
This function returns true if the node is sharing a comment with other nodes.
Definition node.h:250
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:192
bool hasDoc() const
Returns true if this node is documented, or it represents a documented node read from the index ('had...
Definition node.cpp:942
bool isRelatedNonmember() const
Returns true if this is a related nonmember of something.
Definition node.h:124
virtual bool isClassNode() const
Returns true if this is an instance of ClassNode.
Definition node.h:145
bool isCppNode() const
Returns true if this node's Genus value is CPP.
Definition node.h:92
virtual void setStatus(Status t)
Sets the node's status to t.
Definition node.cpp:574
virtual bool isCollectionNode() const
Returns true if this is an instance of CollectionNode.
Definition node.h:146
void setThreadSafeness(ThreadSafeness t)
Sets the node's thread safeness to t.
Definition node.h:176
bool isQmlModule() const
Returns true if the node type is QmlModule.
Definition node.h:120
@ SignatureReturnType
Definition node.h:68
bool isExample() const
Returns true if the node type is Example.
Definition node.h:99
bool isIndexNode() const
Returns true if this node was created from something in an index file.
Definition node.h:107
static bool nodeLessThan(const Node *first, const Node *second)
Returns true if the node n1 is less than node n2.
Definition node.cpp:79
const Parameter & at(int i) const
Definition parameters.h:36
int count() const
Definition parameters.h:34
A record of a linkable target within the documentation.
Definition tree.h:27
TargetType
A type of a linkable target record.
Definition tree.h:29
@ Keyword
Definition tree.h:29
@ Target
Definition tree.h:29
@ Contents
Definition tree.h:29