34#include <QtCore/qdebug.h>
35#include <QtCore/qdir.h>
36#include <QtCore/qregularexpression.h>
38#ifndef QT_BOOTSTRAPPED
39# include "QtCore/qurl.h"
44using namespace std::literals::string_literals;
48using namespace Qt::StringLiterals;
51QMap<QString, QMap<QString, QString>>
Generator::s_fmtLeftMaps;
52QMap<QString, QMap<QString, QString>>
Generator::s_fmtRightMaps;
53QList<Generator *>
Generator::s_generators;
59QHash<QString, QString>
Generator::s_outputPrefixes;
60QHash<QString, QString>
Generator::s_outputSuffixes;
64bool Generator::s_redirectDocumentationToDevNull =
false;
68static QRegularExpression
tag(
"</?@[^>]*>");
75
76
77
78
79
84 s_generators.prepend(
this);
88
89
90
93 s_generators.removeAll(
this);
97 const Node *actualNode)
99 if (actualNode ==
nullptr)
100 actualNode = apparentNode;
102 addNodeLink(text, actualNode, apparentNode->plainFullName(relative));
106 const Node *actualNode)
108 if (actualNode ==
nullptr)
109 actualNode = apparentNode;
111 addNodeLink(text, actualNode, fullName);
115
116
117
118
125
126
127
128
134 for (
const auto &node : nodes) {
135 text << Atom(Atom::ListItemNumber, QString::number(++count));
136 text << Atom(Atom::ListItemLeft, QString(
"bullet"));
137 appendSignature(text, node);
138 text << Atom(Atom::ListItemRight, QString(
"bullet"));
146 QMap<QString, Text> classMap;
147 for (
const auto &relatedClass : rc) {
148 ClassNode *rcn = relatedClass.m_node;
149 if (rcn && rcn->isInAPI()) {
151 appendFullName(className, rcn, cn);
152 classMap[className.toString().toLower()] = className;
157 const QStringList classNames = classMap.keys();
158 for (
const auto &className : classNames) {
159 text << classMap[className];
160 text << Utilities::comma(index++, classNames.size());
168 QMap<QString, Text> classMap;
170 QStringList typeNames(knownTypes);
171 for (
const auto sub : subs)
172 typeNames << sub->name();
174 for (
const auto sub : subs) {
176 appendFullName(full_name, sub, base);
178 if (typeNames.count(sub->name()) > 1)
179 full_name << Atom(Atom::String,
" (%1)"_L1.arg(sub->logicalModuleName()));
180 classMap[full_name.toString().toLower()] = full_name;
184 const auto &names = classMap.keys();
185 for (
const auto &name : names)
186 text << classMap[name] << Utilities::comma(index++, names.size());
191
192
193
194
195
196
197
205 if (s_outFileNames.contains(fileName) && !node->isAttribution() && !fileName.contains(
"-attribution-"_L1))
206 node->location().warning(
"Already generated %1 for this project"_L1.arg(fileName));
208 QString path = outputDir() + QLatin1Char(
'/') + fileName;
210 const auto &outPath = s_redirectDocumentationToDevNull ? QStringLiteral(
"/dev/null") : path;
211 auto outFile =
new QFile(outPath);
213 if (!s_redirectDocumentationToDevNull && outFile->exists()) {
214 const QString warningText {
"Output file already exists, overwriting %1"_L1.arg(outFile->fileName())};
215 if (qEnvironmentVariableIsSet(
"QDOC_ALL_OVERWRITES_ARE_WARNINGS"))
218 qCDebug(lcQdoc) << qUtf8Printable(warningText);
221 if (!outFile->open(QFile::WriteOnly | QFile::Text)) {
223 QStringLiteral(
"Cannot open output file '%1'").arg(outFile->fileName()));
226 qCDebug(lcQdoc,
"Writing: %s", qPrintable(path));
227 s_outFileNames << fileName;
228 s_trademarks.clear();
233
234
235
236
240 QFile *outFile = openSubPageFile(
static_cast<
const PageNode*>(node), fileName);
241 auto *out =
new QTextStream(outFile);
242 outStreamStack.push(out);
246
247
248
249
252 outStreamStack.top()->flush();
253 delete outStreamStack.top()->device();
254 delete outStreamStack.pop();
263 return node->fileNameBase();
265 QString base{node->name()};
266 if (base.endsWith(
".html"))
267 base.truncate(base.size() - 5);
271 base.append(
"-qmlmodule");
273 base.append(
"-module");
274 base.append(outputSuffix(node));
277 base.prepend(
"%1-"_L1.arg(s_project.toLower()));
278 base.append(
"-example");
282
283
284
285
286
287
288
289
291 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
293 if (InclusionFilter::isIncluded(policy, context))
294 base.prepend(
"%1%2-"_L1.arg(node->logicalModuleName(), outputSuffix(node)));
298 base.append(
"-%1-proxy"_L1.arg(node->tree()->physicalModuleName()));
301 const Node *p = node;
303 const Node *pp = p->parent();
304 base.prepend(p->name());
305 if (pp ==
nullptr || pp->name().isEmpty() || pp->isTextPageNode())
307 base.prepend(
'-'_L1);
310 if (node->isNamespace() && !node->name().isEmpty()) {
311 const auto *ns =
static_cast<
const NamespaceNode *>(node);
312 if (!ns->isDocumentedHere()) {
313 base.append(QLatin1String(
"-sub-"));
314 base.append(ns->tree()->camelCaseModuleName());
317 base.append(outputSuffix(node));
320 base.prepend(outputPrefix(node));
321 QString canonicalName{ Utilities::asAsciiPrintable(base) };
323 n->setFileNameBase(canonicalName);
324 return canonicalName;
328
329
330
331
332
336 link.prepend(s_project.toLower() + QLatin1Char(
'-'));
338 QString canonicalName{ Utilities::asAsciiPrintable(link) };
339 canonicalName.append(QLatin1Char(
'.'));
340 canonicalName.append(fileExt.isEmpty() ? fileExtension() : fileExt);
341 return canonicalName;
345
346
347
351 if (relative->files().contains(fileName))
352 suffix = QLatin1String(
" Example File");
353 else if (relative->images().contains(fileName))
354 suffix = QLatin1String(
" Image File");
358 return fileName.mid(fileName.lastIndexOf(QLatin1Char(
'/')) + 1) + suffix;
362
363
364
365
366
369 if (!node->url().isEmpty())
376 QFileInfo originalName(node->name());
377 QString suffix = originalName.suffix();
378 if (!suffix.isEmpty() && suffix !=
"html") {
380 QString name = fileBase(node);
381 return name + QLatin1Char(
'.') + suffix;
385 QString name = fileBase(node) + QLatin1Char(
'.');
386 return name + (extension.isNull() ? fileExtension() : extension);
390
391
392
393
394
395
396
397
398QString
Generator::cleanRef(
const QString &ref,
bool xmlCompliant)
409 clean.reserve(ref.size() + 20);
410 const QChar c = ref[0];
411 const uint u = c.unicode();
413 if ((u >=
'a' && u <=
'z') || (u >=
'A' && u <=
'Z') || (!xmlCompliant && u >=
'0' && u <=
'9')) {
415 }
else if (xmlCompliant && u >=
'0' && u <=
'9') {
416 clean += QLatin1Char(
'A') + c;
417 }
else if (u ==
'~') {
419 }
else if (u ==
'_') {
420 clean +=
"underscore.";
422 clean += QLatin1Char(
'A');
425 for (
int i = 1; i < ref.size(); i++) {
426 const QChar c = ref[i];
427 const uint u = c.unicode();
428 if ((u >=
'a' && u <=
'z') || (u >=
'A' && u <=
'Z') || (u >=
'0' && u <=
'9') || u ==
'-'
429 || u ==
'_' || (xmlCompliant && u ==
':') || u ==
'.') {
431 }
else if (c.isSpace()) {
432 clean += QLatin1Char(
'-');
433 }
else if (u ==
'!') {
435 }
else if (u ==
'&') {
437 }
else if (u ==
'<') {
439 }
else if (u ==
'=') {
441 }
else if (u ==
'>') {
443 }
else if (u ==
'#') {
444 clean += QLatin1Char(
'#');
446 clean += QLatin1Char(
'-');
447 clean += QString::number(
static_cast<
int>(u), 16);
455 return s_fmtLeftMaps[format()];
460 return s_fmtRightMaps[format()];
464
465
470 if (!node->url().isEmpty())
478
479
480
481 if (!fileBase(node).isEmpty())
482 parentName = fileBase(node) + QLatin1Char(
'.') + currentGenerator()->fileExtension();
486 return fileBase(node) + QLatin1Char(
'.') + currentGenerator()->fileExtension();
488 parentName = fileBase(node) + QLatin1Char(
'.') + currentGenerator()->fileExtension();
489 }
else if (fileBase(node).isEmpty())
492 Node *parentNode =
nullptr;
496 if (!node->parent()->isNamespace() || !node->parent()->name().isEmpty())
497 parentName = fullDocumentLocation(node->parent());
501 case NodeType::Class:
502 case NodeType::Struct:
503 case NodeType::Union:
504 case NodeType::Namespace:
505 case NodeType::Proxy:
506 parentName = fileBase(node) + QLatin1Char(
'.') + currentGenerator()->fileExtension();
509 const auto *fn =
static_cast<
const FunctionNode *>(node);
512 anchorRef = QLatin1Char(
'#') + node->name() +
"-signal";
515 anchorRef = QLatin1Char(
'#') + node->name() +
"-signal-handler";
518 anchorRef = QLatin1Char(
'#') + node->name() +
"-method";
522 anchorRef =
"#dtor." + fn->name().mid(1);
523 else if (
const auto *p = fn->primaryAssociatedProperty(); p && fn->doc().isEmpty())
524 return fullDocumentLocation(p);
525 else if (fn->overloadNumber() > 0)
526 anchorRef = QLatin1Char(
'#') + cleanRef(fn->name()) + QLatin1Char(
'-')
527 + QString::number(fn->overloadNumber());
529 anchorRef = QLatin1Char(
'#') + cleanRef(fn->name());
535
536
537
538
541 anchorRef = QLatin1Char(
'#') + node->name() +
"-enum";
544 const auto *tdef =
static_cast<
const TypedefNode *>(node);
545 if (tdef->associatedEnum())
546 return fullDocumentLocation(tdef->associatedEnum());
549 anchorRef = QLatin1Char(
'#') + node->name() +
"-typedef";
552 anchorRef = QLatin1Char(
'#') + node->name() +
"-prop";
560 anchorRef = QLatin1Char(
'#') + node->name() +
"-attached-prop";
562 anchorRef = QLatin1Char(
'#') + node->name() +
"-prop";
565 anchorRef = QLatin1Char(
'#') + node->name() +
"-var";
573 parentName = fileBase(node);
574 parentName.replace(QLatin1Char(
'/'), QLatin1Char(
'-'))
575 .replace(QLatin1Char(
'.'), QLatin1Char(
'-'));
588 return parentName.toLower() + anchorRef;
593 QList<Text> alsoList = node
->doc().alsoList();
594 supplementAlsoList(node, alsoList);
596 if (!alsoList.isEmpty()) {
603 for (
const auto &also : std::as_const(alsoList)) {
605 QString link = also.firstAtom()->string();
606 if (!used.contains(link)) {
613 for (
const auto &also : std::as_const(items))
614 text << also << Utilities::separator(i++, items.size());
622 bool generate,
int &numAtoms)
624 while (atom !=
nullptr) {
626 int numAtoms0 = numAtoms;
627 bool rightFormat = canHandleFormat(atom->string());
642 if (generate && numAtoms0 == numAtoms) {
643 relative->location().warning(QStringLiteral(
"Output format %1 not handled %2")
644 .arg(format(), outFileName()));
645 Atom unhandledFormatAtom(Atom::UnhandledFormat, format());
655 n += generateAtom(atom, relative, marker);
667
668
669
675
676
677
681 text <<
"Destroys the instance of ";
682 text << fn
->parent()->name() <<
".";
684 text <<
" The destructor is virtual.";
690 text <<
"Default constructs an instance of ";
691 text << fn
->parent()->name() <<
".";
697 text <<
"Copy constructor.";
703 text <<
"Move-copy constructor.";
709 text <<
"Copy-assignment operator.";
715 text <<
"Move-assignment operator.";
720 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
723 node
->location().warning(QStringLiteral(
"No documentation for '%1'")
724 .arg(node->plainSignature()));
728 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
732 QStringLiteral(
"No documentation for '%1'").arg(node->plainSignature()));
737 generateReimplementsClause(fn, marker);
763 const auto *enume =
static_cast<
const EnumNode *>(node);
765 QSet<QString> definedItems;
766 const QList<EnumItem> &items = enume->items();
767 for (
const auto &item : items)
768 definedItems.insert(item.name());
770 const auto &documentedItemList = enume
->doc().enumItemNames();
771 QSet<QString> documentedItems(documentedItemList.cbegin(), documentedItemList.cend());
772 const QSet<QString> allItems = definedItems + documentedItems;
773 if (allItems.size() > definedItems.size()
774 || allItems.size() > documentedItems.size()) {
775 for (
const auto &it : allItems) {
776 if (!definedItems.contains(it)) {
778 QString best = nearestName(it, definedItems);
779 if (!best.isEmpty() && !documentedItems.contains(best))
780 details = QStringLiteral(
"Maybe you meant '%1'?").arg(best);
782 node->doc().location().warning(
783 QStringLiteral(
"No such enum item '%1' in %2")
784 .arg(it, node->plainFullName()),
786 }
else if (!documentedItems.contains(it)) {
787 node->doc().location().warning(
788 QStringLiteral(
"Undocumented enum item '%1' in %2")
789 .arg(it, node->plainFullName()));
795 const QSet<QString> documentedNames = fn
->doc().parameterNames();
796 if (declaredNames != documentedNames) {
797 for (
const auto &name : declaredNames) {
798 if (!documentedNames.contains(name)) {
799 if (fn->isActive() || fn->isPreliminary()) {
802 if (!fn->isMarkedReimp() && !fn->isOverload() &&
803 !(fn->isSomeCtor() && fn->hasOverloads())) {
804 fn->doc().location().warning(
805 QStringLiteral(
"Undocumented parameter '%1' in %2")
806 .arg(name, node->plainFullName()));
811 for (
const auto &name : documentedNames) {
812 if (!declaredNames.contains(name) && CodeParser::isWorthWarningAbout(fn->doc())) {
813 QString best = nearestName(name, declaredNames);
816 details = QStringLiteral(
"Maybe you meant '%1'?").arg(best);
817 fn->doc().location().warning(QStringLiteral(
"No such parameter '%1' in %2")
818 .arg(name, fn->plainFullName()),
824
825
826
827
830 if (!fn
->doc().body().contains(
"return"))
832 QStringLiteral(
"Undocumented return value "
833 "(hint: use 'return' or 'returns' in the text"));
836 if (
auto *qpn =
static_cast<
const QmlPropertyNode *>(node); !qpn->validateDataType())
837 qpn->doc().location().warning(
"Invalid QML property type: %1"_L1.arg(qpn->dataType()));
845
846
847
848
849
855 const auto *en =
static_cast<
const ExampleNode *>(node);
858 if (exampleUrl.isEmpty()) {
864 generateLinkToExample(en, marker, exampleUrl);
869
870
871
872
873
874
876 const QString &baseUrl)
878 QString exampleUrl(baseUrl);
880#ifndef QT_BOOTSTRAPPED
881 link = QUrl(exampleUrl).host();
885 link.prepend(
"Example project");
887 const QLatin1Char separator(
'/');
888 const QLatin1Char placeholder(
'\1');
889 if (!exampleUrl.contains(placeholder)) {
890 if (!exampleUrl.endsWith(separator))
891 exampleUrl += separator;
892 exampleUrl += placeholder;
899 pathRoot = metaTagMap->value(QLatin1String(
"installpath"));
900 if (pathRoot.isEmpty())
902 QStringList path = QStringList() << pathRoot << en->name();
903 path.removeAll(QString());
907 <<
Atom(
Atom::Link, exampleUrl.replace(placeholder, path.join(separator)))
918 const QString prefix(
"/images/used-in-examples");
924 s_outFileNames << prefix.mid(1) +
"/" + resolved_file.get_query();
928 QString imgOutDir = s_outDir + prefix +
"/" + QFileInfo{resolved_file.get_query()}.path();
929 if (!dirInfo.mkpath(imgOutDir))
930 en
->location().fatal(QStringLiteral(
"Cannot create output directory '%1'").arg(imgOutDir));
931 Config::copyFile(en->location(), resolved_file.get_path(), QFileInfo{resolved_file.get_query()}.fileName(), imgOutDir);
946
947
948
949
950
951
961 paths = en->images();
968 std::sort(paths.begin(), paths.end(), Generator::comparePaths);
973 for (
const auto &path : std::as_const(paths)) {
974 auto maybe_resolved_file{file_resolver.resolve(path)};
975 if (!maybe_resolved_file) {
977 QString details = std::transform_reduce(
978 file_resolver.get_search_directories().cbegin(),
979 file_resolver.get_search_directories().cend(),
980 u"Searched directories:"_s,
982 [](
const DirectoryPath &directory_path) -> QString {
return u' ' + directory_path.value(); }
985 en->location().warning(u"(Generator)Cannot find file to quote from: %1"_s.arg(path), details);
990 const auto &file{*maybe_resolved_file};
992 addImageToCopy(en, file);
994 generateExampleFilePage(en, file, marker);
997 text << Atom(Atom::ListItemNumber, openedList.numberString())
998 << Atom(Atom::ListItemLeft, openedList.styleString()) << Atom::ParaLeft
999 << Atom(atomType, file.get_query()) << Atom(Atom::FormattingLeft,
ATOM_FORMATTING_LINK) << file.get_query()
1001 << Atom(Atom::ListItemRight, openedList.styleString());
1004 if (!paths.isEmpty())
1005 generateText(text, en, marker);
1009
1010
1013 if (!node->url().isNull())
1017 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
1025
1026
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1053 beginSubPage(node, fileName(node));
1060 QString name = cn->name().toLower();
1061 name.replace(QChar(
' '), QString(
"-"));
1063 cn->tree()->physicalModuleName() +
"-" + name +
"." + fileExtension();
1064 beginSubPage(node, filename);
1069 beginSubPage(node, fileName(node));
1075 beginSubPage(node, fileName(node));
1079 beginSubPage(node, fileName(node));
1084 beginSubPage(node, fileName(node));
1092 auto *aggregate =
static_cast<
Aggregate *>(node);
1094 for (
auto *child : children) {
1095 if (child->isPageNode() && !child->isPrivate()) {
1096 generateDocumentation(child);
1097 }
else if (!node->parent() && child->isInAPI() && !child->isRelatedNonmember()) {
1099 child->location().warning(u"No documentation generated for %1 '%2' in global scope."_s
1100 .arg(typeString(child), child->name()),
1101 u"Maybe you forgot to use the '\\relates' command?"_s);
1102 child->setStatus(Node::DontDocument);
1103 }
else if (child->isQmlModule() && !child->wasSeen()) {
1105 auto *qmlModule =
static_cast<CollectionNode *>(child);
1106 for (
const auto *member : qmlModule->members()) {
1107 member->location().warning(
1108 u"Undocumented QML module '%1' referred by type '%2' or its members"_s
1109 .arg(qmlModule->name(), member->name()),
1110 u"Maybe you forgot to document '\\qmlmodule %1'?"_s
1111 .arg(qmlModule->name()));
1113 }
else if (child->isQmlType() && !child->hasDoc()) {
1115 auto *qmlType =
static_cast<QmlTypeNode *>(child);
1116 if (
auto qmid = qmlType->logicalModuleName(); !qmid.isEmpty())
1117 qmlType->location().warning(u"No such type '%1' in QML module '%2'"_s
1118 .arg(qmlType->name(), qmid));
1130 const FunctionNode *overrides = cn->findOverriddenFunction(fn);
1136 overrides->parent()->name()
1137 +
"::" + overrides->signature(Node::SignaturePlain);
1140 generateText(text, fn, marker);
1142 fn
->doc().location().warning(
1143 QStringLiteral(
"Illegal \\reimp; no documented virtual function for %1")
1144 .arg(overrides->plainSignature()));
1148 const PropertyNode *sameName = cn->findOverriddenProperty(fn);
1149 if (sameName && sameName
->hasDoc()) {
1151 text <<
Atom::ParaLeft <<
"Reimplements an access function for property: ";
1152 QString fullName = sameName->parent()->name() +
"::" + sameName->name();
1155 generateText(text, fn, marker);
1161 QStringList since = node->since().split(QLatin1Char(
' '));
1164 if (since.size() == 1) {
1166 return productName.isEmpty() ? node->since() : productName +
" " + since[0];
1170 return node->since();
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1195 status = metaMap->value(
"status");
1196 if (!status.isEmpty())
1199 const auto &since = node->deprecatedSince();
1201 status = u"Deprecated"_s;
1202 if (!since.isEmpty())
1203 status +=
" since %1"_L1.arg(since);
1204 }
else if (!since.isEmpty()) {
1205 status =
"Until %1"_L1.arg(since);
1207 status = u"Preliminary"_s;
1209 status = collection->state();
1212 return status.isEmpty() ?
std::nullopt :
std::optional(status);
1217 if (!node->since().isEmpty()) {
1219 text << Atom::ParaLeft <<
"This " << typeString(node) <<
" was introduced in "
1220 << formatSince(node) <<
"." << Atom::ParaRight;
1226 std::vector<
const Node*> nodes;
1229 nodes.reserve(shared_node->collective().size());
1230 nodes.insert(nodes.begin(), shared_node->collective().begin(), shared_node->collective().end());
1231 }
else nodes.push_back(node);
1233 std::size_t counter{1};
1234 for (
const Node* node : nodes) {
1235 if (node->isFunction(Genus::CPP)) {
1236 if (
const auto &exception_info =
static_cast<
const FunctionNode*>(node)->getNoexcept(); exception_info && !(*exception_info).isEmpty()) {
1238 text << Atom::NoteLeft
1239 << (nodes.size() > 1 ? QString::fromStdString(
" ("s + std::to_string(counter) +
")"s) : QString::fromStdString(
"This ") + typeString(node))
1240 <<
" is noexcept when "
1241 << Atom(Atom::C, marker->markedUpCode(*exception_info,
nullptr, Location()))
1242 <<
" is " << Atom(Atom::C,
"true") <<
"."
1244 generateText(text, node, marker);
1260 const QString &state =
static_cast<
const CollectionNode*>(node)->state();
1261 if (!state.isEmpty()) {
1262 text << Atom::ParaLeft <<
"This " << typeString(node) <<
" is in "
1269 if (
const auto &version = node->deprecatedSince(); !version.isEmpty()) {
1270 text << Atom::ParaLeft <<
"This " << typeString(node)
1271 <<
" is scheduled for deprecation in version "
1272 << version <<
"." << Atom::ParaRight;
1275 case Node::Preliminary:
1277 << typeString(node) <<
" is under development and is subject to change."
1284 text <<
"This " << typeString(node) <<
" is deprecated";
1285 if (
const QString &version = node->deprecatedSince(); !version.isEmpty()) {
1287 if (node
->isQmlNode() && !node->logicalModuleName().isEmpty())
1288 text << node->logicalModuleName() <<
" ";
1292 text <<
". We strongly advise against using it in new code.";
1305
1306
1307
1311 Q_ASSERT(node && !node->name().isEmpty());
1313 text << Atom(Atom::DivLeft,
1314 "class=\"admonition %1\""_L1.arg(prefix == AdmonitionPrefix::Note ? u"note"_s : u"auto"_s));
1329 text <<
"This function can be invoked via the meta-object system and from QML. See "
1335 text <<
"This is a private signal. It can be used in signal connections "
1336 "but cannot be emitted by the user.";
1340 QString handler(node->name());
1341 qsizetype prefixLocation = handler.lastIndexOf(
'.', -2) + 1;
1342 handler[prefixLocation] = handler[prefixLocation].toTitleCase();
1343 handler.insert(prefixLocation, QLatin1String(
"on"));
1344 text <<
"The corresponding handler is "
1353 const auto *fn =
static_cast<
const FunctionNode *>(node);
1354 auto nodes = fn->associatedProperties();
1355 if (nodes.isEmpty())
1360 QMap<PropertyNode::FunctionRole, QList<
const PropertyNode *>> roleGroups;
1361 for (
const auto *n : std::as_const(nodes)) {
1362 const auto *pn =
static_cast<
const PropertyNode *>(n);
1363 if (pn->isInAPI()) {
1364 PropertyNode::FunctionRole role = pn->role(fn);
1365 roleGroups[role].append(pn);
1369 if (roleGroups.isEmpty())
1380 for (
auto role : roleOrder) {
1381 const auto it = roleGroups.constFind(role);
1382 if (it == roleGroups.cend())
1385 const auto &properties = it.value();
1389 case PropertyNode::FunctionRole::Getter:
1390 msg = u"Getter function"_s;
1392 case PropertyNode::FunctionRole::Setter:
1393 msg = u"Setter function"_s;
1395 case PropertyNode::FunctionRole::Resetter:
1396 msg = u"Resetter function"_s;
1398 case PropertyNode::FunctionRole::Notifier:
1399 msg = u"Notifier signal"_s;
1401 case PropertyNode::FunctionRole::Bindable:
1402 msg = u"Bindable function"_s;
1408 if (properties.size() == 1) {
1409 const auto *pn = properties.first();
1410 text << msg << u" for property "_s << Atom(Atom::Link, pn->name())
1414 text << msg << u" for properties "_s;
1415 for (qsizetype i = 0; i < properties.size(); ++i) {
1416 const auto *pn = properties.at(i);
1420 << Utilities::separator(i, properties.size());
1429 text <<
"This property supports "
1433 text <<
" bindings.";
1438 const auto *func =
static_cast<
const FunctionNode *>(node);
1441 QString functionType = func->isSignal() ?
"signal" :
"slot";
1442 const QString &configKey = func
->isSignal() ?
"overloadedsignalstarget" :
"overloadedslotstarget";
1443 const QString &defaultTarget = func
->isSignal() ?
"connecting-overloaded-signals" :
"connecting-overloaded-slots";
1444 const QString &linkTarget = Config::instance().get(configKey).asString(defaultTarget);
1446 text <<
"This " << functionType <<
" is overloaded. ";
1448 QString snippet = generateOverloadSnippet(func);
1449 if (!snippet.isEmpty()) {
1450 text <<
"To connect to this " << functionType <<
":\n\n"
1454 text <<
"For more examples and approaches, see "
1457 <<
"connecting to overloaded " << functionType <<
"s"
1460 const auto &args = node
->doc().overloadList();
1461 if (args.first().first.isEmpty()) {
1462 text <<
"This is an overloaded function.";
1464 QString target = args.first().first;
1467 if (!target.contains(
"::")) {
1470 target = parent->name() +
"::" + target;
1488
1489
1490
1491
1494 bool result =
false;
1505
1506
1507
1508
1509
1510
1511
1512
1516 bool result =
false;
1519 for (
auto child : children) {
1520 if (!child->isDeprecated()) {
1521 switch (child->threadSafeness()) {
1522 case Node::Reentrant:
1523 reentrant.append(child);
1524 if (ts == Node::ThreadSafe)
1527 case Node::ThreadSafe:
1528 threadsafe.append(child);
1529 if (ts == Node::Reentrant)
1532 case Node::NonReentrant:
1533 nonreentrant.append(child);
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1565 if (atom->count() > 1) {
1566 if (s_trademarks.contains(atom->string(1)))
1568 s_trademarks << atom->string(1);
1581
1582
1583
1586 Text text, rlink, tlink;
1591 bool exceptions =
false;
1602 case Node::NonReentrant:
1605 << typeString(node) <<
" is not " << rlink <<
"." << Atom::ParaRight;
1611 exceptions = hasExceptions(node, reentrant, threadsafe, nonreentrant);
1612 text <<
"All functions in this " << typeString(node) <<
" are ";
1621 text <<
" with the following exceptions:";
1623 text <<
"This " << typeString(node) <<
" is ";
1640 if (!nonreentrant.isEmpty()) {
1642 text <<
"These functions are not " << rlink <<
":" <<
Atom::ParaRight;
1643 signatureList(nonreentrant, node, marker);
1645 if (!threadsafe.isEmpty()) {
1648 text <<
"These functions are also " << tlink <<
":" <<
Atom::ParaRight;
1650 signatureList(threadsafe, node, marker);
1653 if (!reentrant.isEmpty()) {
1655 text <<
"These functions are only " << rlink <<
":" <<
Atom::ParaRight;
1656 signatureList(reentrant, node, marker);
1658 if (!nonreentrant.isEmpty()) {
1661 text <<
"These functions are not " << rlink <<
":" <<
Atom::ParaRight;
1662 signatureList(nonreentrant, node, marker);
1669
1670
1671
1672
1673
1677 if (category == ComparisonCategory::None)
1681 text << Atom::ParaLeft <<
"This %1 is "_L1.arg(typeString(node))
1683 << QString::fromStdString(comparisonCategoryAsString(category))
1684 << ((category == ComparisonCategory::Equality) ?
"-"_L1 :
"ly "_L1)
1685 << Atom(Atom::String,
"comparable"_L1)
1687 <<
"."_L1 << Atom::ParaRight;
1693
1694
1695
1696
1697
1698
1702 if (!node
->doc().comparesWithMap())
1705 Text relationshipText;
1706 for (
auto [key, description] : node->doc().comparesWithMap()->asKeyValueRange()) {
1707 const QString &category = QString::fromStdString(comparisonCategoryAsString(key));
1709 relationshipText << Atom::ParaLeft <<
"This %1 is "_L1.arg(typeString(node))
1711 << ((key == ComparisonCategory::Equality) ?
"-"_L1 :
"ly "_L1)
1716 const QStringList types{description.firstAtom()->string().split(
';'_L1)};
1717 for (
const auto &name : types)
1718 relationshipText << Atom(Atom::AutoLink, name)
1719 << Utilities::separator(types.indexOf(name), types.size());
1721 relationshipText << Atom(Atom::ParaRight) << description;
1729
1730
1733 s_currentGenerator =
this;
1739 for (
const auto &generator : std::as_const(s_generators)) {
1740 if (generator->format() == format)
1755 while (i < markedCode.size()) {
1756 if (markedCode.at(i) == QLatin1Char(
'\n')) {
1760 for (
int j = 0; j < level; j++)
1761 t += QLatin1Char(
' ');
1765 t += markedCode.at(i++);
1772 Config &config = Config::instance();
1773 s_outputFormats = config.getOutputFormats();
1776 for (
auto &g : s_generators) {
1777 if (s_outputFormats.contains(g->format())) {
1778 s_currentGenerator = g;
1779 g->initializeGenerator();
1784 for (
const auto &n : configFormatting) {
1786 const auto &formattingDotNames = config.subVars(formattingDotName);
1787 for (
const auto &f : formattingDotNames) {
1788 const auto &configVar = config.get(formattingDotName + Config::dot + f);
1789 QString def{configVar.asString()};
1790 if (!def.isEmpty()) {
1791 int numParams = Config::numParams(def);
1792 int numOccs = def.count(
"\1");
1793 if (numParams != 1) {
1794 configVar.location().warning(QStringLiteral(
"Formatting '%1' must "
1796 "parameter (found %2)")
1797 .arg(n, numParams));
1798 }
else if (numOccs > 1) {
1799 configVar.location().fatal(QStringLiteral(
"Formatting '%1' must "
1800 "contain exactly one "
1801 "occurrence of '\\1' "
1805 int paramPos = def.indexOf(
"\1");
1806 s_fmtLeftMaps[f].insert(n, def.left(paramPos));
1807 s_fmtRightMaps[f].insert(n, def.mid(paramPos + 1));
1814 s_outDir = config.getOutputDir();
1815 s_outSubdir = s_outDir.mid(s_outDir.lastIndexOf(
'/') + 1);
1817 s_outputPrefixes.clear();
1819 if (!items.isEmpty()) {
1820 for (
const auto &prefix : items)
1821 s_outputPrefixes[prefix] =
1824 if (!items.contains(u"QML"_s))
1825 s_outputPrefixes[u"QML"_s] = u"qml-"_s;
1827 s_outputSuffixes.clear();
1830 + Config::dot + suffix).asString();
1837
1838
1839
1840void Generator::copyTemplateFiles(
const QString &configVar,
const QString &subDir)
1857 Config &config = Config::instance();
1858 QStringList files = config.getCanonicalPathList(configVar,
Config::Validate);
1859 const auto &loc = config.get(configVar)
.location();
1860 if (!files.isEmpty()) {
1873 QString templateDir = s_outDir + QLatin1Char(
'/') + subDir;
1874 if (!dirInfo.exists(templateDir) && !dirInfo.mkdir(templateDir)) {
1876 loc.fatal(QStringLiteral(
"Cannot create %1 directory '%2'").arg(subDir, templateDir));
1878 for (
const auto &file : files) {
1879 if (!file.isEmpty())
1880 Config::copyFile(loc, file, file, templateDir);
1887
1888
1889
1890
1893 Config &config = Config::instance();
1894 s_outFileNames.clear();
1895 s_useOutputSubdirs =
true;
1896 if (config.get(format() + Config::dot +
"nosubdirs").asBool())
1899 if (s_outputFormats.isEmpty())
1902 s_outDir = config.getOutputDir(format());
1903 if (s_outDir.isEmpty()) {
1904 Location().fatal(QStringLiteral(
"No output directory specified in "
1905 "configuration file or on the command line"));
1907 s_outSubdir = s_outDir.mid(s_outDir.lastIndexOf(
'/') + 1);
1910 QDir outputDir(s_outDir);
1911 if (outputDir.exists()) {
1913 if (!outputDir.isEmpty())
1914 Location().error(QStringLiteral(
"Output directory '%1' exists but is not empty")
1917 }
else if (!outputDir.mkpath(QStringLiteral(
"."))) {
1918 Location().fatal(QStringLiteral(
"Cannot create output directory '%1'").arg(s_outDir));
1925 const QLatin1String imagesDir(
"images");
1926 if (!outputDir.exists(imagesDir) && !outputDir.mkdir(imagesDir))
1927 Location().fatal(QStringLiteral(
"Cannot create images directory '%1'").arg(outputDir.filePath(imagesDir)));
1930 copyTemplateFiles(format() + Config::dot +
CONFIG_SCRIPTS,
"scripts");
1941
1942
1943
1955
1956
1957
1958
1961 return *outStreamStack.top();
1966 return QFileInfo(
static_cast<QFile *>(
out().device())->fileName()).fileName();
1975 return s_outputPrefixes[u"QML"_s];
1977 return s_outputPrefixes[u"CPP"_s];
1990 return s_outputSuffixes[u"QML"_s];
1992 return s_outputSuffixes[u"CPP"_s];
2002 QStringView *contents, QStringView *par1)
2005 if (i >= n || src[i] != c)
2010 while (i < n && src[i] == ' ')
2020 if (tag != QStringView(src).mid(i, tag.size())) {
2032 while (i < n && src[i].isLetter())
2034 if (src[i] ==
'=') {
2039 while (i < n && src[i] !=
'"')
2041 *par1 = QStringView(src).mid(j, i - j);
2052 if (i + 4 + tag.size() > n)
2056 if (src[i + 1] !=
'/')
2058 if (src[i + 2] !=
'@')
2060 if (tag != QStringView(src).mid(i + 3, tag.size()))
2062 if (src[i + 3 + tag.size()] !=
'>')
2067 *contents = QStringView(src).mid(j, i - j);
2069 i += tag.size() + 4;
2079 QString t = markedCode;
2080 t.replace(tag, QString());
2081 t.replace(quot, QLatin1String(
"\""));
2082 t.replace(gt, QLatin1String(
">"));
2083 t.replace(lt, QLatin1String(
"<"));
2084 t.replace(amp, QLatin1String(
"&"));
2092 while (atom && atom
->type() != type) {
2100
2101
2111 m_sectionNumber.clear();
2117 const auto fn =
static_cast<
const FunctionNode *>(node);
2119 QString alternateName;
2122 if (fn->name().startsWith(
"set") && fn->name().size() >= 4) {
2123 alternateName = fn->name()[3].toLower();
2124 alternateName += fn->name().mid(4);
2125 alternateFunc = fn
->parent()->findFunctionChild(alternateName, QString());
2127 if (!alternateFunc) {
2128 alternateName =
"is" + fn->name().mid(3);
2129 alternateFunc = fn
->parent()->findFunctionChild(alternateName, QString());
2130 if (!alternateFunc) {
2131 alternateName =
"has" + fn->name().mid(3);
2132 alternateFunc = fn
->parent()->findFunctionChild(alternateName, QString());
2135 }
else if (!fn->name().isEmpty()) {
2136 alternateName =
"set";
2137 alternateName += fn->name()[0].toUpper();
2138 alternateName += fn->name().mid(1);
2139 alternateFunc = fn
->parent()->findFunctionChild(alternateName, QString());
2144 for (i = 0; i < alsoList.size(); ++i) {
2145 if (alsoList.at(i).toString().contains(alternateName))
2149 if (i == alsoList.size()) {
2152 alternateName +=
"()";
2158 alsoList.prepend(also);
2178 const auto *start{body.firstAtom()};
2184 text << body.subText(text
.isEmpty() ? start : start->next(), end);
2199 for (
const auto &generator : std::as_const(s_generators)) {
2200 if (s_outputFormats.contains(generator->format()))
2201 generator->terminateGenerator();
2227 s_generators.clear();
2229 s_fmtLeftMaps.clear();
2230 s_fmtRightMaps.clear();
2237
2238
2239
2240QString
Generator::trimmedTrailing(
const QString &string,
const QString &prefix,
2241 const QString &suffix)
2243 QString trimmed = string;
2244 while (trimmed.size() > 0 && trimmed[trimmed.size() - 1].isSpace())
2245 trimmed.truncate(trimmed.size() - 1);
2247 trimmed.append(suffix);
2248 trimmed.prepend(prefix);
2267 return "documentation";
2274 const auto fn =
static_cast<
const FunctionNode *>(node);
2279 return "signal handler";
2297 const auto &collective =
static_cast<
const SharedCommentNode *>(node)->collective();
2298 return collective.first()->nodeTypeString();
2301 return "documentation";
2307 Location::internalError(QStringLiteral(
"unknown atom type '%1' in %2 generator")
2308 .arg(atom->typeString(), format()));
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2345 if (!cn || (cn->cmakeComponent().isEmpty() && cn->cmakePackage().isEmpty())) {
2349 const QString package =
2350 cn->cmakePackage().isEmpty() ?
"Qt" + QString::number(QT_VERSION_MAJOR) : cn->cmakePackage();
2352 QString findPackageText;
2353 if (cn->cmakeComponent().isEmpty()) {
2354 findPackageText =
"find_package(" + package +
" REQUIRED)";
2356 findPackageText =
"find_package(" + package +
" REQUIRED COMPONENTS " + cn->cmakeComponent() +
")";
2360 if (cn->cmakeTargetItem().isEmpty()) {
2361 if (cn->cmakeComponent().isEmpty()) {
2362 targetText = package +
"::" + package;
2364 targetText = package +
"::" + cn->cmakeComponent();
2367 targetText = cn->cmakeTargetItem();
2370 const QString targetLinkLibrariesText =
"target_link_libraries(mytarget PRIVATE " + targetText +
")";
2371 const QStringList cmakeInfo { findPackageText, targetLinkLibrariesText };
2373 return std::make_pair(findPackageText, targetLinkLibrariesText);
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386void Generator::addNodeLink(
Text &text,
const QString &nodeRef,
const QString &linkText) {
2394
2395
2396
2397
2398
2399
2400
2401
2405 Utilities::stringForNode(node),
2406 linkText.isEmpty() ? node->name() : linkText
2411
2412
2413
2419 QString className = func->parent()->name();
2420 QString functionName = func->name();
2421 QString parameters = func->parameters().generateTypeList();
2423 QString objectName = generateObjectName(className);
2425 QString snippet = QString(
2426 "// Connect using qOverload:\n"
2427 "connect(%1, qOverload<%2>(&%3::%4),\n"
2428 " receiver, &ReceiverClass::slot);\n\n"
2429 "// Or using a lambda:\n"
2430 "connect(%1, qOverload<%2>(&%3::%4),\n"
2431 " this, [](%5) { /* handle %4 */ });")
2432 .arg(objectName, parameters, className, functionName,
2433 func->parameters().generateTypeAndNameList());
2439
2440
2441
2444 QString name = className;
2446 if (name.startsWith(
'Q') && name.length() > 1)
2449 if (!name.isEmpty())
2450 name[0] = name[0].toLower();
#define ATOM_FORMATTING_TELETYPE
#define ATOM_FORMATTING_BOLD
#define ATOM_FORMATTING_TRADEMARK
#define ATOM_FORMATTING_ITALIC
#define ATOM_FORMATTING_LINK
const NodeList & childNodes() const
Returns a const reference to the child list.
The Atom class is the fundamental unit for representing documents internally.
AtomType type() const
Return the type of this atom.
AtomType
\value AnnotatedList \value AutoLink \value BaseName \value BriefLeft \value BriefRight \value C \val...
const Atom * next() const
Return the next atom in the atom list.
The ClassNode represents a C++ class.
A class for holding the members of a collection of doc pages.
bool wasSeen() const override
Returns the seen flag data member of this node if it is a NamespaceNode or a CollectionNode.
const Location & location() const
bool asBool() const
Returns this config variable as a boolean.
The Config class contains the configuration variables for controlling how qdoc produces documentation...
const Location & location() const
Returns the starting location of a qdoc comment.
const Text & body() const
QStringMultiMap * metaTagMap() const
Encapsulate the logic that QDoc uses to find files whose path is provided by the user and that are re...
This node is used to represent any kind of function being documented.
signed short overloadNumber() const
Returns the overload number for this function.
bool isPrivateSignal() const
const Parameters & parameters() const
const QString & overridesThis() const
bool isDeprecated() const override
\reimp
bool hasOverloads() const
Returns true if this function has overloads.
bool isMarkedReimp() const override
Returns true if the FunctionNode is marked as a reimplemented function.
bool isIgnored() const
In some cases, it is ok for a public function to be not documented.
bool hasAssociatedProperties() const
Metaness metaness() const
void appendSignature(Text &text, const Node *node)
Append the signature for the function named in node to text, so that is a link to the documentation f...
virtual void generateCollectionNode(CollectionNode *, CodeMarker *)
virtual void generateProxyPage(Aggregate *, CodeMarker *)
virtual void generateCppReferencePage(Aggregate *, CodeMarker *)
bool generateComparisonCategory(const Node *node, CodeMarker *marker=nullptr)
QMap< QString, QString > & formattingRightMap()
virtual QString typeString(const Node *node)
FileResolver & file_resolver
virtual bool generateText(const Text &text, const Node *relative)
virtual void initializeFormat()
Reads format-specific variables from config, sets output (sub)directories, creates them on the filesy...
virtual void generateDocumentation(Node *node)
Recursive writing of HTML files from the root node.
const Atom * generateAtomList(const Atom *atom, const Node *relative, CodeMarker *marker, bool generate, int &numGeneratedAtoms)
void generateStatus(const Node *node, CodeMarker *marker)
virtual void generateAlsoList(const Node *node, CodeMarker *marker)
void appendFullName(Text &text, const Node *apparentNode, const Node *relative, const Node *actualNode=nullptr)
virtual void generateFileList(const ExampleNode *en, CodeMarker *marker, bool images)
This function is called when the documentation for an example is being formatted.
void generateThreadSafeness(const Node *node, CodeMarker *marker)
Generates text that explains how threadsafe and/or reentrant node is.
Generator(FileResolver &file_resolver)
Constructs the generator base class.
QString linkForExampleFile(const QString &path, const QString &fileExt=QString())
Constructs an href link from an example file name, which is a path to the example file.
void beginSubPage(const Node *node, const QString &fileName)
Creates the file named fileName in the output directory.
bool generateComparisonList(const Node *node)
Generates a list of types that compare to node with the comparison category that applies for the rela...
static bool useOutputSubdirs()
void generateNoexceptNote(const Node *node, CodeMarker *marker)
void unknownAtom(const Atom *atom)
QString generateObjectName(const QString &className)
Generates an appropriate object name for code snippets based on the class name.
virtual bool generateText(const Text &text, const Node *relative, CodeMarker *marker)
Generate the documentation for relative.
int appendSortedQmlNames(Text &text, const Node *base, const QStringList &knownTypes, const QList< Node * > &subs)
void generateLinkToExample(const ExampleNode *en, CodeMarker *marker, const QString &exampleUrl)
Generates an external link to the project folder for example node.
virtual void terminateGenerator()
QString generateOverloadSnippet(const FunctionNode *func)
Generates a contextual code snippet for connecting to an overloaded signal or slot.
static bool matchAhead(const Atom *atom, Atom::AtomType expectedAtomType)
QString fullDocumentLocation(const Node *node)
Returns the full document location.
void addImageToCopy(const ExampleNode *en, const ResolvedFile &resolved_file)
virtual void generateDocs()
Traverses the database recursively to generate all the documentation.
static bool appendTrademark(const Atom *atom)
Returns true if a trademark symbol should be appended to the output as determined by atom.
void generateEnumValuesForQmlReference(const Node *node, CodeMarker *marker)
virtual int skipAtoms(const Atom *atom, Atom::AtomType type) const
bool m_threeColumnEnumValueTable
virtual void generateQmlTypePage(QmlTypeNode *, CodeMarker *)
void signatureList(const QList< Node * > &nodes, const Node *relative, CodeMarker *marker)
Generate a bullet list of function signatures.
void appendFullName(Text &text, const Node *apparentNode, const QString &fullName, const Node *actualNode)
virtual void generateBody(const Node *node, CodeMarker *marker)
Generate the body of the documentation from the qdoc comment found with the entity represented by the...
virtual void generatePageNode(PageNode *, CodeMarker *)
virtual ~Generator()
Destroys the generator after removing it from the list of output generators.
void generateSince(const Node *node, CodeMarker *marker)
QMap< QString, QString > & formattingLeftMap()
int appendSortedNames(Text &text, const ClassNode *classe, const QList< RelatedClass > &classes)
void endSubPage()
Flush the text stream associated with the subpage, and then pop it off the text stream stack and dele...
virtual void generateAddendum(const Node *node, Addendum type, CodeMarker *marker)
QString indent(int level, const QString &markedCode)
QString fileName(const Node *node, const QString &extension=QString()) const
If the node has a URL, return the URL as the file name.
virtual void generateAddendum(const Node *node, Addendum type, CodeMarker *marker, AdmonitionPrefix prefix)
Generates an addendum note of type type for node, using marker as the code marker.
static void resetUseOutputSubdirs()
bool parseArg(const QString &src, const QString &tag, int *pos, int n, QStringView *contents, QStringView *par1=nullptr)
virtual void generateGenericCollectionPage(CollectionNode *, CodeMarker *)
virtual QString fileBase(const Node *node) const
virtual void initializeGenerator()
No-op base implementation.
void initializeTextOutput()
Resets the variables used during text output.
void generateRequiredLinks(const Node *node, CodeMarker *marker)
Generates either a link to the project folder for example node, or a list of links files/images if 'u...
static Generator * currentGenerator()
static bool isIncluded(const InclusionPolicy &policy, const NodeContext &context)
static bool requiresDocumentation(const InclusionPolicy &policy, const NodeContext &context)
The Location class provides a way to mark a location in a file.
Location()
Constructs an empty location.
Interface implemented by Node subclasses that can refer to a C++ enum.
virtual const NativeEnum * nativeEnum() const =0
Encapsulates information about native (C++) enum values.
const EnumNode * enumNode() const
QString styleString() const
OpenedList(ListStyle style)
A PageNode is a Node that generates a documentation page.
bool noAutoList() const
Returns the value of the no auto-list flag.
This class describes one instance of using the Q_PROPERTY macro.
PropertyType propertyType() const
This class provides exclusive access to the qdoc database, which consists of a forrest of trees and a...
static QDocDatabase * qdocDB()
Creates the singleton.
NamespaceNode * primaryTreeRoot()
Returns a pointer to the root node of the primary tree.
const CollectionNode * getModuleNode(const Node *relative)
Returns the collection node representing the module that relative node belongs to,...
void mergeCollections(CollectionNode *c)
Finds all the collection nodes with the same name and type as c and merges their members into the mem...
const Atom * firstAtom() const
#define CONFIG_REDIRECTDOCUMENTATIONTODEVNULL
#define CONFIG_AUTOLINKERRORS
#define CONFIG_EXTRAIMAGES
#define CONFIG_OUTPUTSUFFIXES
#define CONFIG_OUTPUTPREFIXES
#define CONFIG_NOLINKERRORS
#define CONFIG_EXAMPLESINSTALLPATH
#define CONFIG_PRODUCTNAME
#define CONFIG_QUOTINGINFORMATION
#define CONFIG_STYLESHEETS
#define CONFIG_FORMATTING
QMultiMap< QString, QString > QStringMultiMap
The Node class is the base class for all the nodes in QDoc's parse tree.
bool isGenericCollection() const
Returns true if the node type is Collection.
bool isExternalPage() const
Returns true if the node type is ExternalPage.
const Doc & doc() const
Returns a reference to the node's Doc data member.
bool isQmlNode() const
Returns true if this node's Genus value is QML.
virtual bool docMustBeGenerated() const
This function is called to perform a test to decide if the node must have documentation generated.
virtual bool isWrapper() const
Returns true if the node is a class node or a QML type node that is marked as being a wrapper class o...
bool isPrivate() const
Returns true if this node's access is Private.
bool isNamespace() const
Returns true if the node type is Namespace.
bool isQmlBasicType() const
Returns true if the node type is QmlBasicType.
ComparisonCategory comparisonCategory() const
bool hasFileNameBase() const
Returns true if the node's file name base has been set.
bool isQmlType() const
Returns true if the node type is QmlType or QmlValueType.
bool isSharedCommentNode() const
Returns true if the node type is SharedComment.
bool isHeader() const
Returns true if the node type is HeaderFile.
NodeType nodeType() const override
Returns this node's type.
Genus genus() const override
Returns this node's Genus.
virtual bool isPageNode() const
Returns true if this node represents something that generates a documentation page.
virtual bool isMacro() const
returns true if either FunctionNode::isMacroWithParams() or FunctionNode::isMacroWithoutParams() retu...
bool isEnumType() const
Returns true if the node type is Enum.
virtual Status status() const
Returns the node's status value.
virtual bool isTextPageNode() const
Returns true if the node is a PageNode but not an Aggregate.
virtual bool isAttached() const
Returns true if the QML property or QML method node is marked as attached.
Aggregate * parent() const
Returns the node's parent pointer.
virtual bool isDeprecated() const
Returns true if this node's status is Deprecated.
virtual bool isAggregate() const
Returns true if this node is an aggregate, which means it inherits Aggregate and can therefore have c...
static bool nodeNameLessThan(const Node *first, const Node *second)
Returns true if the node n1 is less than node n2.
const Location & location() const
If this node's definition location is empty, this function returns this node's declaration location.
bool isProxyNode() const
Returns true if the node type is Proxy.
Access access() const
Returns the node's Access setting, which can be Public, Protected, or Private.
bool isFunction(Genus g=Genus::DontCare) const
Returns true if this is a FunctionNode and its Genus is set to g.
ThreadSafeness threadSafeness() const
Returns the thread safeness value for whatever this node represents.
virtual bool isMarkedReimp() const
Returns true if the FunctionNode is marked as a reimplemented function.
bool isProperty() const
Returns true if the node type is Property.
NodeContext createContext() const
bool isModule() const
Returns true if the node type is Module.
virtual bool isPropertyGroup() const
Returns true if the node is a SharedCommentNode for documenting multiple C++ properties or multiple Q...
ThreadSafeness
An unsigned char that specifies the degree of thread-safeness of the element.
bool isSharingComment() const
This function returns true if the node is sharing a comment with other nodes.
virtual CollectionNode * logicalModule() const
If this is a QmlTypeNode, a pointer to its QML module is returned, which is a pointer to a Collection...
bool hasDoc() const
Returns true if this node is documented, or it represents a documented node read from the index ('had...
virtual bool isClassNode() const
Returns true if this is an instance of ClassNode.
virtual bool isCollectionNode() const
Returns true if this is an instance of CollectionNode.
bool isQmlModule() const
Returns true if the node type is QmlModule.
bool isExample() const
Returns true if the node type is Example.
bool isIndexNode() const
Returns true if this node was created from something in an index file.
bool isQmlProperty() const
Returns true if the node type is QmlProperty.
Represents a file that is reachable by QDoc based on its current configuration.