summaryrefslogtreecommitdiffstats
path: root/src/qdoc/qdoc/src/qdoc/functionnode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qdoc/qdoc/src/qdoc/functionnode.cpp')
-rw-r--r--src/qdoc/qdoc/src/qdoc/functionnode.cpp473
1 files changed, 473 insertions, 0 deletions
diff --git a/src/qdoc/qdoc/src/qdoc/functionnode.cpp b/src/qdoc/qdoc/src/qdoc/functionnode.cpp
new file mode 100644
index 000000000..82933e0ac
--- /dev/null
+++ b/src/qdoc/qdoc/src/qdoc/functionnode.cpp
@@ -0,0 +1,473 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "functionnode.h"
+#include "propertynode.h"
+
+#include <string>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class FunctionNode
+
+ This node is used to represent any kind of function being
+ documented. It can represent a C++ class member function, a C++
+ global function, a QML method, or a macro, with or without
+ parameters.
+
+ A C++ function can be a signal, a slot, a constructor of any
+ kind, a destructor, a copy or move assignment operator, or
+ just a plain old member function or a global function.
+
+ A QML method can be a plain old method, or a
+ signal or signal handler.
+
+ If the function is an overload, its overload flag is
+ true.
+
+ The function node also has an overload number. If the
+ node's overload flag is set, this overload number is
+ positive; otherwise, the overload number is 0.
+ */
+
+/*!
+ Construct a function node for a C++ function. It's parent
+ is \a parent, and it's name is \a name.
+
+ \note The function node's overload flag is set to false, and
+ its overload number is set to 0. These data members are set
+ in normalizeOverloads(), when all the overloads are known.
+ */
+FunctionNode::FunctionNode(Aggregate *parent, const QString &name)
+ : Node(Function, parent, name),
+ m_const(false),
+ m_default(false),
+ m_static(false),
+ m_reimpFlag(false),
+ m_attached(false),
+ m_overloadFlag(false),
+ m_isFinal(false),
+ m_isOverride(false),
+ m_isRef(false),
+ m_isRefRef(false),
+ m_isInvokable(false),
+ m_explicit{false},
+ m_constexpr{false},
+ m_metaness(Plain),
+ m_virtualness(NonVirtual),
+ m_overloadNumber(0)
+{
+ // nothing
+}
+
+/*!
+ Construct a function node for a QML method or signal, specified
+ by ther Metaness value \a type. It's parent is \a parent, and
+ it's name is \a name. If \a attached is true, it is an attached
+ method or signal.
+
+ \note The function node's overload flag is set to false, and
+ its overload number is set to 0. These data members are set
+ in normalizeOverloads(), when all the overloads are known.
+ */
+FunctionNode::FunctionNode(Metaness kind, Aggregate *parent, const QString &name, bool attached)
+ : Node(Function, parent, name),
+ m_const(false),
+ m_default(false),
+ m_static(false),
+ m_reimpFlag(false),
+ m_attached(attached),
+ m_overloadFlag(false),
+ m_isFinal(false),
+ m_isOverride(false),
+ m_isRef(false),
+ m_isRefRef(false),
+ m_isInvokable(false),
+ m_explicit{false},
+ m_constexpr{false},
+ m_metaness(kind),
+ m_virtualness(NonVirtual),
+ m_overloadNumber(0)
+{
+ setGenus(getGenus(m_metaness));
+ if (!isCppNode() && name.startsWith("__"))
+ setStatus(Internal);
+}
+
+/*!
+ Clone this node on the heap and make the clone a child of
+ \a parent. Return the pointer to the clone.
+ */
+Node *FunctionNode::clone(Aggregate *parent)
+{
+ auto *fn = new FunctionNode(*this); // shallow copy
+ fn->setParent(nullptr);
+ parent->addChild(fn);
+ return fn;
+}
+
+/*!
+ Returns this function's virtualness value as a string
+ for use as an attribute value in index files.
+ */
+QString FunctionNode::virtualness() const
+{
+ switch (m_virtualness) {
+ case FunctionNode::NormalVirtual:
+ return QLatin1String("virtual");
+ case FunctionNode::PureVirtual:
+ return QLatin1String("pure");
+ case FunctionNode::NonVirtual:
+ default:
+ break;
+ }
+ return QLatin1String("non");
+}
+
+/*!
+ Sets the function node's virtualness value based on the value
+ of string \a value, which is the value of the function's \e{virtual}
+ attribute in an index file. If \a value is \e{pure}, and if the
+ parent() is a C++ class, set the parent's \e abstract flag to
+ \c {true}.
+ */
+void FunctionNode::setVirtualness(const QString &value)
+{
+ if (value == QLatin1String("pure")) {
+ m_virtualness = PureVirtual;
+ if (parent() && parent()->isClassNode())
+ parent()->setAbstract(true);
+ return;
+ }
+
+ m_virtualness = (value == QLatin1String("virtual")) ? NormalVirtual : NonVirtual;
+}
+
+static QMap<QString, FunctionNode::Metaness> metanessMap_;
+static void buildMetanessMap()
+{
+ metanessMap_["plain"] = FunctionNode::Plain;
+ metanessMap_["signal"] = FunctionNode::Signal;
+ metanessMap_["slot"] = FunctionNode::Slot;
+ metanessMap_["constructor"] = FunctionNode::Ctor;
+ metanessMap_["copy-constructor"] = FunctionNode::CCtor;
+ metanessMap_["move-constructor"] = FunctionNode::MCtor;
+ metanessMap_["destructor"] = FunctionNode::Dtor;
+ metanessMap_["macro"] = FunctionNode::MacroWithParams;
+ metanessMap_["macrowithparams"] = FunctionNode::MacroWithParams;
+ metanessMap_["macrowithoutparams"] = FunctionNode::MacroWithoutParams;
+ metanessMap_["copy-assign"] = FunctionNode::CAssign;
+ metanessMap_["move-assign"] = FunctionNode::MAssign;
+ metanessMap_["native"] = FunctionNode::Native;
+ metanessMap_["qmlsignal"] = FunctionNode::QmlSignal;
+ metanessMap_["qmlsignalhandler"] = FunctionNode::QmlSignalHandler;
+ metanessMap_["qmlmethod"] = FunctionNode::QmlMethod;
+}
+
+static QMap<QString, FunctionNode::Metaness> topicMetanessMap_;
+static void buildTopicMetanessMap()
+{
+ topicMetanessMap_["fn"] = FunctionNode::Plain;
+ topicMetanessMap_["qmlsignal"] = FunctionNode::QmlSignal;
+ topicMetanessMap_["qmlattachedsignal"] = FunctionNode::QmlSignal;
+ topicMetanessMap_["qmlmethod"] = FunctionNode::QmlMethod;
+ topicMetanessMap_["qmlattachedmethod"] = FunctionNode::QmlMethod;
+}
+
+/*!
+ Determines the Genus value for this FunctionNode given the
+ Metaness value \a metaness. Returns the Genus value. \a metaness must be
+ one of the values of Metaness. If not, Node::DontCare is
+ returned.
+ */
+Node::Genus FunctionNode::getGenus(FunctionNode::Metaness metaness)
+{
+ switch (metaness) {
+ case FunctionNode::Plain:
+ case FunctionNode::Signal:
+ case FunctionNode::Slot:
+ case FunctionNode::Ctor:
+ case FunctionNode::Dtor:
+ case FunctionNode::CCtor:
+ case FunctionNode::MCtor:
+ case FunctionNode::MacroWithParams:
+ case FunctionNode::MacroWithoutParams:
+ case FunctionNode::Native:
+ case FunctionNode::CAssign:
+ case FunctionNode::MAssign:
+ return Node::CPP;
+ case FunctionNode::QmlSignal:
+ case FunctionNode::QmlSignalHandler:
+ case FunctionNode::QmlMethod:
+ return Node::QML;
+ }
+
+ return Node::DontCare;
+}
+
+/*!
+ This static function converts the string \a value to an enum
+ value for the kind of function named by \a value.
+ */
+FunctionNode::Metaness FunctionNode::getMetaness(const QString &value)
+{
+ if (metanessMap_.isEmpty())
+ buildMetanessMap();
+ return metanessMap_[value];
+}
+
+/*!
+ This static function converts the topic string \a topic to an enum
+ value for the kind of function this FunctionNode represents.
+ */
+FunctionNode::Metaness FunctionNode::getMetanessFromTopic(const QString &topic)
+{
+ if (topicMetanessMap_.isEmpty())
+ buildTopicMetanessMap();
+ return topicMetanessMap_[topic];
+}
+
+/*!
+ Sets the function node's overload number to \a number. If \a number
+ is 0, the function node's overload flag is set to false. If
+ \a number is greater than 0, the overload flag is set to true.
+ */
+void FunctionNode::setOverloadNumber(signed short number)
+{
+ m_overloadNumber = number;
+ m_overloadFlag = (number > 0);
+}
+
+/*!
+ \fn void FunctionNode::setReimpFlag()
+
+ Sets the function node's reimp flag to \c true, which means
+ the \e {\\reimp} command was used in the qdoc comment. It is
+ supposed to mean that the function reimplements a virtual
+ function in a base class.
+ */
+
+/*!
+ Returns a string representing the kind of function this
+ Function node represents, which depends on the Metaness
+ value.
+ */
+QString FunctionNode::kindString() const
+{
+ switch (m_metaness) {
+ case FunctionNode::QmlSignal:
+ return "QML signal";
+ case FunctionNode::QmlSignalHandler:
+ return "QML signal handler";
+ case FunctionNode::QmlMethod:
+ return "QML method";
+ default:
+ return "function";
+ }
+}
+
+/*!
+ Returns a string representing the Metaness enum value for
+ this function. It is used in index files.
+ */
+QString FunctionNode::metanessString() const
+{
+ switch (m_metaness) {
+ case FunctionNode::Plain:
+ return "plain";
+ case FunctionNode::Signal:
+ return "signal";
+ case FunctionNode::Slot:
+ return "slot";
+ case FunctionNode::Ctor:
+ return "constructor";
+ case FunctionNode::CCtor:
+ return "copy-constructor";
+ case FunctionNode::MCtor:
+ return "move-constructor";
+ case FunctionNode::Dtor:
+ return "destructor";
+ case FunctionNode::MacroWithParams:
+ return "macrowithparams";
+ case FunctionNode::MacroWithoutParams:
+ return "macrowithoutparams";
+ case FunctionNode::Native:
+ return "native";
+ case FunctionNode::CAssign:
+ return "copy-assign";
+ case FunctionNode::MAssign:
+ return "move-assign";
+ case FunctionNode::QmlSignal:
+ return "qmlsignal";
+ case FunctionNode::QmlSignalHandler:
+ return "qmlsignalhandler";
+ case FunctionNode::QmlMethod:
+ return "qmlmethod";
+ default:
+ return "plain";
+ }
+}
+
+/*!
+ Adds the "associated" property \a p to this function node.
+ The function might be the setter or getter for a property,
+ for example.
+ */
+void FunctionNode::addAssociatedProperty(PropertyNode *p)
+{
+ m_associatedProperties.append(p);
+}
+
+/*!
+ \reimp
+
+ Returns \c true if this is an access function for an obsolete property,
+ otherwise calls the base implementation of isDeprecated().
+*/
+bool FunctionNode::isDeprecated() const
+{
+ auto it = std::find_if_not(m_associatedProperties.begin(), m_associatedProperties.end(),
+ [](const Node *p) -> bool { return p->isDeprecated(); });
+
+ if (!m_associatedProperties.isEmpty() && it == m_associatedProperties.end())
+ return true;
+
+ return Node::isDeprecated();
+}
+
+/*! \fn unsigned char FunctionNode::overloadNumber() const
+ Returns the overload number for this function.
+ */
+
+/*!
+ Reconstructs and returns the function's signature.
+
+ Specific parts of the signature are included according to
+ flags in \a options:
+
+ \value Node::SignaturePlain
+ Plain signature
+ \value Node::SignatureDefaultValues
+ Include any default argument values
+ \value Node::SignatureReturnType
+ Include return type
+ \value Node::SignatureTemplateParams
+ Include \c {template <parameter_list>} if one exists
+ */
+QString FunctionNode::signature(Node::SignatureOptions options) const
+{
+ QStringList elements;
+
+ if (options & Node::SignatureTemplateParams && templateDecl())
+ elements << (*templateDecl()).to_qstring();
+ if (options & Node::SignatureReturnType)
+ elements << m_returnType;
+ elements.removeAll(QString());
+
+ if (!isMacroWithoutParams()) {
+ elements << name() + QLatin1Char('(')
+ + m_parameters.signature(options & Node::SignatureDefaultValues)
+ + QLatin1Char(')');
+ if (!isMacro()) {
+ if (isConst())
+ elements << QStringLiteral("const");
+ if (isRef())
+ elements << QStringLiteral("&");
+ else if (isRefRef())
+ elements << QStringLiteral("&&");
+ }
+ } else {
+ elements << name();
+ }
+ return elements.join(QLatin1Char(' '));
+}
+
+/*!
+ \fn int FunctionNode::compare(const FunctionNode *f1, const FunctionNode *f2)
+
+ Compares FunctionNode \a f1 with \a f2, assumed to have identical names.
+ Returns an integer less than, equal to, or greater than zero if f1 is
+ considered less than, equal to, or greater than f2.
+
+ The main purpose is to provide stable ordering for function overloads.
+ */
+[[nodiscard]] int compare(const FunctionNode *f1, const FunctionNode *f2)
+{
+ // Compare parameter count
+ int param_count{f1->parameters().count()};
+
+ if (int param_diff = param_count - f2->parameters().count(); param_diff != 0)
+ return param_diff;
+
+ // Constness
+ if (f1->isConst() != f2->isConst())
+ return f1->isConst() ? 1 : -1;
+
+ // Reference qualifiers
+ if (f1->isRef() != f2->isRef())
+ return f1->isRef() ? 1 : -1;
+ if (f1->isRefRef() != f2->isRefRef())
+ return f1->isRefRef() ? 1 : -1;
+
+ // Attachedness (applies to QML methods)
+ if (f1->isAttached() != f2->isAttached())
+ return f1->isAttached() ? 1 : -1;
+
+ // Parameter types
+ const Parameters &p1{f1->parameters()};
+ const Parameters &p2{f2->parameters()};
+ for (qsizetype i = 0; i < param_count; ++i) {
+ if (int type_comp = QString::compare(p1.at(i).type(), p2.at(i).type());
+ type_comp != 0) {
+ return type_comp;
+ }
+ }
+
+ // Template declarations
+ const auto t1{f1->templateDecl()};
+ const auto t2{f2->templateDecl()};
+ if (!t1 && !t2)
+ return 0;
+
+ if (t1 && t2)
+ return (*t1).to_std_string().compare((*t2).to_std_string());
+
+ return t1 ? 1 : -1;
+}
+
+/*!
+ In some cases, it is ok for a public function to be not documented.
+ For example, the macro Q_OBJECT adds several functions to the API of
+ a class, but these functions are normally not meant to be documented.
+ So if a function node doesn't have documentation, then if its name is
+ in the list of functions that it is ok not to document, this function
+ returns true. Otherwise, it returns false.
+
+ These are the member function names added by macros. Usually they
+ are not documented, but they can be documented, so this test avoids
+ reporting an error if they are not documented.
+
+ But maybe we should generate a standard text for each of them?
+ */
+bool FunctionNode::isIgnored() const
+{
+ if (!hasDoc()) {
+ if (name().startsWith(QLatin1String("qt_")) || name() == QLatin1String("metaObject")
+ || name() == QLatin1String("tr") || name() == QLatin1String("trUtf8")
+ || name() == QLatin1String("d_func")) {
+ return true;
+ }
+ QString s = signature(Node::SignatureReturnType);
+ if (s.contains(QLatin1String("enum_type")) && s.contains(QLatin1String("operator|")))
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \fn bool FunctionNode::hasOverloads() const
+ Returns \c true if this function has overloads.
+ */
+
+QT_END_NAMESPACE