diff options
Diffstat (limited to 'src/qdoc/generator.cpp')
-rw-r--r-- | src/qdoc/generator.cpp | 196 |
1 files changed, 124 insertions, 72 deletions
diff --git a/src/qdoc/generator.cpp b/src/qdoc/generator.cpp index 46d3ad453..bdeeec2be 100644 --- a/src/qdoc/generator.cpp +++ b/src/qdoc/generator.cpp @@ -75,11 +75,8 @@ QStringList Generator::styleFiles; bool Generator::noLinkErrors_ = false; bool Generator::autolinkErrors_ = false; bool Generator::redirectDocumentationToDevNull_ = false; -Generator::QDocPass Generator::qdocPass_ = Generator::Neither; bool Generator::qdocSingleExec_ = false; -bool Generator::qdocWriteQaPages_ = false; bool Generator::useOutputSubdirs_ = true; -bool Generator::useTimestamps_ = false; QmlTypeNode *Generator::qmlTypeContext_ = nullptr; static QRegExp tag("</?@[^>]*>"); @@ -393,9 +390,10 @@ QString Generator::fileBase(const Node *node) const to the file name. The suffix, if one exists, is appended to the module name. */ - if (!node->logicalModuleName().isEmpty()) { + if (!node->logicalModuleName().isEmpty() + && (!node->logicalModule()->isInternal() || showInternal_)) base.prepend(node->logicalModuleName() + outputSuffix(node) + QLatin1Char('-')); - } + base.prepend(outputPrefix(node)); } else if (node->isProxyNode()) { base = node->name(); @@ -761,55 +759,55 @@ const Atom *Generator::generateAtomList(const Atom *atom, const Node *relative, */ void Generator::generateBody(const Node *node, CodeMarker *marker) { + const FunctionNode *fn = node->isFunction() ? static_cast<const FunctionNode *>(node) : nullptr; if (!node->hasDoc() && !node->hasSharedDoc()) { /* Test for special function, like a destructor or copy constructor, that has no documentation. */ - if (node->isFunction()) { - const FunctionNode *func = static_cast<const FunctionNode *>(node); - if (func->isDtor()) { + if (fn) { + if (fn->isDtor()) { Text text; text << "Destroys the instance of "; - text << func->parent()->name() << "."; - if (func->isVirtual()) + text << fn->parent()->name() << "."; + if (fn->isVirtual()) text << " The destructor is virtual."; out() << "<p>"; generateText(text, node, marker); out() << "</p>"; - } else if (func->isCtor()) { + } else if (fn->isCtor()) { Text text; text << "Default constructs an instance of "; - text << func->parent()->name() << "."; + text << fn->parent()->name() << "."; out() << "<p>"; generateText(text, node, marker); out() << "</p>"; - } else if (func->isCCtor()) { + } else if (fn->isCCtor()) { Text text; text << "Copy constructor."; out() << "<p>"; generateText(text, node, marker); out() << "</p>"; - } else if (func->isMCtor()) { + } else if (fn->isMCtor()) { Text text; text << "Move-copy constructor."; out() << "<p>"; generateText(text, node, marker); out() << "</p>"; - } else if (func->isCAssign()) { + } else if (fn->isCAssign()) { Text text; text << "Copy-assignment operator."; out() << "<p>"; generateText(text, node, marker); out() << "</p>"; - } else if (func->isMAssign()) { + } else if (fn->isMAssign()) { Text text; text << "Move-assignment operator."; out() << "<p>"; generateText(text, node, marker); out() << "</p>"; } else if (!node->isWrapper() && !node->isMarkedReimp()) { - if (!func->isIgnored()) // undocumented functions added by Q_OBJECT + if (!fn->isIgnored()) // undocumented functions added by Q_OBJECT node->location().warning( tr("No documentation for '%1'").arg(node->plainSignature())); } @@ -820,8 +818,7 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) tr("No documentation for '%1'").arg(node->plainSignature())); } } else if (!node->isSharingComment()) { - if (node->isFunction()) { - const FunctionNode *fn = static_cast<const FunctionNode *>(node); + if (fn) { if (!fn->overridesThis().isEmpty()) generateReimplementsClause(fn, marker); } @@ -831,6 +828,18 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) return; } + if (fn) { + if (fn->isQmlSignal()) + generateAddendum(node, QmlSignalHandler, marker); + if (fn->isPrivateSignal()) + generateAddendum(node, PrivateSignal, marker); + if (fn->isInvokable()) + generateAddendum(node, Invokable, marker); + if (fn->hasAssociatedProperties()) + generateAddendum(node, AssociatedProperties, marker); + } + + // Generate warnings if (node->isEnumType()) { const EnumNode *enume = static_cast<const EnumNode *>(node); @@ -862,8 +871,7 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) } } } - } else if (node->isFunction()) { - const FunctionNode *fn = static_cast<const FunctionNode *>(node); + } else if (fn) { const QSet<QString> declaredNames = fn->parameters().getNames(); const QSet<QString> documentedNames = fn->doc().parameterNames(); if (declaredNames != documentedNames) { @@ -920,7 +928,7 @@ void Generator::generateRequiredLinks(const Node *node, CodeMarker *marker) return; const ExampleNode *en = static_cast<const ExampleNode *>(node); - QString exampleUrl = config()->getString(CONFIG_URL + Config::dot + CONFIG_EXAMPLES); + QString exampleUrl = Config::instance().getString(CONFIG_URL + Config::dot + CONFIG_EXAMPLES); if (exampleUrl.isEmpty()) { if (!en->noAutoList()) { @@ -962,7 +970,7 @@ void Generator::generateLinkToExample(const ExampleNode *en, CodeMarker *marker, // Construct a path to the example; <install path>/<example name> QString pathRoot = en->doc().metaTagMap().value(QLatin1String("installpath")); if (pathRoot.isEmpty()) - pathRoot = config()->getString(CONFIG_EXAMPLESINSTALLPATH); + pathRoot = Config::instance().getString(CONFIG_EXAMPLESINSTALLPATH); QStringList path = QStringList() << pathRoot << en->name(); path.removeAll({}); @@ -1261,8 +1269,12 @@ void Generator::generateReimplementsClause(const FunctionNode *fn, CodeMarker *m appendFullName(text, overrides->parent(), fullName, overrides); text << "." << Atom::ParaRight; generateText(text, fn, marker); - return; + } else { + fn->doc().location().warning( + tr("Illegal \\reimp; no documented virtual function for %1") + .arg(overrides->plainSignature())); } + return; } const PropertyNode *sameName = cn->findOverriddenProperty(fn); if (sameName && sameName->hasDoc()) { @@ -1272,10 +1284,6 @@ void Generator::generateReimplementsClause(const FunctionNode *fn, CodeMarker *m appendFullName(text, sameName->parent(), fullName, sameName); text << "." << Atom::ParaRight; generateText(text, fn, marker); - } else { - fn->doc().location().warning( - tr("Illegal \\reimp; no documented virtual function for %1") - .arg(fn->plainSignature())); } } } @@ -1346,33 +1354,76 @@ void Generator::generateStatus(const Node *node, CodeMarker *marker) } /*! - Generates a bold line that explains that this is a private signal, - only made public to let users pass it to connect(). - */ -void Generator::generatePrivateSignalNote(const Node *node, CodeMarker *marker) + Generates an addendum note of type \a type for \a node, using \a marker + as the code marker. +*/ +void Generator::generateAddendum(const Node *node, Addendum type, CodeMarker *marker) { + Q_ASSERT(node && !node->name().isEmpty()); Text text; text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) - << "Note: " << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) - << "This is a private signal. It can be used in signal connections but cannot be emitted " - "by the user." - << Atom::ParaRight; - generateText(text, node, marker); -} + << "Note: " << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD); + + switch (type) { + case Invokable: + text << "This function can be invoked via the meta-object system and from QML. See " + << Atom(Atom::Link, "Q_INVOKABLE") + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << "Q_INVOKABLE" + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) << "."; + break; + case PrivateSignal: + text << "This is a private signal. It can be used in signal connections " + "but cannot be emitted by the user."; + break; + case QmlSignalHandler: + { + QString handler(node->name()); + handler[0] = handler[0].toTitleCase(); + handler.prepend(QLatin1String("on")); + text << "The corresponding handler is " + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_TELETYPE) << handler + << Atom(Atom::FormattingRight, ATOM_FORMATTING_TELETYPE) << "."; + break; + } + case AssociatedProperties: + { + if (!node->isFunction()) + return; + const FunctionNode *fn = static_cast<const FunctionNode *>(node); + NodeList nodes = fn->associatedProperties(); + if (nodes.isEmpty()) + return; + std::sort(nodes.begin(), nodes.end(), Node::nodeNameLessThan); + for (const auto *n : qAsConst(nodes)) { + QString msg; + const PropertyNode *pn = static_cast<const PropertyNode *>(n); + switch (pn->role(fn)) { + case PropertyNode::Getter: + msg = QStringLiteral("Getter function"); + break; + case PropertyNode::Setter: + msg = QStringLiteral("Setter function"); + break; + case PropertyNode::Resetter: + msg = QStringLiteral("Resetter function"); + break; + case PropertyNode::Notifier: + msg = QStringLiteral("Notifier signal"); + break; + default: + continue; + } + text << msg << " for property " << Atom(Atom::Link, pn->name()) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << pn->name() + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) << ". "; + } + break; + } + default: + return; + } -/*! - Generates a bold line that says: - "This function can be invoked via the meta-object system and from QML. See Q_INVOKABLE." - */ -void Generator::generateInvokableNote(const Node *node, CodeMarker *marker) -{ - Text text; - text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) - << "Note: " << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) - << "This function can be invoked via the meta-object system and from QML. See " - << Atom(Atom::Link, "Q_INVOKABLE") << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << "Q_INVOKABLE" << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) << "." - << Atom::ParaRight; + text << Atom::ParaRight; generateText(text, node, marker); } @@ -1562,11 +1613,7 @@ QString Generator::getOverloadedSignalCode(const Node *node) } /*! - If the node is an overloaded signal, and a node with an example on how to connect to it - - Someone didn't finish writing this comment, and I don't know what this - function is supposed to do, so I have not tried to complete the comment - yet. + If the node is an overloaded signal, add a node with an example on how to connect to it */ void Generator::generateOverloadedSignal(const Node *node, CodeMarker *marker) { @@ -1690,8 +1737,9 @@ QString Generator::indent(int level, const QString &markedCode) return t; } -void Generator::initialize(const Config &config) +void Generator::initialize() { + Config &config = Config::instance(); outputFormats = config.getOutputFormats(); redirectDocumentationToDevNull_ = config.getBool(CONFIG_REDIRECTDOCUMENTATIONTODEVNULL); @@ -1711,7 +1759,7 @@ void Generator::initialize(const Config &config) for (auto &g : generators) { if (outputFormats.contains(g->format())) { currentGenerator_ = g; - g->initializeGenerator(config); + g->initializeGenerator(); } } @@ -1770,9 +1818,9 @@ void Generator::initialize(const Config &config) Creates template-specific subdirs (e.g. /styles and /scripts for HTML) and copies the files to them. */ -void Generator::copyTemplateFiles(const Config &config, const QString &configVar, - const QString &subDir) +void Generator::copyTemplateFiles(const QString &configVar, const QString &subDir) { + Config &config = Config::instance(); QStringList files = config.getCanonicalPathList(configVar, true); if (!files.isEmpty()) { QDir dirInfo; @@ -1790,12 +1838,13 @@ void Generator::copyTemplateFiles(const Config &config, const QString &configVar } /*! - Reads format-specific variables from \a config, sets output + Reads format-specific variables from config, sets output (sub)directories, creates them on the filesystem and copies the template-specific files. */ -void Generator::initializeFormat(const Config &config) +void Generator::initializeFormat() { + Config &config = Config::instance(); outFileNames_.clear(); useOutputSubdirs_ = true; if (config.getBool(format() + Config::dot + "nosubdirs")) @@ -1814,7 +1863,7 @@ void Generator::initializeFormat(const Config &config) QDir dirInfo; if (dirInfo.exists(outDir_)) { - if (!generating() && Generator::useOutputSubdirs()) { + if (!config.generating() && Generator::useOutputSubdirs()) { if (!Config::removeDirContents(outDir_)) config.lastLocation().error(tr("Cannot empty output directory '%1'").arg(outDir_)); } @@ -1823,16 +1872,16 @@ void Generator::initializeFormat(const Config &config) } // Output directory exists, which is enough for prepare phase. - if (preparing()) + if (config.preparing()) return; if (!dirInfo.exists(outDir_ + "/images") && !dirInfo.mkdir(outDir_ + "/images")) config.lastLocation().fatal( tr("Cannot create images directory '%1'").arg(outDir_ + "/images")); - copyTemplateFiles(config, format() + Config::dot + CONFIG_STYLESHEETS, "style"); - copyTemplateFiles(config, format() + Config::dot + CONFIG_SCRIPTS, "scripts"); - copyTemplateFiles(config, format() + Config::dot + CONFIG_EXTRAIMAGES, "images"); + copyTemplateFiles(format() + Config::dot + CONFIG_STYLESHEETS, "style"); + copyTemplateFiles(format() + Config::dot + CONFIG_SCRIPTS, "scripts"); + copyTemplateFiles(format() + Config::dot + CONFIG_EXTRAIMAGES, "images"); // Use a format-specific .quotinginformation if defined, otherwise a global value if (config.subVars(format()).contains(CONFIG_QUOTINGINFORMATION)) @@ -1856,11 +1905,10 @@ void Generator::augmentImageDirs(QSet<QString> &moreImageDirs) /*! Sets the generator's pointer to the Config instance. */ -void Generator::initializeGenerator(const Config &config) +void Generator::initializeGenerator() { - config_ = &config; - showInternal_ = config.getBool(CONFIG_SHOWINTERNAL); - singleExec_ = config.getBool(CONFIG_SINGLEEXEC); + showInternal_ = Config::instance().getBool(CONFIG_SHOWINTERNAL); + singleExec_ = Config::instance().getBool(CONFIG_SINGLEEXEC); } bool Generator::matchAhead(const Atom *atom, Atom::AtomType expectedAtomType) @@ -2138,8 +2186,8 @@ QString Generator::typeString(const Node *node) case Node::Union: return "union"; case Node::QmlType: - return "type"; case Node::QmlBasicType: + case Node::JsBasicType: return "type"; case Node::Page: return "documentation"; @@ -2171,6 +2219,10 @@ QString Generator::typeString(const Node *node) case Node::JsModule: case Node::QmlModule: return "module"; + case Node::SharedComment: { + const auto &collective = static_cast<const SharedCommentNode *>(node)->collective(); + return collective.first()->nodeTypeString(); + } default: return "documentation"; } |