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;
60QHash<QString, QString>
Generator::s_outputPrefixes;
61QHash<QString, QString>
Generator::s_outputSuffixes;
69static QRegularExpression
tag(
"</?@[^>]*>");
76
77
78
79
80
85 s_generators.prepend(
this);
89
90
91
94 s_generators.removeAll(
this);
98 const Node *actualNode)
100 if (actualNode ==
nullptr)
101 actualNode = apparentNode;
103 addNodeLink(text, actualNode, apparentNode->plainFullName(relative));
107 const Node *actualNode)
109 if (actualNode ==
nullptr)
110 actualNode = apparentNode;
112 addNodeLink(text, actualNode, fullName);
116
117
118
119
126
127
128
129
135 for (
const auto &node : nodes) {
136 text << Atom(Atom::ListItemNumber, QString::number(++count));
137 text << Atom(Atom::ListItemLeft, QString(
"bullet"));
138 appendSignature(text, node);
139 text << Atom(Atom::ListItemRight, QString(
"bullet"));
147 QMap<QString, Text> classMap;
148 for (
const auto &relatedClass : rc) {
149 ClassNode *rcn = relatedClass.m_node;
150 if (rcn && rcn->isInAPI()) {
152 appendFullName(className, rcn, cn);
153 classMap[className.toString().toLower()] = className;
158 const QStringList classNames = classMap.keys();
159 for (
const auto &className : classNames) {
160 text << classMap[className];
161 text << Utilities::comma(index++, classNames.size());
169 QMap<QString, Text> classMap;
171 QStringList typeNames(knownTypes);
172 for (
const auto sub : subs)
173 typeNames << sub->name();
175 for (
const auto sub : subs) {
177 appendFullName(full_name, sub, base);
179 if (typeNames.count(sub->name()) > 1)
180 full_name << Atom(Atom::String,
" (%1)"_L1.arg(sub->logicalModuleName()));
181 classMap[full_name.toString().toLower()] = full_name;
185 const auto &names = classMap.keys();
186 for (
const auto &name : names)
187 text << classMap[name] << Utilities::comma(index++, names.size());
192
193
194
195
196
197
198
206 if (s_outFileNames.contains(fileName) && !node->isAttribution() && !fileName.contains(
"-attribution-"_L1))
207 node->location().warning(
"Already generated %1 for this project"_L1.arg(fileName));
209 QString path = outputDir() + QLatin1Char(
'/') + fileName;
212 auto outFile =
new QFile(outPath);
215 const QString warningText {
"Output file already exists, overwriting %1"_L1.arg(outFile->fileName())};
216 if (qEnvironmentVariableIsSet(
"QDOC_ALL_OVERWRITES_ARE_WARNINGS"))
219 qCDebug(lcQdoc) << qUtf8Printable(warningText);
222 if (!outFile->open(QFile::WriteOnly | QFile::Text)) {
224 QStringLiteral(
"Cannot open output file '%1'").arg(outFile->fileName()));
227 qCDebug(lcQdoc,
"Writing: %s", qPrintable(path));
228 s_outFileNames << fileName;
229 s_trademarks.clear();
234
235
236
237
241 QFile *outFile = openSubPageFile(
static_cast<
const PageNode*>(node), fileName);
242 auto *out =
new QTextStream(outFile);
243 outStreamStack.push(out);
247
248
249
250
253 outStreamStack.top()->flush();
254 delete outStreamStack.top()->device();
255 delete outStreamStack.pop();
264 return node->fileNameBase();
266 QString base{node->name()};
267 if (base.endsWith(
".html"))
268 base.truncate(base.size() - 5);
272 base.append(
"-qmlmodule");
274 base.append(
"-module");
275 base.append(outputSuffix(node));
278 base.prepend(
"%1-"_L1.arg(s_project.toLower()));
279 base.append(
"-example");
283
284
285
286
287
288
289
290
292 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
294 if (InclusionFilter::isIncluded(policy, context))
295 base.prepend(
"%1%2-"_L1.arg(node->logicalModuleName(), outputSuffix(node)));
299 base.append(
"-%1-proxy"_L1.arg(node->tree()->physicalModuleName()));
302 const Node *p = node;
304 const Node *pp = p->parent();
305 base.prepend(p->name());
306 if (pp ==
nullptr || pp->name().isEmpty() || pp->isTextPageNode())
308 base.prepend(
'-'_L1);
311 if (node->isNamespace() && !node->name().isEmpty()) {
312 const auto *ns =
static_cast<
const NamespaceNode *>(node);
313 if (!ns->isDocumentedHere()) {
314 base.append(QLatin1String(
"-sub-"));
315 base.append(ns->tree()->camelCaseModuleName());
318 base.append(outputSuffix(node));
321 base.prepend(outputPrefix(node));
322 QString canonicalName{ Utilities::asAsciiPrintable(base) };
324 n->setFileNameBase(canonicalName);
325 return canonicalName;
329
330
331
332
333
337 link.prepend(s_project.toLower() + QLatin1Char(
'-'));
339 QString canonicalName{ Utilities::asAsciiPrintable(link) };
340 canonicalName.append(QLatin1Char(
'.'));
341 canonicalName.append(fileExt.isEmpty() ? fileExtension() : fileExt);
342 return canonicalName;
346
347
348
352 if (relative->files().contains(fileName))
353 suffix = QLatin1String(
" Example File");
354 else if (relative->images().contains(fileName))
355 suffix = QLatin1String(
" Image File");
359 return fileName.mid(fileName.lastIndexOf(QLatin1Char(
'/')) + 1) + suffix;
363
364
365
366
367
370 if (!node->url().isEmpty())
377 QFileInfo originalName(node->name());
378 QString suffix = originalName.suffix();
379 if (!suffix.isEmpty() && suffix !=
"html") {
381 QString name = fileBase(node);
382 return name + QLatin1Char(
'.') + suffix;
386 QString name = fileBase(node) + QLatin1Char(
'.');
387 return name + (extension.isNull() ? fileExtension() : extension);
391
392
393
394
395
396
397
398
399QString
Generator::cleanRef(
const QString &ref,
bool xmlCompliant)
410 clean.reserve(ref.size() + 20);
411 const QChar c = ref[0];
412 const uint u = c.unicode();
414 if ((u >=
'a' && u <=
'z') || (u >=
'A' && u <=
'Z') || (!xmlCompliant && u >=
'0' && u <=
'9')) {
416 }
else if (xmlCompliant && u >=
'0' && u <=
'9') {
417 clean += QLatin1Char(
'A') + c;
418 }
else if (u ==
'~') {
420 }
else if (u ==
'_') {
421 clean +=
"underscore.";
423 clean += QLatin1Char(
'A');
426 for (
int i = 1; i < ref.size(); i++) {
427 const QChar c = ref[i];
428 const uint u = c.unicode();
429 if ((u >=
'a' && u <=
'z') || (u >=
'A' && u <=
'Z') || (u >=
'0' && u <=
'9') || u ==
'-'
430 || u ==
'_' || (xmlCompliant && u ==
':') || u ==
'.') {
432 }
else if (c.isSpace()) {
433 clean += QLatin1Char(
'-');
434 }
else if (u ==
'!') {
436 }
else if (u ==
'&') {
438 }
else if (u ==
'<') {
440 }
else if (u ==
'=') {
442 }
else if (u ==
'>') {
444 }
else if (u ==
'#') {
445 clean += QLatin1Char(
'#');
447 clean += QLatin1Char(
'-');
448 clean += QString::number(
static_cast<
int>(u), 16);
456 return s_fmtLeftMaps[format()];
461 return s_fmtRightMaps[format()];
465
466
471 if (!node->url().isEmpty())
479
480
481
482 if (!fileBase(node).isEmpty())
483 parentName = fileBase(node) + QLatin1Char(
'.') + currentGenerator()->fileExtension();
487 return fileBase(node) + QLatin1Char(
'.') + currentGenerator()->fileExtension();
489 parentName = fileBase(node) + QLatin1Char(
'.') + currentGenerator()->fileExtension();
490 }
else if (fileBase(node).isEmpty())
493 Node *parentNode =
nullptr;
497 if (!node->parent()->isNamespace() || !node->parent()->name().isEmpty())
498 parentName = fullDocumentLocation(node->parent());
502 case NodeType::Class:
503 case NodeType::Struct:
504 case NodeType::Union:
505 case NodeType::Namespace:
506 case NodeType::Proxy:
507 parentName = fileBase(node) + QLatin1Char(
'.') + currentGenerator()->fileExtension();
510 const auto *fn =
static_cast<
const FunctionNode *>(node);
513 anchorRef = QLatin1Char(
'#') + node->name() +
"-signal";
516 anchorRef = QLatin1Char(
'#') + node->name() +
"-signal-handler";
519 anchorRef = QLatin1Char(
'#') + node->name() +
"-method";
523 anchorRef =
"#dtor." + fn->name().mid(1);
524 else if (
const auto *p = fn->primaryAssociatedProperty(); p && fn->doc().isEmpty())
525 return fullDocumentLocation(p);
526 else if (fn->overloadNumber() > 0)
527 anchorRef = QLatin1Char(
'#') + cleanRef(fn->name()) + QLatin1Char(
'-')
528 + QString::number(fn->overloadNumber());
530 anchorRef = QLatin1Char(
'#') + cleanRef(fn->name());
536
537
538
539
542 anchorRef = QLatin1Char(
'#') + node->name() +
"-enum";
545 const auto *tdef =
static_cast<
const TypedefNode *>(node);
546 if (tdef->associatedEnum())
547 return fullDocumentLocation(tdef->associatedEnum());
550 anchorRef = QLatin1Char(
'#') + node->name() +
"-typedef";
553 anchorRef = QLatin1Char(
'#') + node->name() +
"-prop";
561 anchorRef = QLatin1Char(
'#') + node->name() +
"-attached-prop";
563 anchorRef = QLatin1Char(
'#') + node->name() +
"-prop";
566 anchorRef = QLatin1Char(
'#') + node->name() +
"-var";
574 parentName = fileBase(node);
575 parentName.replace(QLatin1Char(
'/'), QLatin1Char(
'-'))
576 .replace(QLatin1Char(
'.'), QLatin1Char(
'-'));
589 return parentName.toLower() + anchorRef;
593
594
595
596
597
598
599
602 QList<Text> alsoList = node
->doc().alsoList();
603 supplementAlsoList(node, alsoList);
605 if (!alsoList.isEmpty()) {
612 for (
const auto &also : std::as_const(alsoList)) {
614 const Atom *atom = also.firstAtom();
615 QString link = atom->string();
616 if (!used.contains(link)) {
621 if (m_qdb->findNodeForAtom(atom, node, ref) == node && ref.isEmpty())
622 node->doc().location().warning(
"Redundant link to self in \\sa command for %1"_L1.arg(node->name()));
627 for (
const auto &also : std::as_const(items))
628 text << also << Utilities::separator(i++, items.size());
636 bool generate,
int &numAtoms)
638 while (atom !=
nullptr) {
640 int numAtoms0 = numAtoms;
641 bool rightFormat = canHandleFormat(atom->string());
656 if (generate && numAtoms0 == numAtoms) {
657 relative->location().warning(QStringLiteral(
"Output format %1 not handled %2")
658 .arg(format(), outFileName()));
659 Atom unhandledFormatAtom(Atom::UnhandledFormat, format());
669 n += generateAtom(atom, relative, marker);
681
682
683
689
690
691
695 text <<
"Destroys the instance of ";
696 text << fn
->parent()->name() <<
".";
698 text <<
" The destructor is virtual.";
704 text <<
"Default constructs an instance of ";
705 text << fn
->parent()->name() <<
".";
711 text <<
"Copy constructor.";
717 text <<
"Move-copy constructor.";
723 text <<
"Copy-assignment operator.";
729 text <<
"Move-assignment operator.";
734 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
737 node
->location().warning(QStringLiteral(
"No documentation for '%1'")
738 .arg(node->plainSignature()));
742 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
746 QStringLiteral(
"No documentation for '%1'").arg(node->plainSignature()));
751 generateReimplementsClause(fn, marker);
778 const auto *enume =
static_cast<
const EnumNode *>(node);
780 QSet<QString> definedItems;
781 const QList<EnumItem> &items = enume->items();
782 for (
const auto &item : items)
783 definedItems.insert(item.name());
785 const auto &documentedItemList = enume
->doc().enumItemNames();
786 QSet<QString> documentedItems(documentedItemList.cbegin(), documentedItemList.cend());
787 const QSet<QString> allItems = definedItems + documentedItems;
788 if (allItems.size() > definedItems.size()
789 || allItems.size() > documentedItems.size()) {
790 for (
const auto &it : allItems) {
791 if (!definedItems.contains(it)) {
793 QString best = nearestName(it, definedItems);
794 if (!best.isEmpty() && !documentedItems.contains(best))
795 details = QStringLiteral(
"Maybe you meant '%1'?").arg(best);
797 node->doc().location().warning(
798 QStringLiteral(
"No such enum item '%1' in %2")
799 .arg(it, node->plainFullName()),
801 }
else if (!documentedItems.contains(it)) {
802 node->doc().location().warning(
803 QStringLiteral(
"Undocumented enum item '%1' in %2")
804 .arg(it, node->plainFullName()));
810 const QSet<QString> documentedNames = fn
->doc().parameterNames();
811 if (declaredNames != documentedNames) {
812 for (
const auto &name : declaredNames) {
813 if (!documentedNames.contains(name)) {
814 if (fn->isActive() || fn->isPreliminary()) {
817 if (!fn->isMarkedReimp() && !fn->isOverload()
818 && !(fn->isSomeCtor() && fn->hasOverloads())) {
819 fn->doc().location().warning(
820 QStringLiteral(
"Undocumented parameter '%1' in %2")
821 .arg(name, node->plainFullName()));
826 for (
const auto &name : documentedNames) {
827 if (!declaredNames.contains(name) && CodeParser::isWorthWarningAbout(fn->doc())) {
828 QString best = nearestName(name, declaredNames);
831 details = QStringLiteral(
"Maybe you meant '%1'?").arg(best);
832 fn->doc().location().warning(QStringLiteral(
"No such parameter '%1' in %2")
833 .arg(name, fn->plainFullName()),
839
840
841
842
845 if (!fn
->doc().body().contains(
"return"))
847 QStringLiteral(
"Undocumented return value "
848 "(hint: use 'return' or 'returns' in the text"));
851 if (
auto *qpn =
static_cast<
const QmlPropertyNode *>(node); !qpn->validateDataType())
852 qpn->doc().location().warning(
"Invalid QML property type: %1"_L1.arg(qpn->dataType()));
860
861
862
863
864
870 const auto *en =
static_cast<
const ExampleNode *>(node);
873 if (exampleUrl.isEmpty()) {
879 generateLinkToExample(en, marker, exampleUrl);
884
885
886
887
888
889
891 const QString &baseUrl)
893 QString exampleUrl(baseUrl);
895#ifndef QT_BOOTSTRAPPED
896 link = QUrl(exampleUrl).host();
900 link.prepend(
"Example project");
902 const QLatin1Char separator(
'/');
903 const QLatin1Char placeholder(
'\1');
904 if (!exampleUrl.contains(placeholder)) {
905 if (!exampleUrl.endsWith(separator))
906 exampleUrl += separator;
907 exampleUrl += placeholder;
914 pathRoot = metaTagMap->value(QLatin1String(
"installpath"));
915 if (pathRoot.isEmpty())
917 QStringList path = QStringList() << pathRoot << en->name();
918 path.removeAll(QString());
922 <<
Atom(
Atom::Link, exampleUrl.replace(placeholder, path.join(separator)))
933 const QString prefix(
"/images/used-in-examples");
939 s_outFileNames << prefix.mid(1) +
"/" + resolved_file.get_query();
943 QString imgOutDir = s_outDir + prefix +
"/" + QFileInfo{resolved_file.get_query()}.path();
944 if (!dirInfo.mkpath(imgOutDir))
945 en
->location().fatal(QStringLiteral(
"Cannot create output directory '%1'").arg(imgOutDir));
946 Config::copyFile(en->location(), resolved_file.get_path(), QFileInfo{resolved_file.get_query()}.fileName(), imgOutDir);
961
962
963
964
965
966
976 paths = en->images();
983 std::sort(paths.begin(), paths.end(), Generator::comparePaths);
988 for (
const auto &path : std::as_const(paths)) {
989 auto maybe_resolved_file{file_resolver.resolve(path)};
990 if (!maybe_resolved_file) {
992 QString details = std::transform_reduce(
993 file_resolver.get_search_directories().cbegin(),
994 file_resolver.get_search_directories().cend(),
995 u"Searched directories:"_s,
997 [](
const DirectoryPath &directory_path) -> QString {
return u' ' + directory_path.value(); }
1000 en->location().warning(u"(Generator)Cannot find file to quote from: %1"_s.arg(path), details);
1005 const auto &file{*maybe_resolved_file};
1007 addImageToCopy(en, file);
1009 generateExampleFilePage(en, file, marker);
1012 text << Atom(Atom::ListItemNumber, openedList.numberString())
1013 << Atom(Atom::ListItemLeft, openedList.styleString()) << Atom::ParaLeft
1014 << Atom(atomType, file.get_query()) << Atom(Atom::FormattingLeft,
ATOM_FORMATTING_LINK) << file.get_query()
1016 << Atom(Atom::ListItemRight, openedList.styleString());
1019 if (!paths.isEmpty())
1020 generateText(text, en, marker);
1024
1025
1028 if (!node->url().isNull())
1032 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
1040
1041
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1068 beginSubPage(node, fileName(node));
1075 QString name = cn->name().toLower();
1076 name.replace(QChar(
' '), QString(
"-"));
1078 cn->tree()->physicalModuleName() +
"-" + name +
"." + fileExtension();
1079 beginSubPage(node, filename);
1084 beginSubPage(node, fileName(node));
1090 beginSubPage(node, fileName(node));
1094 beginSubPage(node, fileName(node));
1099 beginSubPage(node, fileName(node));
1107 auto *aggregate =
static_cast<
Aggregate *>(node);
1109 for (
auto *child : children) {
1110 if (child->isPageNode() && !child->isPrivate()) {
1111 generateDocumentation(child);
1112 }
else if (!node->parent() && child->isInAPI() && !child->isRelatedNonmember()) {
1114 child->location().warning(u"No documentation generated for %1 '%2' in global scope."_s
1115 .arg(typeString(child), child->name()),
1116 u"Maybe you forgot to use the '\\relates' command?"_s);
1117 child->setStatus(Node::DontDocument);
1118 }
else if (child->isQmlModule() && !child->wasSeen()) {
1120 auto *qmlModule =
static_cast<CollectionNode *>(child);
1121 for (
const auto *member : qmlModule->members()) {
1122 member->location().warning(
1123 u"Undocumented QML module '%1' referred by type '%2' or its members"_s
1124 .arg(qmlModule->name(), member->name()),
1125 u"Maybe you forgot to document '\\qmlmodule %1'?"_s
1126 .arg(qmlModule->name()));
1128 }
else if (child->isQmlType() && !child->hasDoc()) {
1130 auto *qmlType =
static_cast<QmlTypeNode *>(child);
1131 if (
auto qmid = qmlType->logicalModuleName(); !qmid.isEmpty())
1132 qmlType->location().warning(u"No such type '%1' in QML module '%2'"_s
1133 .arg(qmlType->name(), qmid));
1145 const FunctionNode *overrides = cn->findOverriddenFunction(fn);
1151 overrides->parent()->name()
1152 +
"::" + overrides->signature(Node::SignaturePlain);
1155 generateText(text, fn, marker);
1157 fn
->doc().location().warning(
1158 QStringLiteral(
"Illegal \\reimp; no documented virtual function for %1")
1159 .arg(overrides->plainSignature()));
1163 const PropertyNode *sameName = cn->findOverriddenProperty(fn);
1164 if (sameName && sameName
->hasDoc()) {
1166 text <<
Atom::ParaLeft <<
"Reimplements an access function for property: ";
1167 QString fullName = sameName->parent()->name() +
"::" + sameName->name();
1170 generateText(text, fn, marker);
1176 QStringList since = node->since().split(QLatin1Char(
' '));
1179 if (since.size() == 1) {
1181 return productName.isEmpty() ? node->since() : productName +
" " + since[0];
1185 return node->since();
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1210 status = metaMap->value(
"status");
1211 if (!status.isEmpty())
1214 const auto &since = node->deprecatedSince();
1216 status = u"Deprecated"_s;
1217 if (!since.isEmpty())
1218 status +=
" since %1"_L1.arg(since);
1219 }
else if (!since.isEmpty()) {
1220 status =
"Until %1"_L1.arg(since);
1222 status = u"Preliminary"_s;
1224 status = collection->state();
1227 return status.isEmpty() ?
std::nullopt :
std::optional(status);
1232 if (!node->since().isEmpty()) {
1235 const auto &collective =
static_cast<
const SharedCommentNode *>(node)->collective();
1236 QString typeStr = collective.size() > 1 ? typeString(collective.first()) +
"s" : typeString(node);
1237 text << Atom::ParaLeft <<
"These " << typeStr <<
" were introduced in "
1238 << formatSince(node) <<
"." << Atom::ParaRight;
1240 text << Atom::ParaLeft <<
"This " << typeString(node) <<
" was introduced in "
1241 << formatSince(node) <<
"." << Atom::ParaRight;
1248 std::vector<
const Node*> nodes;
1251 nodes.reserve(shared_node->collective().size());
1252 nodes.insert(nodes.begin(), shared_node->collective().begin(), shared_node->collective().end());
1253 }
else nodes.push_back(node);
1255 std::size_t counter{1};
1256 for (
const Node* node : nodes) {
1257 if (node->isFunction(Genus::CPP)) {
1258 if (
const auto &exception_info =
static_cast<
const FunctionNode*>(node)->getNoexcept(); exception_info && !(*exception_info).isEmpty()) {
1260 text << Atom::NoteLeft
1261 << (nodes.size() > 1 ? QString::fromStdString(
" ("s + std::to_string(counter) +
")"s) : QString::fromStdString(
"This ") + typeString(node))
1262 <<
" is noexcept when "
1263 << Atom(Atom::C, marker->markedUpCode(*exception_info,
nullptr, Location()))
1264 <<
" is " << Atom(Atom::C,
"true") <<
"."
1266 generateText(text, node, marker);
1282 const QString &state =
static_cast<
const CollectionNode*>(node)->state();
1283 if (!state.isEmpty()) {
1284 text << Atom::ParaLeft <<
"This " << typeString(node) <<
" is in "
1291 if (
const auto &version = node->deprecatedSince(); !version.isEmpty()) {
1292 text << Atom::ParaLeft <<
"This " << typeString(node)
1293 <<
" is scheduled for deprecation in version "
1294 << version <<
"." << Atom::ParaRight;
1297 case Node::Preliminary:
1299 << typeString(node) <<
" is under development and is subject to change."
1306 text <<
"This " << typeString(node) <<
" is deprecated";
1307 if (
const QString &version = node->deprecatedSince(); !version.isEmpty()) {
1309 if (node
->isQmlNode() && !node->logicalModuleName().isEmpty())
1310 text << node->logicalModuleName() <<
" ";
1314 text <<
". We strongly advise against using it in new code.";
1327
1328
1329
1333 Q_ASSERT(node && !node->name().isEmpty());
1335 text << Atom(Atom::DivLeft,
1336 "class=\"admonition %1\""_L1.arg(prefix == AdmonitionPrefix::Note ? u"note"_s : u"auto"_s));
1351 text <<
"This function can be invoked via the meta-object system and from QML. See "
1357 text <<
"This is a private signal. It can be used in signal connections "
1358 "but cannot be emitted by the user.";
1362 QString handler(node->name());
1363 qsizetype prefixLocation = handler.lastIndexOf(
'.', -2) + 1;
1364 handler[prefixLocation] = handler[prefixLocation].toTitleCase();
1365 handler.insert(prefixLocation, QLatin1String(
"on"));
1366 text <<
"The corresponding handler is "
1375 const auto *fn =
static_cast<
const FunctionNode *>(node);
1376 auto nodes = fn->associatedProperties();
1377 if (nodes.isEmpty())
1382 QMap<PropertyNode::FunctionRole, QList<
const PropertyNode *>> roleGroups;
1383 for (
const auto *n : std::as_const(nodes)) {
1384 const auto *pn =
static_cast<
const PropertyNode *>(n);
1385 if (pn->isInAPI()) {
1386 PropertyNode::FunctionRole role = pn->role(fn);
1387 roleGroups[role].append(pn);
1391 if (roleGroups.isEmpty())
1402 for (
auto role : roleOrder) {
1403 const auto it = roleGroups.constFind(role);
1404 if (it == roleGroups.cend())
1407 const auto &properties = it.value();
1411 case PropertyNode::FunctionRole::Getter:
1412 msg = u"Getter function"_s;
1414 case PropertyNode::FunctionRole::Setter:
1415 msg = u"Setter function"_s;
1417 case PropertyNode::FunctionRole::Resetter:
1418 msg = u"Resetter function"_s;
1420 case PropertyNode::FunctionRole::Notifier:
1421 msg = u"Notifier signal"_s;
1423 case PropertyNode::FunctionRole::Bindable:
1424 msg = u"Bindable function"_s;
1430 if (properties.size() == 1) {
1431 const auto *pn = properties.first();
1432 text << msg << u" for property "_s << Atom(Atom::Link, pn->name())
1436 text << msg << u" for properties "_s;
1437 for (qsizetype i = 0; i < properties.size(); ++i) {
1438 const auto *pn = properties.at(i);
1442 << Utilities::separator(i, properties.size());
1451 text <<
"This property supports "
1455 text <<
" bindings.";
1460 const auto *func =
static_cast<
const FunctionNode *>(node);
1467 QString functionType = func->isSignal() ?
"signal" :
"slot";
1468 const QString &configKey = func
->isSignal() ?
"overloadedsignalstarget" :
"overloadedslotstarget";
1469 const QString &defaultTarget = func
->isSignal() ?
"connecting-overloaded-signals" :
"connecting-overloaded-slots";
1470 const QString &linkTarget = Config::instance().get(configKey).asString(defaultTarget);
1472 text <<
"This " << functionType <<
" is overloaded. ";
1474 QString snippet = generateOverloadSnippet(func);
1475 if (!snippet.isEmpty()) {
1476 text <<
"To connect to this " << functionType <<
":\n\n"
1480 text <<
"For more examples and approaches, see "
1483 <<
"connecting to overloaded " << functionType <<
"s"
1486 const auto &args = node
->doc().overloadList();
1487 if (args.first().first.isEmpty()) {
1488 text <<
"This is an overloaded function.";
1490 QString target = args.first().first;
1493 if (!target.contains(
"::")) {
1496 target = parent->name() +
"::" + target;
1513
1514
1515
1516
1519 bool result =
false;
1530
1531
1532
1533
1534
1535
1536
1537
1541 bool result =
false;
1544 for (
auto child : children) {
1545 if (!child->isDeprecated()) {
1546 switch (child->threadSafeness()) {
1547 case Node::Reentrant:
1548 reentrant.append(child);
1549 if (ts == Node::ThreadSafe)
1552 case Node::ThreadSafe:
1553 threadsafe.append(child);
1554 if (ts == Node::Reentrant)
1557 case Node::NonReentrant:
1558 nonreentrant.append(child);
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1590 if (atom->count() > 1) {
1591 if (s_trademarks.contains(atom->string(1)))
1593 s_trademarks << atom->string(1);
1606
1607
1608
1611 Text text, rlink, tlink;
1616 bool exceptions =
false;
1627 case Node::NonReentrant:
1630 << typeString(node) <<
" is not " << rlink <<
"." << Atom::ParaRight;
1636 exceptions = hasExceptions(node, reentrant, threadsafe, nonreentrant);
1637 text <<
"All functions in this " << typeString(node) <<
" are ";
1646 text <<
" with the following exceptions:";
1648 text <<
"This " << typeString(node) <<
" is ";
1665 if (!nonreentrant.isEmpty()) {
1667 text <<
"These functions are not " << rlink <<
":" <<
Atom::ParaRight;
1668 signatureList(nonreentrant, node, marker);
1670 if (!threadsafe.isEmpty()) {
1673 text <<
"These functions are also " << tlink <<
":" <<
Atom::ParaRight;
1675 signatureList(threadsafe, node, marker);
1678 if (!reentrant.isEmpty()) {
1680 text <<
"These functions are only " << rlink <<
":" <<
Atom::ParaRight;
1681 signatureList(reentrant, node, marker);
1683 if (!nonreentrant.isEmpty()) {
1686 text <<
"These functions are not " << rlink <<
":" <<
Atom::ParaRight;
1687 signatureList(nonreentrant, node, marker);
1694
1695
1696
1697
1698
1702 if (category == ComparisonCategory::None)
1706 text << Atom::ParaLeft <<
"This %1 is "_L1.arg(typeString(node))
1708 << QString::fromStdString(comparisonCategoryAsString(category))
1709 << ((category == ComparisonCategory::Equality) ?
"-"_L1 :
"ly "_L1)
1710 << Atom(Atom::String,
"comparable"_L1)
1712 <<
"."_L1 << Atom::ParaRight;
1718
1719
1720
1721
1722
1723
1727 if (!node
->doc().comparesWithMap())
1730 Text relationshipText;
1731 for (
auto [key, description] : node->doc().comparesWithMap()->asKeyValueRange()) {
1732 const QString &category = QString::fromStdString(comparisonCategoryAsString(key));
1734 relationshipText << Atom::ParaLeft <<
"This %1 is "_L1.arg(typeString(node))
1736 << ((key == ComparisonCategory::Equality) ?
"-"_L1 :
"ly "_L1)
1741 const QStringList types{description.firstAtom()->string().split(
';'_L1)};
1742 for (
const auto &name : types)
1743 relationshipText << Atom(Atom::AutoLink, name)
1744 << Utilities::separator(types.indexOf(name), types.size());
1746 relationshipText << Atom(Atom::ParaRight) << description;
1754
1755
1758 s_currentGenerator =
this;
1764 for (
const auto &generator : std::as_const(s_generators)) {
1765 if (generator->format() == format)
1780 while (i < markedCode.size()) {
1781 if (markedCode.at(i) == QLatin1Char(
'\n')) {
1785 for (
int j = 0; j < level; j++)
1786 t += QLatin1Char(
' ');
1790 t += markedCode.at(i++);
1797 Config &config = Config::instance();
1798 s_outputFormats = config.getOutputFormats();
1801 for (
auto &g : s_generators) {
1802 if (s_outputFormats.contains(g->format())) {
1803 s_currentGenerator = g;
1804 g->initializeGenerator();
1809 for (
const auto &n : configFormatting) {
1811 const auto &formattingDotNames = config.subVars(formattingDotName);
1812 for (
const auto &f : formattingDotNames) {
1813 const auto &configVar = config.get(formattingDotName + Config::dot + f);
1814 QString def{configVar.asString()};
1815 if (!def.isEmpty()) {
1816 int numParams = Config::numParams(def);
1817 int numOccs = def.count(
"\1");
1818 if (numParams != 1) {
1819 configVar.location().warning(QStringLiteral(
"Formatting '%1' must "
1821 "parameter (found %2)")
1822 .arg(n, numParams));
1823 }
else if (numOccs > 1) {
1824 configVar.location().fatal(QStringLiteral(
"Formatting '%1' must "
1825 "contain exactly one "
1826 "occurrence of '\\1' "
1830 int paramPos = def.indexOf(
"\1");
1831 s_fmtLeftMaps[f].insert(n, def.left(paramPos));
1832 s_fmtRightMaps[f].insert(n, def.mid(paramPos + 1));
1839 s_outDir = config.getOutputDir();
1840 s_outSubdir = s_outDir.mid(s_outDir.lastIndexOf(
'/') + 1);
1842 s_outputPrefixes.clear();
1844 if (!items.isEmpty()) {
1845 for (
const auto &prefix : items)
1846 s_outputPrefixes[prefix] =
1849 if (!items.contains(u"QML"_s))
1850 s_outputPrefixes[u"QML"_s] = u"qml-"_s;
1852 s_outputSuffixes.clear();
1855 + Config::dot + suffix).asString();
1862
1863
1864
1865void Generator::copyTemplateFiles(
const QString &configVar,
const QString &subDir)
1882 Config &config = Config::instance();
1883 QStringList files = config.getCanonicalPathList(configVar,
Config::Validate);
1884 const auto &loc = config.get(configVar)
.location();
1885 if (!files.isEmpty()) {
1898 QString templateDir = s_outDir + QLatin1Char(
'/') + subDir;
1899 if (!dirInfo.exists(templateDir) && !dirInfo.mkdir(templateDir)) {
1901 loc.fatal(QStringLiteral(
"Cannot create %1 directory '%2'").arg(subDir, templateDir));
1903 for (
const auto &file : files) {
1904 if (!file.isEmpty())
1905 Config::copyFile(loc, file, file, templateDir);
1912
1913
1914
1915
1918 Config &config = Config::instance();
1919 s_outFileNames.clear();
1920 s_useOutputSubdirs =
true;
1921 if (config.get(format() + Config::dot +
"nosubdirs").asBool())
1924 if (s_outputFormats.isEmpty())
1929 s_outDir = config.getOutputDir(format());
1930 if (s_outDir.isEmpty()) {
1931 Location().fatal(QStringLiteral(
"No output directory specified in "
1932 "configuration file or on the command line"));
1934 s_outSubdir = s_outDir.mid(s_outDir.lastIndexOf(
'/') + 1);
1937 QDir outputDir(s_outDir);
1938 if (outputDir.exists()) {
1940 if (!outputDir.isEmpty())
1941 Location().error(QStringLiteral(
"Output directory '%1' exists but is not empty")
1944 }
else if (!outputDir.mkpath(QStringLiteral(
"."))) {
1945 Location().fatal(QStringLiteral(
"Cannot create output directory '%1'").arg(s_outDir));
1953 if (!outputDir.exists(imagesDir) && !outputDir.mkpath(imagesDir))
1954 Location().fatal(
"Cannot create images directory '%1'"_L1
1955 .arg(QDir::cleanPath(outputDir.filePath(imagesDir))));
1956 s_imagesOutDir = imagesDir;
1959 copyTemplateFiles(format() + Config::dot +
CONFIG_SCRIPTS,
"scripts");
1970
1971
1972
1984
1985
1986
1987
1990 return *outStreamStack.top();
1995 return QFileInfo(
static_cast<QFile *>(
out().device())->fileName()).fileName();
2004 return s_outputPrefixes[u"QML"_s];
2006 return s_outputPrefixes[u"CPP"_s];
2019 return s_outputSuffixes[u"QML"_s];
2021 return s_outputSuffixes[u"CPP"_s];
2031 QStringView *contents, QStringView *par1)
2034 if (i >= n || src[i] != c)
2039 while (i < n && src[i] == ' ')
2049 if (tag != QStringView(src).mid(i, tag.size())) {
2061 while (i < n && src[i].isLetter())
2063 if (src[i] ==
'=') {
2068 while (i < n && src[i] !=
'"')
2070 *par1 = QStringView(src).mid(j, i - j);
2081 if (i + 4 + tag.size() > n)
2085 if (src[i + 1] !=
'/')
2087 if (src[i + 2] !=
'@')
2089 if (tag != QStringView(src).mid(i + 3, tag.size()))
2091 if (src[i + 3 + tag.size()] !=
'>')
2096 *contents = QStringView(src).mid(j, i - j);
2098 i += tag.size() + 4;
2108 QString t = markedCode;
2109 t.replace(tag, QString());
2110 t.replace(quot, QLatin1String(
"\""));
2111 t.replace(gt, QLatin1String(
">"));
2112 t.replace(lt, QLatin1String(
"<"));
2113 t.replace(amp, QLatin1String(
"&"));
2121 while (atom && atom
->type() != type) {
2129
2130
2140 m_sectionNumber.clear();
2146 const auto fn =
static_cast<
const FunctionNode *>(node);
2148 QString alternateName;
2151 if (fn->name().startsWith(
"set") && fn->name().size() >= 4) {
2152 alternateName = fn->name()[3].toLower();
2153 alternateName += fn->name().mid(4);
2154 alternateFunc = fn
->parent()->findFunctionChild(alternateName, QString());
2156 if (!alternateFunc) {
2157 alternateName =
"is" + fn->name().mid(3);
2158 alternateFunc = fn
->parent()->findFunctionChild(alternateName, QString());
2159 if (!alternateFunc) {
2160 alternateName =
"has" + fn->name().mid(3);
2161 alternateFunc = fn
->parent()->findFunctionChild(alternateName, QString());
2164 }
else if (!fn->name().isEmpty()) {
2165 alternateName =
"set";
2166 alternateName += fn->name()[0].toUpper();
2167 alternateName += fn->name().mid(1);
2168 alternateFunc = fn
->parent()->findFunctionChild(alternateName, QString());
2173 for (i = 0; i < alsoList.size(); ++i) {
2174 if (alsoList.at(i).toString().contains(alternateName))
2178 if (i == alsoList.size()) {
2181 alternateName +=
"()";
2187 alsoList.prepend(also);
2207 const auto *start{body.firstAtom()};
2213 text << body.subText(text
.isEmpty() ? start : start->next(), end);
2228 for (
const auto &generator : std::as_const(s_generators)) {
2229 if (s_outputFormats.contains(generator->format()))
2230 generator->terminateGenerator();
2256 s_generators.clear();
2258 s_fmtLeftMaps.clear();
2259 s_fmtRightMaps.clear();
2261 s_imagesOutDir.clear();
2267
2268
2269
2270QString
Generator::trimmedTrailing(
const QString &string,
const QString &prefix,
2271 const QString &suffix)
2273 QString trimmed = string;
2274 while (trimmed.size() > 0 && trimmed[trimmed.size() - 1].isSpace())
2275 trimmed.truncate(trimmed.size() - 1);
2277 trimmed.append(suffix);
2278 trimmed.prepend(prefix);
2285 case NodeType::Namespace:
2286 return "namespace"_L1;
2287 case NodeType::Class:
2289 case NodeType::Struct:
2291 case NodeType::Union:
2293 case NodeType::QmlType:
2294 case NodeType::QmlValueType:
2296 case NodeType::Page:
2297 return "documentation"_L1;
2298 case NodeType::Enum:
2300 case NodeType::Typedef:
2301 case NodeType::TypeAlias:
2302 return "typedef"_L1;
2304 const auto fn =
static_cast<
const FunctionNode *>(node);
2306 case FunctionNode::QmlSignal:
2308 case FunctionNode::QmlSignalHandler:
2309 return "signal handler"_L1;
2310 case FunctionNode::QmlMethod:
2312 case FunctionNode::MacroWithParams:
2313 case FunctionNode::MacroWithoutParams:
2318 return "function"_L1;
2320 case NodeType::Property:
2321 case NodeType::QmlProperty:
2322 return "property"_L1;
2323 case NodeType::Module:
2324 case NodeType::QmlModule:
2326 case NodeType::Variable:
2327 return "variable"_L1;
2330 if (shared->isPropertyGroup())
2331 return "property group"_L1;
2332 const auto &collective = shared->collective();
2333 return collective.first()->nodeTypeString();
2336 return "documentation"_L1;
2342 Location::internalError(QStringLiteral(
"unknown atom type '%1' in %2 generator")
2343 .arg(atom->typeString(), format()));
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2380 if (!cn || (cn->cmakeComponent().isEmpty() && cn->cmakePackage().isEmpty())) {
2384 const QString package =
2385 cn->cmakePackage().isEmpty() ?
"Qt" + QString::number(QT_VERSION_MAJOR) : cn->cmakePackage();
2387 QString findPackageText;
2388 if (cn->cmakeComponent().isEmpty()) {
2389 findPackageText =
"find_package(" + package +
" REQUIRED)";
2391 findPackageText =
"find_package(" + package +
" REQUIRED COMPONENTS " + cn->cmakeComponent() +
")";
2395 if (cn->cmakeTargetItem().isEmpty()) {
2396 if (cn->cmakeComponent().isEmpty()) {
2397 targetText = package +
"::" + package;
2399 targetText = package +
"::" + cn->cmakeComponent();
2402 targetText = cn->cmakeTargetItem();
2405 const QString targetLinkLibrariesText =
"target_link_libraries(mytarget PRIVATE " + targetText +
")";
2406 const QStringList cmakeInfo { findPackageText, targetLinkLibrariesText };
2408 return std::make_pair(findPackageText, targetLinkLibrariesText);
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421void Generator::addNodeLink(
Text &text,
const QString &nodeRef,
const QString &linkText) {
2429
2430
2431
2432
2433
2434
2435
2436
2440 Utilities::stringForNode(node),
2441 linkText.isEmpty() ? node->name() : linkText
2446
2447
2448
2454 QString className = func->parent()->name();
2455 QString functionName = func->name();
2456 QString parameters = func->parameters().generateTypeList();
2458 QString objectName = generateObjectName(className);
2460 QString snippet = QString(
2461 "// Connect using qOverload:\n"
2462 "connect(%1, qOverload<%2>(&%3::%4),\n"
2463 " receiver, &ReceiverClass::slot);\n\n"
2464 "// Or using a lambda:\n"
2465 "connect(%1, qOverload<%2>(&%3::%4),\n"
2466 " this, [](%5) { /* handle %4 */ });")
2467 .arg(objectName, parameters, className, functionName,
2468 func->parameters().generateTypeAndNameList());
2474
2475
2476
2479 QString name = className;
2481 if (name.startsWith(
'Q') && name.length() > 1)
2484 if (!name.isEmpty())
2485 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.
bool isPrimaryOverload() const
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)
Generates text for a "see also" list for the given node and marker if a list has been defined.
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)
static bool s_redirectDocumentationToDevNull
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_IMAGESOUTPUTDIR
#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.