qdoc: Allow formal parameters in link targets
authorMartin Smith <martin.smith@digia.com>
Thu, 6 Aug 2015 11:47:44 +0000 (13:47 +0200)
committerMartin Smith <martin.smith@digia.com>
Sun, 16 Aug 2015 14:47:58 +0000 (14:47 +0000)
This update allows qdoc to handle \l commands for linking
to functions, where the formal parameters are included in
the link target.

For example, \l {QWidget::find(QString name)} will only match
a member function of QWidget that has a single parameter of type
QString. The parameter name is not used in the search.

Change-Id: I8a31c9a7ed632f12a0e6d8a33cbb5cd361098317
Task-number: QTBUG-47286
Reviewed-by: Martin Smith <martin.smith@digia.com>
16 files changed:
src/corelib/tools/qlist.cpp
src/tools/qdoc/codeparser.h
src/tools/qdoc/cppcodemarker.cpp
src/tools/qdoc/cppcodeparser.cpp
src/tools/qdoc/cppcodeparser.h
src/tools/qdoc/doc/qdoc-manual-markupcmds.qdoc
src/tools/qdoc/generator.cpp
src/tools/qdoc/node.cpp
src/tools/qdoc/node.h
src/tools/qdoc/qdocdatabase.cpp
src/tools/qdoc/qdocdatabase.h
src/tools/qdoc/qdocindexfiles.cpp
src/tools/qdoc/qmlvisitor.cpp
src/tools/qdoc/tokenizer.cpp
src/tools/qdoc/tree.cpp
src/tools/qdoc/tree.h

index 509afadfc27a203375be73a6792df1bea24c0823..8ed0da7ca0e9e298ee1a0b61cf5c60fae91508db 100644 (file)
@@ -378,7 +378,7 @@ void **QListData::erase(void **xi)
     references into a QVector and non-heap-allocating QLists.
 
     Internally, QList\<T\> is represented as an array of T if
-    If \c{sizeof(T) <= sizeof(void*)} and T has been declared to be
+    \c{sizeof(T) <= sizeof(void*)} and T has been declared to be
     either a \c{Q_MOVABLE_TYPE} or a \c{Q_PRIMITIVE_TYPE} using
     \l {Q_DECLARE_TYPEINFO}. Otherwise, QList\<T\> is represented
     as an array of T* and the items are allocated on the heap.
index 379deb7e2327013e04d577c22a81b910fd485279..9d9e9286ece11c5e5f14d6851fd78a0cc4fde075 100644 (file)
@@ -40,7 +40,6 @@
 QT_BEGIN_NAMESPACE
 
 class Config;
-class Node;
 class QString;
 class QDocDatabase;
 
index 868b2492905a7abaf904a646a4e0a30ba7741c0f..774ff115b98ead08e7161a2dee5191856daae0f9 100644 (file)
@@ -157,11 +157,11 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node,
             synopsis += "(";
             if (!func->parameters().isEmpty()) {
                 //synopsis += QLatin1Char(' ');
-                QList<Parameter>::ConstIterator p = func->parameters().constBegin();
+                QVector<Parameter>::ConstIterator p = func->parameters().constBegin();
                 while (p != func->parameters().constEnd()) {
                     if (p != func->parameters().constBegin())
                         synopsis += ", ";
-                    synopsis += typified((*p).leftType());
+                    synopsis += typified((*p).dataType());
                     if (style != Subpage && !(*p).name().isEmpty())
                         synopsis +=
                                 "<@param>" + protect((*p).name()) + "</@param>";
@@ -328,11 +328,11 @@ QString CppCodeMarker::markedUpQmlItem(const Node* node, bool summary)
             synopsis = name;
         synopsis += QLatin1Char('(');
         if (!func->parameters().isEmpty()) {
-            QList<Parameter>::ConstIterator p = func->parameters().constBegin();
+            QVector<Parameter>::ConstIterator p = func->parameters().constBegin();
             while (p != func->parameters().constEnd()) {
                 if (p != func->parameters().constBegin())
                     synopsis += ", ";
-                synopsis += typified((*p).leftType());
+                synopsis += typified((*p).dataType());
                 if (!(*p).name().isEmpty()) {
                     if (!synopsis.endsWith(QLatin1Char('(')))
                         synopsis += QLatin1Char(' ');
index cab416370a36d493ae06c75373309b3da56810ae..8d9596c10bb89707bdbf566e640fb72c4659d5c3 100644 (file)
@@ -54,6 +54,7 @@ static bool inMacroCommand_ = false;
 static bool parsingHeaderFile_ = false;
 QStringList CppCodeParser::exampleFiles;
 QStringList CppCodeParser::exampleDirs;
+CppCodeParser* CppCodeParser::cppParser_ = 0;
 
 /*!
   The constructor initializes some regular expressions
@@ -63,6 +64,7 @@ CppCodeParser::CppCodeParser()
     : varComment("/\\*\\s*([a-zA-Z_0-9]+)\\s*\\*/"), sep("(?:<[^>]+>)?::")
 {
     reset();
+    cppParser_ = this;
 }
 
 /*!
@@ -374,12 +376,12 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
             }
             else {
                 func->setMetaness(FunctionNode::MacroWithParams);
-                QList<Parameter> params = func->parameters();
+                QVector<Parameter> params = func->parameters();
                 for (int i = 0; i < params.size(); ++i) {
                     Parameter &param = params[i];
-                    if (param.name().isEmpty() && !param.leftType().isEmpty()
-                            && param.leftType() != "...")
-                        param = Parameter("", "", param.leftType());
+                    if (param.name().isEmpty() && !param.dataType().isEmpty()
+                            && param.dataType() != "...")
+                        param = Parameter("", "", param.dataType());
                 }
                 func->setParameters(params);
             }
@@ -1308,23 +1310,23 @@ bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var)
 
 /*!
   Parse the next function parameter, if there is one, and
-  append it to parameter list \a p. Return true if a parameter
-  is parsed and appended to \a p. Otherwise return false.
+  append it to parameter vector \a pvect. Return true if
+  a parameter is parsed and appended to \a pvect.
+  Otherwise return false.
  */
-bool CppCodeParser::matchParameter(ParsedParameterList& pplist)
+bool CppCodeParser::matchParameter(QVector<Parameter>& pvect, bool& isQPrivateSignal)
 {
-    ParsedParameter pp;
     if (match(Tok_QPrivateSignal)) {
-        pp.qPrivateSignal_ = true;
-        pplist.append(pp);
+        isQPrivateSignal = true;
         return true;
     }
 
+    Parameter p;
     CodeChunk chunk;
-    if (!matchDataType(&chunk, &pp.name_)) {
+    if (!matchDataType(&chunk, &p.name_)) {
         return false;
     }
-    pp.dataType_ = chunk.toString();
+    p.dataType_ = chunk.toString();
     chunk.clear();
     match(Tok_Comment);
     if (match(Tok_Equal)) {
@@ -1336,8 +1338,8 @@ bool CppCodeParser::matchParameter(ParsedParameterList& pplist)
             readToken();
         }
     }
-    pp.defaultValue_ = chunk.toString();
-    pplist.append(pp);
+    p.defaultValue_ = chunk.toString();
+    pvect.append(p);
     return true;
 }
 
@@ -1542,10 +1544,11 @@ bool CppCodeParser::matchFunctionDecl(Aggregate *parent,
     readToken();
 
     // A left paren was seen. Parse the parameters
-    ParsedParameterList pplist;
+    bool isQPrivateSignal = false;
+    QVector<Parameter> pvect;
     if (tok != Tok_RightParen) {
         do {
-            if (!matchParameter(pplist))
+            if (!matchParameter(pvect, isQPrivateSignal))
                 return false;
         } while (match(Tok_Comma));
     }
@@ -1629,13 +1632,10 @@ bool CppCodeParser::matchFunctionDecl(Aggregate *parent,
         func->setStatic(matched_static);
         func->setConst(matchedConst);
         func->setVirtualness(virtuality);
-        if (!pplist.isEmpty()) {
-            foreach (const ParsedParameter& pp, pplist) {
-                if (pp.qPrivateSignal_)
-                    func->setPrivateSignal();
-                else
-                    func->addParameter(Parameter(pp.dataType_, "", pp.name_, pp.defaultValue_));
-            }
+        if (isQPrivateSignal)
+            func->setPrivateSignal();
+        if (!pvect.isEmpty()) {
+            func->setParameters(pvect);
         }
     }
     if (parentPathPtr != 0)
@@ -2416,6 +2416,34 @@ bool CppCodeParser::makeFunctionNode(const QString& signature,
     return ok;
 }
 
+/*!
+  This function uses a Tokenizer to parse the \a parameters of a
+  function into the parameter vector \a {pvect}.
+ */
+bool CppCodeParser::parseParameters(const QString& parameters,
+                                    QVector<Parameter>& pvect,
+                                    bool& isQPrivateSignal)
+{
+    Tokenizer* outerTokenizer = tokenizer;
+    int outerTok = tok;
+
+    QByteArray latin1 = parameters.toLatin1();
+    Tokenizer stringTokenizer(Location(), latin1);
+    stringTokenizer.setParsingFnOrMacro(true);
+    tokenizer = &stringTokenizer;
+    readToken();
+
+    inMacroCommand_ = false;
+    do {
+        if (!matchParameter(pvect, isQPrivateSignal))
+            return false;
+    } while (match(Tok_Comma));
+
+    tokenizer = outerTokenizer;
+    tok = outerTok;
+    return true;
+}
+
 /*!
   Create a new FunctionNode for a QML method or signal, as
   specified by \a type, as a child of \a parent. \a sig is
index 733418e27addfaa595fc6bdfebcdbde292657ec2..ec044823215db4dc2db2c788d99cb01eadd15cfc 100644 (file)
@@ -51,16 +51,6 @@ class CppCodeParser : public CodeParser
 {
     Q_DECLARE_TR_FUNCTIONS(QDoc::CppCodeParser)
 
-    struct ParsedParameter {
-        bool qPrivateSignal_;
-        QString dataType_;
-        QString name_;
-        QString defaultValue_;
-      ParsedParameter() : qPrivateSignal_(false) { }
-    };
-    friend class QTypeInfo<ParsedParameter>;
-    typedef QVector<ParsedParameter> ParsedParameterList;
-
     struct ExtraFuncData {
         Aggregate* root; // Used as the parent.
         Node::NodeType type; // The node type: Function, etc.
@@ -74,6 +64,7 @@ class CppCodeParser : public CodeParser
 public:
     CppCodeParser();
     ~CppCodeParser();
+    static CppCodeParser* cppParser() { return cppParser_; }
 
     virtual void initializeParser(const Config& config) Q_DECL_OVERRIDE;
     virtual void terminateParser() Q_DECL_OVERRIDE;
@@ -84,6 +75,7 @@ public:
     virtual void parseSourceFile(const Location& location, const QString& filePath) Q_DECL_OVERRIDE;
     virtual void doneParsingHeaderFiles() Q_DECL_OVERRIDE;
     virtual void doneParsingSourceFiles() Q_DECL_OVERRIDE;
+    bool parseParameters(const QString& parameters, QVector<Parameter>& pvect, bool& isQPrivateSignal);
 
 protected:
     const QSet<QString>& topicCommands();
@@ -126,7 +118,7 @@ protected:
     bool matchTemplateAngles(CodeChunk *type = 0);
     bool matchTemplateHeader();
     bool matchDataType(CodeChunk *type, QString *var = 0);
-    bool matchParameter(ParsedParameterList& pplist);
+    bool matchParameter(QVector<Parameter>& pvect, bool& isQPrivateSignal);
     bool matchFunctionDecl(Aggregate *parent,
                            QStringList *parentPathPtr,
                            FunctionNode **funcPtr,
@@ -184,10 +176,10 @@ protected:
 
     static QStringList exampleFiles;
     static QStringList exampleDirs;
+    static CppCodeParser* cppParser_;
     QString exampleNameFilter;
     QString exampleImageFilter;
 };
-Q_DECLARE_TYPEINFO(CppCodeParser::ParsedParameter, Q_MOVABLE_TYPE);
 
 #define COMMAND_ABSTRACT                Doc::alias("abstract")
 #define COMMAND_CLASS                   Doc::alias("class")
index 0f9ca463bba3001056978bb88420b76cc2e2e741..49cbfc06545f8420a6f7006a3c57dc652af52ddb 100644 (file)
     \li \c {\l QWidget} - The name of a class documented with the \l
     {class-command} {\\class} command.
 
-    \li \c {\l QWidget::sizeHint()} - The name of a member function,
-    documented with or without an \l {fn-command} {\\fn} command.
+    \li \c {\l QWidget::sizeHint()} - The signature of a function without
+    parameters. If a matching function without parameters can't be found,
+    the link is satisfied with the first matching function found.
+
+    \li \c {\l QWidget::removeAction(QAction* action)} - The signature
+    of a function with parameters. If an exact match is not found, the
+    link is not satisfied and qdoc reports a \e {Can't link to...} error.
 
     \li \c {\l <QtGlobal>} - The subject of a \l {headerfile-command}
     {\\headerfile} command.
index 5153b0de5cb46179725f341de3d39af4afcdfa53..7dfbbb1cb85ba6185e959f917d1de7caf01e2511 100644 (file)
@@ -804,9 +804,9 @@ void Generator::generateBody(const Node *node, CodeMarker *marker)
         else if (node->type() == Node::Function) {
             const FunctionNode *func = static_cast<const FunctionNode *>(node);
             QSet<QString> definedParams;
-            QList<Parameter>::ConstIterator p = func->parameters().constBegin();
+            QVector<Parameter>::ConstIterator p = func->parameters().constBegin();
             while (p != func->parameters().constEnd()) {
-                if ((*p).name().isEmpty() && (*p).leftType() != QLatin1String("...")
+                if ((*p).name().isEmpty() && (*p).dataType() != QLatin1String("...")
                         && func->name() != QLatin1String("operator++")
                         && func->name() != QLatin1String("operator--")) {
                     node->doc().location().warning(tr("Missing parameter name"));
@@ -836,7 +836,7 @@ void Generator::generateBody(const Node *node, CodeMarker *marker)
                     else if (!(*a).isEmpty() && !documentedParams.contains(*a)) {
                         bool needWarning = (func->status() > Node::Obsolete);
                         if (func->overloadNumber() > 0) {
-                            FunctionNode *primaryFunc = func->parent()->findFunctionNode(func->name());
+                            FunctionNode *primaryFunc = func->parent()->findFunctionNode(func->name(), QString());
                             if (primaryFunc) {
                                 foreach (const Parameter &param,
                                          primaryFunc->parameters()) {
@@ -1504,7 +1504,7 @@ void Generator::generateOverloadedSignal(const Node* node, CodeMarker* marker)
         if (i != 0)
             code += ", ";
         const Parameter &p = func->parameters().at(i);
-        code += p.leftType() + p.rightType();
+        code += p.dataType() + p.rightType();
     }
 
     code += ")";
@@ -1516,7 +1516,7 @@ void Generator::generateOverloadedSignal(const Node* node, CodeMarker* marker)
         if (i != 0)
             code += ", ";
         const Parameter &p = func->parameters().at(i);
-        code += p.leftType();
+        code += p.dataType();
         if (code[code.size()-1].isLetterOrNumber())
             code += " ";
         code += p.name()  + p.rightType();
@@ -2049,14 +2049,14 @@ void Generator::supplementAlsoList(const Node *node, QList<Text> &alsoList)
             if (func->name().startsWith("set") && func->name().size() >= 4) {
                 alternateName = func->name()[3].toLower();
                 alternateName += func->name().mid(4);
-                alternateFunc = func->parent()->findFunctionNode(alternateName);
+                alternateFunc = func->parent()->findFunctionNode(alternateName, QString());
 
                 if (!alternateFunc) {
                     alternateName = "is" + func->name().mid(3);
-                    alternateFunc = func->parent()->findFunctionNode(alternateName);
+                    alternateFunc = func->parent()->findFunctionNode(alternateName, QString());
                     if (!alternateFunc) {
                         alternateName = "has" + func->name().mid(3);
-                        alternateFunc = func->parent()->findFunctionNode(alternateName);
+                        alternateFunc = func->parent()->findFunctionNode(alternateName, QString());
                     }
                 }
             }
@@ -2064,7 +2064,7 @@ void Generator::supplementAlsoList(const Node *node, QList<Text> &alsoList)
                 alternateName = "set";
                 alternateName += func->name()[0].toUpper();
                 alternateName += func->name().mid(1);
-                alternateFunc = func->parent()->findFunctionNode(alternateName);
+                alternateFunc = func->parent()->findFunctionNode(alternateName, QString());
             }
 
             if (alternateFunc && alternateFunc->access() != Node::Private) {
index 8646e699a9baded9063c561131debe3bbfa438a3..1ed6820fbf409586fe10d6856545f286b87c01c6 100644 (file)
 #include "node.h"
 #include "tree.h"
 #include "codemarker.h"
-#include "codeparser.h"
+#include "cppcodeparser.h"
 #include <quuid.h>
 #include "qdocdatabase.h"
 #include <qdebug.h>
 #include "generator.h"
+#include "tokenizer.h"
 
 QT_BEGIN_NAMESPACE
 
@@ -810,9 +811,56 @@ Node* Aggregate::findChildNode(const QString& name, NodeType type)
   Find a function node that is a child of this nose, such
   that the function node has the specified \a name.
  */
-FunctionNode *Aggregate::findFunctionNode(const QString& name) const
-{
-    return static_cast<FunctionNode *>(primaryFunctionMap_.value(name));
+FunctionNode *Aggregate::findFunctionNode(const QString& name, const QString& params) const
+{
+    FunctionNode* pfn = static_cast<FunctionNode*>(primaryFunctionMap_.value(name));
+    FunctionNode* fn = pfn;
+    if (fn) {
+        const QVector<Parameter>* funcParams = &(fn->parameters());
+        if (params.isEmpty() && funcParams->isEmpty())
+            return fn;
+        bool isQPrivateSignal = false; // Not used in the search
+        QVector<Parameter> testParams;
+        if (!params.isEmpty()) {
+            CppCodeParser* cppParser = CppCodeParser::cppParser();
+            cppParser->parseParameters(params, testParams, isQPrivateSignal);
+        }
+        NodeList funcs = secondaryFunctionMap_.value(name);
+        int i = -1;
+        while (fn) {
+            if (testParams.size() == funcParams->size()) {
+                if (testParams.isEmpty())
+                    return fn;
+                bool different = false;
+                for (int j=0; j<testParams.size(); j++) {
+                    if (testParams.at(j).dataType() != funcParams->at(j).dataType()) {
+                        different = true;
+                        break;
+                    }
+                }
+                if (!different)
+                    return fn;
+            }
+            if (++i < funcs.size()) {
+                fn = static_cast<FunctionNode*>(funcs.at(i));
+                funcParams = &(fn->parameters());
+            }
+            else
+                fn = 0;
+        }
+        if (!fn && !testParams.empty())
+            return 0;
+    }
+    /*
+      Most \l commands that link to functions don't include
+      the parameter declarations in the function signature,
+      so if the \l is meant to go to a function that does
+      have parameters, the algorithm above won't find it.
+      Therefore we must return the pointer to the function
+      in the primary function map in the cases where the
+      parameters should have been specified in the \l command.
+    */
+    return (fn ? fn : pfn);
 }
 
 /*!
@@ -1090,20 +1138,20 @@ void Aggregate::setIncludes(const QStringList& includes)
  */
 bool Aggregate::isSameSignature(const FunctionNode *f1, const FunctionNode *f2)
 {
-    if (f1->parameters().count() != f2->parameters().count())
+    if (f1->parameters().size() != f2->parameters().size())
         return false;
     if (f1->isConst() != f2->isConst())
         return false;
 
-    QList<Parameter>::ConstIterator p1 = f1->parameters().constBegin();
-    QList<Parameter>::ConstIterator p2 = f2->parameters().constBegin();
+    QVector<Parameter>::ConstIterator p1 = f1->parameters().constBegin();
+    QVector<Parameter>::ConstIterator p2 = f2->parameters().constBegin();
     while (p2 != f2->parameters().constEnd()) {
         if ((*p1).hasType() && (*p2).hasType()) {
             if ((*p1).rightType() != (*p2).rightType())
                 return false;
 
-            QString t1 = p1->leftType();
-            QString t2 = p2->leftType();
+            QString t1 = p1->dataType();
+            QString t2 = p2->dataType();
 
             if (t1.length() < t2.length())
                 qSwap(t1, t2);
@@ -1751,33 +1799,40 @@ void TypedefNode::setAssociatedEnum(const EnumNode *enume)
 
 /*!
   Constructs this parameter from the left and right types
-  \a leftType and rightType, the parameter \a name, and the
+  \a dataType and rightType, the parameter \a name, and the
   \a defaultValue. In practice, \a rightType is not used,
   and I don't know what is was meant for.
  */
-Parameter::Parameter(const QString& leftType,
+Parameter::Parameter(const QString& dataType,
                      const QString& rightType,
                      const QString& name,
                      const QString& defaultValue)
-    : leftType_(leftType), rightType_(rightType), name_(name), defaultValue_(defaultValue)
+    : dataType_(dataType),
+      rightType_(rightType),
+      name_(name),
+      defaultValue_(defaultValue)
 {
+    // nothing.
 }
 
 /*!
-  The standard copy constructor copies the strings from \a p.
+  Standard copy constructor copies \p.
  */
 Parameter::Parameter(const Parameter& p)
-    : leftType_(p.leftType_), rightType_(p.rightType_), name_(p.name_), defaultValue_(p.defaultValue_)
+    : dataType_(p.dataType_),
+      rightType_(p.rightType_),
+      name_(p.name_),
+      defaultValue_(p.defaultValue_)
 {
+    // nothing.
 }
 
 /*!
-  Assigning Parameter \a p to this Parameter copies the
-  strings across.
+  standard assignment operator assigns \p.
  */
 Parameter& Parameter::operator=(const Parameter& p)
 {
-    leftType_ = p.leftType_;
+    dataType_ = p.dataType_;
     rightType_ = p.rightType_;
     name_ = p.name_;
     defaultValue_ = p.defaultValue_;
@@ -1791,7 +1846,7 @@ Parameter& Parameter::operator=(const Parameter& p)
  */
 QString Parameter::reconstruct(bool value) const
 {
-    QString p = leftType_ + rightType_;
+    QString p = dataType_ + rightType_;
     if (!p.endsWith(QChar('*')) && !p.endsWith(QChar('&')) && !p.endsWith(QChar(' ')))
         p += QLatin1Char(' ');
     p += name_;
@@ -1902,8 +1957,8 @@ void FunctionNode::addParameter(const Parameter& parameter)
  */
 void FunctionNode::borrowParameterNames(const FunctionNode *source)
 {
-    QList<Parameter>::Iterator t = parameters_.begin();
-    QList<Parameter>::ConstIterator s = source->parameters_.constBegin();
+    QVector<Parameter>::Iterator t = parameters_.begin();
+    QVector<Parameter>::ConstIterator s = source->parameters_.constBegin();
     while (s != source->parameters_.constEnd() && t != parameters_.end()) {
         if (!(*s).name().isEmpty())
             (*t).setName((*s).name());
@@ -1958,7 +2013,7 @@ bool FunctionNode::hasActiveAssociatedProperty() const
 QStringList FunctionNode::parameterNames() const
 {
     QStringList names;
-    QList<Parameter>::ConstIterator p = parameters().constBegin();
+    QVector<Parameter>::ConstIterator p = parameters().constBegin();
     while (p != parameters().constEnd()) {
         names << (*p).name();
         ++p;
@@ -1975,7 +2030,7 @@ QString FunctionNode::rawParameters(bool names, bool values) const
 {
     QString raw;
     foreach (const Parameter &parameter, parameters()) {
-        raw += parameter.leftType() + parameter.rightType();
+        raw += parameter.dataType() + parameter.rightType();
         if (names)
             raw += parameter.name();
         if (values)
@@ -1991,7 +2046,7 @@ QString FunctionNode::rawParameters(bool names, bool values) const
 QStringList FunctionNode::reconstructParameters(bool values) const
 {
     QStringList reconstructedParameters;
-    QList<Parameter>::ConstIterator p = parameters().constBegin();
+    QVector<Parameter>::ConstIterator p = parameters().constBegin();
     while (p != parameters().constEnd()) {
         reconstructedParameters << (*p).reconstruct(values);
         ++p;
index e9816dad191e1fb3ac31f27b2a0eb22f1e26fdeb..596a71b6d5e2aee83d57a148fe61c7e45a671fa6 100644 (file)
@@ -376,7 +376,7 @@ public:
     Node* findChildNode(const QString& name, Node::Genus genus) const;
     Node* findChildNode(const QString& name, NodeType type);
     virtual void findChildren(const QString& name, NodeList& nodes) const Q_DECL_OVERRIDE;
-    FunctionNode* findFunctionNode(const QString& name) const;
+    FunctionNode* findFunctionNode(const QString& name, const QString& params) const;
     FunctionNode* findFunctionNode(const FunctionNode* clone) const;
     void addInclude(const QString &include);
     void setIncludes(const QStringList &includes);
@@ -815,12 +815,11 @@ inline void EnumNode::setFlagsType(TypedefNode* t)
     t->setAssociatedEnum(this);
 }
 
-
 class Parameter
 {
 public:
     Parameter() {}
-    Parameter(const QString& leftType,
+    Parameter(const QString& dataType,
               const QString& rightType = QString(),
               const QString& name = QString(),
               const QString& defaultValue = QString());
@@ -830,21 +829,24 @@ public:
 
     void setName(const QString& name) { name_ = name; }
 
-    bool hasType() const { return leftType_.length() + rightType_.length() > 0; }
-    const QString& leftType() const { return leftType_; }
+    bool hasType() const { return dataType_.length() + rightType_.length() > 0; }
+    const QString& dataType() const { return dataType_; }
     const QString& rightType() const { return rightType_; }
     const QString& name() const { return name_; }
     const QString& defaultValue() const { return defaultValue_; }
 
     QString reconstruct(bool value = false) const;
 
-private:
-    QString leftType_;
-    QString rightType_;
+ public:
+    QString dataType_;
+    QString rightType_;  // mws says remove this 04/08/2015
     QString name_;
     QString defaultValue_;
 };
 
+//friend class QTypeInfo<Parameter>;
+//Q_DECLARE_TYPEINFO(Parameter, Q_MOVABLE_TYPE);
+
 class FunctionNode : public LeafNode
 {
 public:
@@ -874,7 +876,7 @@ public:
     void setOverloadNumber(unsigned char n) { overloadNumber_ = n; }
     void setReimplemented(bool b);
     void addParameter(const Parameter& parameter);
-    inline void setParameters(const QList<Parameter>& parameters);
+    inline void setParameters(const QVector<Parameter>& parameters);
     void borrowParameterNames(const FunctionNode* source);
     void setReimplementedFrom(FunctionNode* from);
 
@@ -907,7 +909,7 @@ public:
     virtual bool isJsMethod() const Q_DECL_OVERRIDE {
         return (type() == Node::QmlMethod) && (genus() == Node::JS);
     }
-    const QList<Parameter>& parameters() const { return parameters_; }
+    const QVector<Parameter>& parameters() const { return parameters_; }
     void clearParams() { parameters_.clear(); }
     QStringList parameterNames() const;
     QString rawParameters(bool names = false, bool values = false) const;
@@ -957,7 +959,7 @@ private:
     bool privateSignal_: 1;
     bool overload_ : 1;
     unsigned char overloadNumber_;
-    QList<Parameter> parameters_;
+    QVector<Parameter> parameters_;
     const FunctionNode* reimplementedFrom_;
     PropNodeList        associatedProperties_;
     QList<FunctionNode*> reimplementedBy_;
@@ -1030,7 +1032,7 @@ private:
     const PropertyNode* overrides_;
 };
 
-inline void FunctionNode::setParameters(const QList<Parameter> &p)
+inline void FunctionNode::setParameters(const QVector<Parameter> &p)
 {
     parameters_ = p;
 }
index 5f2a61bb7656361c28f5dae831433fc2a8e51001..7f2e64b00c74e2b9f9caac0cb3bbf621d14ff6a1 100644 (file)
@@ -380,6 +380,30 @@ QString QDocForest::getLinkCounts(QStringList& strings, QVector<int>& counts)
     return depends;
 }
 
+/*!
+ */
+const Node* QDocForest::findFunctionNode(const QString& target,
+                                         const Node* relative,
+                                         Node::Genus genus)
+{
+    QString function, params;
+    int length = target.length();
+    if (target.endsWith(QChar(')'))) {
+        int position = target.lastIndexOf(QChar('('));
+        params = target.mid(position+1, length-position-2);
+        function = target.left(position);
+    }
+    else
+        function = target;
+    foreach (Tree* t, searchOrder()) {
+        const Node* n = t->findFunctionNode(function, params, relative, genus);
+        if (n)
+            return n;
+        relative = 0;
+    }
+    return 0;
+}
+
 /*! \class QDocDatabase
   This class provides exclusive access to the qdoc database,
   which consists of a forrest of trees and a lot of maps and
@@ -1342,8 +1366,16 @@ void QDocDatabase::resolveNamespaces()
         }
     }
 }
-
-
+#if 0
+/*!
+ */
+const Node* QDocDatabase::findFunctionNode(const QString& target,
+                                           const Node* relative,
+                                           Node::Genus genus)
+{
+    return forest_.findFunctionNode(target, relative, genus);
+}
+#endif
 /*!
   This function is called for autolinking to a \a type,
   which could be a function return type or a parameter
@@ -1641,6 +1673,8 @@ const Node* QDocDatabase::findNodeForAtom(const Atom* a, const Node* relative, Q
     Atom* atom = const_cast<Atom*>(a);
     QStringList targetPath = atom->string().split("#");
     QString first = targetPath.first().trimmed();
+    if (Generator::debugging())
+        qDebug() << "  first:" << first;
 
     Tree* domain = 0;
     Node::Genus genus = Node::DontCare;
@@ -1659,8 +1693,14 @@ const Node* QDocDatabase::findNodeForAtom(const Atom* a, const Node* relative, Q
     else if (domain) {
         if (first.endsWith(".html"))
             node = domain->findNodeByNameAndType(QStringList(first), Node::Document);
-        else if (first.endsWith("()"))
-            node = domain->findFunctionNode(first, 0, genus);
+        else if (first.endsWith(QChar(')'))) {
+            QString function, params;
+            int length = first.length();
+            int position = first.lastIndexOf(QChar('('));
+            params = first.mid(position+1, length-position-2);
+            function = first.left(position);
+            node = domain->findFunctionNode(function, params, 0, genus);
+        }
         else {
             int flags = SearchBaseClasses | SearchEnumValues;
             QStringList nodePath = first.split("::");
@@ -1683,8 +1723,11 @@ const Node* QDocDatabase::findNodeForAtom(const Atom* a, const Node* relative, Q
             if (!node && first.contains("/"))
                 return findNodeForTarget(targetPath, relative, genus, ref);
         }
-        else if (first.endsWith("()"))
+        else if (first.endsWith(QChar(')'))) {
             node = findFunctionNode(first, relative, genus);
+            if (Generator::debugging())
+                qDebug() << "  node:" << node;
+        }
         else {
             node = findNodeForTarget(targetPath, relative, genus, ref);
             return node;
index 5d55ea48e13ac332ecca3a36b7d895ee67426d69..80a92af4edeaa614a91a35d59336be62bb14af2d 100644 (file)
@@ -141,15 +141,8 @@ class QDocForest
 
     const Node* findFunctionNode(const QString& target,
                                  const Node* relative,
-                                 Node::Genus genus) {
-        foreach (Tree* t, searchOrder()) {
-            const Node* n = t->findFunctionNode(target, relative, genus);
-            if (n)
-                return n;
-            relative = 0;
-        }
-        return 0;
-    }
+                                 Node::Genus genus);
+
     const Node* findNodeForTarget(QStringList& targetPath,
                                   const Node* relative,
                                   Node::Genus genus,
index 37194b911c179b22cd88adbbafbeb12bc6648a13..8db901bbc78c2d8d3837a21c92501ee1bc54cf36 100644 (file)
@@ -1238,7 +1238,7 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
             for (int i = 0; i < functionNode->parameters().size(); ++i) {
                 Parameter parameter = functionNode->parameters()[i];
                 writer.writeStartElement("parameter");
-                writer.writeAttribute("left", parameter.leftType());
+                writer.writeAttribute("left", parameter.dataType());
                 writer.writeAttribute("right", parameter.rightType());
                 writer.writeAttribute("name", parameter.name());
                 writer.writeAttribute("default", parameter.defaultValue());
index 6f63624bf03ae14f0b9764b8100b441787cd2207..155e1de054a4859fd7579de1aed053673b26e663 100644 (file)
@@ -675,7 +675,7 @@ bool QmlDocVisitor::visit(QQmlJS::AST::UiPublicMember *member)
                 QString name = member->name.toString();
                 FunctionNode *qmlSignal = new FunctionNode(Node::QmlSignal, current, name, false);
 
-                QList<Parameter> parameters;
+                QVector<Parameter> parameters;
                 for (QQmlJS::AST::UiParameterList *it = member->parameters; it; it = it->next) {
                     if (!it->type.isEmpty() && !it->name.isEmpty())
                         parameters.append(Parameter(it->type.toString(), QString(), it->name.toString()));
@@ -754,7 +754,7 @@ bool QmlDocVisitor::visit(QQmlJS::AST::FunctionDeclaration* fd)
             }
             if (overloads > 1)
                 qmlMethod->setOverloadFlag(true);
-            QList<Parameter> parameters;
+            QVector<Parameter> parameters;
             QQmlJS::AST::FormalParameterList* formals = fd->formals;
             if (formals) {
                 QQmlJS::AST::FormalParameterList* fpl = formals;
index a85c3b00d83cec38e718f085b6536ae857c74c4b..987fff548c741b34e1fe41449ca6f3469df34571 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "config.h"
 #include "tokenizer.h"
+#include "generator.h"
 
 #include <qfile.h>
 #include <qhash.h>
index e0fd68d2e70f8bd4f1b10ec35dab5efd3ae185aa..d64903e61ed21d08c51f066f202107cfff9667e3 100644 (file)
@@ -220,6 +220,7 @@ QmlTypeNode* Tree::findQmlTypeNode(const QStringList& path)
   used as the starting point.
  */
 const FunctionNode* Tree::findFunctionNode(const QStringList& path,
+                                           const QString& params,
                                            const Node* relative,
                                            int findFlags,
                                            Node::Genus genus) const
@@ -234,7 +235,7 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path,
                 qcn = static_cast<QmlTypeNode*>(n);
         }
         if (qcn)
-            return static_cast<const FunctionNode*>(qcn->findFunctionNode(path[2]));
+            return static_cast<const FunctionNode*>(qcn->findFunctionNode(path[2], params));
     }
 
     if (!relative)
@@ -254,7 +255,7 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path,
 
             const Node* next;
             if (i == path.size() - 1)
-                next = ((const Aggregate*) node)->findFunctionNode(path.at(i));
+                next = ((const Aggregate*) node)->findFunctionNode(path.at(i), params);
             else
                 next = ((const Aggregate*) node)->findChildNode(path.at(i), genus);
 
@@ -262,7 +263,7 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path,
                 NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node));
                 foreach (const Node* baseClass, baseClasses) {
                     if (i == path.size() - 1)
-                        next = static_cast<const Aggregate*>(baseClass)->findFunctionNode(path.at(i));
+                        next = static_cast<const Aggregate*>(baseClass)->findFunctionNode(path.at(i), params);
                     else
                         next = static_cast<const Aggregate*>(baseClass)->findChildNode(path.at(i), genus);
 
@@ -1452,13 +1453,17 @@ void Tree::insertQmlType(const QString& key, QmlTypeNode* n)
   Split \a target on "::" and find the function node with that
   path.
  */
-const Node* Tree::findFunctionNode(const QString& target, const Node* relative, Node::Genus genus)
+const Node* Tree::findFunctionNode(const QString& target,
+                                   const QString& params,
+                                   const Node* relative,
+                                   Node::Genus genus) const
 {
     QString t = target;
-    if (t.endsWith("()"))
+    if (t.endsWith("()")) {
         t.chop(2);
+    }
     QStringList path = t.split("::");
-    const FunctionNode* fn = findFunctionNode(path, relative, SearchBaseClasses, genus);
+    const FunctionNode* fn = findFunctionNode(path, params, relative, SearchBaseClasses, genus);
     if (fn && fn->metaness() != FunctionNode::MacroWithoutParams)
         return fn;
     return 0;
index 9e195c90ae27bd7808d854a95aa79997eff618c4..1fef15bc6d8774b9bbe16cdaf2e25fcd6a19a984 100644 (file)
@@ -107,7 +107,10 @@ class Tree
     ClassNode* findClassNode(const QStringList& path, const Node* start = 0) const;
     NamespaceNode* findNamespaceNode(const QStringList& path) const;
     FunctionNode* findFunctionNode(const QStringList& parentPath, const FunctionNode* clone);
-    const Node* findFunctionNode(const QString& target, const Node* relative, Node::Genus genus);
+    const Node* findFunctionNode(const QString& target,
+                                 const QString& params,
+                                 const Node* relative,
+                                 Node::Genus genus) const;
 
     Node* findNodeRecursive(const QStringList& path,
                             int pathIndex,
@@ -163,6 +166,7 @@ class Tree
     NamespaceNode *root() { return &root_; }
 
     const FunctionNode *findFunctionNode(const QStringList &path,
+                                         const QString& params,
                                          const Node *relative = 0,
                                          int findFlags = 0,
                                          Node::Genus genus = Node::DontCare) const;