qdoc: Allow formal parameters in link targets

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>
This commit is contained in:
Martin Smith 2015-08-06 13:47:44 +02:00
parent 6dde874c32
commit 8c5ce68fcf
16 changed files with 237 additions and 110 deletions

View File

@ -378,7 +378,7 @@ void **QListData::erase(void **xi)
references into a QVector and non-heap-allocating QLists. references into a QVector and non-heap-allocating QLists.
Internally, QList\<T\> is represented as an array of T if 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 either a \c{Q_MOVABLE_TYPE} or a \c{Q_PRIMITIVE_TYPE} using
\l {Q_DECLARE_TYPEINFO}. Otherwise, QList\<T\> is represented \l {Q_DECLARE_TYPEINFO}. Otherwise, QList\<T\> is represented
as an array of T* and the items are allocated on the heap. as an array of T* and the items are allocated on the heap.

View File

@ -40,7 +40,6 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class Config; class Config;
class Node;
class QString; class QString;
class QDocDatabase; class QDocDatabase;

View File

@ -157,11 +157,11 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node,
synopsis += "("; synopsis += "(";
if (!func->parameters().isEmpty()) { if (!func->parameters().isEmpty()) {
//synopsis += QLatin1Char(' '); //synopsis += QLatin1Char(' ');
QList<Parameter>::ConstIterator p = func->parameters().constBegin(); QVector<Parameter>::ConstIterator p = func->parameters().constBegin();
while (p != func->parameters().constEnd()) { while (p != func->parameters().constEnd()) {
if (p != func->parameters().constBegin()) if (p != func->parameters().constBegin())
synopsis += ", "; synopsis += ", ";
synopsis += typified((*p).leftType()); synopsis += typified((*p).dataType());
if (style != Subpage && !(*p).name().isEmpty()) if (style != Subpage && !(*p).name().isEmpty())
synopsis += synopsis +=
"<@param>" + protect((*p).name()) + "</@param>"; "<@param>" + protect((*p).name()) + "</@param>";
@ -328,11 +328,11 @@ QString CppCodeMarker::markedUpQmlItem(const Node* node, bool summary)
synopsis = name; synopsis = name;
synopsis += QLatin1Char('('); synopsis += QLatin1Char('(');
if (!func->parameters().isEmpty()) { if (!func->parameters().isEmpty()) {
QList<Parameter>::ConstIterator p = func->parameters().constBegin(); QVector<Parameter>::ConstIterator p = func->parameters().constBegin();
while (p != func->parameters().constEnd()) { while (p != func->parameters().constEnd()) {
if (p != func->parameters().constBegin()) if (p != func->parameters().constBegin())
synopsis += ", "; synopsis += ", ";
synopsis += typified((*p).leftType()); synopsis += typified((*p).dataType());
if (!(*p).name().isEmpty()) { if (!(*p).name().isEmpty()) {
if (!synopsis.endsWith(QLatin1Char('('))) if (!synopsis.endsWith(QLatin1Char('(')))
synopsis += QLatin1Char(' '); synopsis += QLatin1Char(' ');

View File

@ -54,6 +54,7 @@ static bool inMacroCommand_ = false;
static bool parsingHeaderFile_ = false; static bool parsingHeaderFile_ = false;
QStringList CppCodeParser::exampleFiles; QStringList CppCodeParser::exampleFiles;
QStringList CppCodeParser::exampleDirs; QStringList CppCodeParser::exampleDirs;
CppCodeParser* CppCodeParser::cppParser_ = 0;
/*! /*!
The constructor initializes some regular expressions The constructor initializes some regular expressions
@ -63,6 +64,7 @@ CppCodeParser::CppCodeParser()
: varComment("/\\*\\s*([a-zA-Z_0-9]+)\\s*\\*/"), sep("(?:<[^>]+>)?::") : varComment("/\\*\\s*([a-zA-Z_0-9]+)\\s*\\*/"), sep("(?:<[^>]+>)?::")
{ {
reset(); reset();
cppParser_ = this;
} }
/*! /*!
@ -374,12 +376,12 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
} }
else { else {
func->setMetaness(FunctionNode::MacroWithParams); func->setMetaness(FunctionNode::MacroWithParams);
QList<Parameter> params = func->parameters(); QVector<Parameter> params = func->parameters();
for (int i = 0; i < params.size(); ++i) { for (int i = 0; i < params.size(); ++i) {
Parameter &param = params[i]; Parameter &param = params[i];
if (param.name().isEmpty() && !param.leftType().isEmpty() if (param.name().isEmpty() && !param.dataType().isEmpty()
&& param.leftType() != "...") && param.dataType() != "...")
param = Parameter("", "", param.leftType()); param = Parameter("", "", param.dataType());
} }
func->setParameters(params); func->setParameters(params);
} }
@ -1308,23 +1310,23 @@ bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var)
/*! /*!
Parse the next function parameter, if there is one, and Parse the next function parameter, if there is one, and
append it to parameter list \a p. Return true if a parameter append it to parameter vector \a pvect. Return true if
is parsed and appended to \a p. Otherwise return false. 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)) { if (match(Tok_QPrivateSignal)) {
pp.qPrivateSignal_ = true; isQPrivateSignal = true;
pplist.append(pp);
return true; return true;
} }
Parameter p;
CodeChunk chunk; CodeChunk chunk;
if (!matchDataType(&chunk, &pp.name_)) { if (!matchDataType(&chunk, &p.name_)) {
return false; return false;
} }
pp.dataType_ = chunk.toString(); p.dataType_ = chunk.toString();
chunk.clear(); chunk.clear();
match(Tok_Comment); match(Tok_Comment);
if (match(Tok_Equal)) { if (match(Tok_Equal)) {
@ -1336,8 +1338,8 @@ bool CppCodeParser::matchParameter(ParsedParameterList& pplist)
readToken(); readToken();
} }
} }
pp.defaultValue_ = chunk.toString(); p.defaultValue_ = chunk.toString();
pplist.append(pp); pvect.append(p);
return true; return true;
} }
@ -1542,10 +1544,11 @@ bool CppCodeParser::matchFunctionDecl(Aggregate *parent,
readToken(); readToken();
// A left paren was seen. Parse the parameters // A left paren was seen. Parse the parameters
ParsedParameterList pplist; bool isQPrivateSignal = false;
QVector<Parameter> pvect;
if (tok != Tok_RightParen) { if (tok != Tok_RightParen) {
do { do {
if (!matchParameter(pplist)) if (!matchParameter(pvect, isQPrivateSignal))
return false; return false;
} while (match(Tok_Comma)); } while (match(Tok_Comma));
} }
@ -1629,13 +1632,10 @@ bool CppCodeParser::matchFunctionDecl(Aggregate *parent,
func->setStatic(matched_static); func->setStatic(matched_static);
func->setConst(matchedConst); func->setConst(matchedConst);
func->setVirtualness(virtuality); func->setVirtualness(virtuality);
if (!pplist.isEmpty()) { if (isQPrivateSignal)
foreach (const ParsedParameter& pp, pplist) {
if (pp.qPrivateSignal_)
func->setPrivateSignal(); func->setPrivateSignal();
else if (!pvect.isEmpty()) {
func->addParameter(Parameter(pp.dataType_, "", pp.name_, pp.defaultValue_)); func->setParameters(pvect);
}
} }
} }
if (parentPathPtr != 0) if (parentPathPtr != 0)
@ -2416,6 +2416,34 @@ bool CppCodeParser::makeFunctionNode(const QString& signature,
return ok; 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 Create a new FunctionNode for a QML method or signal, as
specified by \a type, as a child of \a parent. \a sig is specified by \a type, as a child of \a parent. \a sig is

View File

@ -51,16 +51,6 @@ class CppCodeParser : public CodeParser
{ {
Q_DECLARE_TR_FUNCTIONS(QDoc::CppCodeParser) 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 { struct ExtraFuncData {
Aggregate* root; // Used as the parent. Aggregate* root; // Used as the parent.
Node::NodeType type; // The node type: Function, etc. Node::NodeType type; // The node type: Function, etc.
@ -74,6 +64,7 @@ class CppCodeParser : public CodeParser
public: public:
CppCodeParser(); CppCodeParser();
~CppCodeParser(); ~CppCodeParser();
static CppCodeParser* cppParser() { return cppParser_; }
virtual void initializeParser(const Config& config) Q_DECL_OVERRIDE; virtual void initializeParser(const Config& config) Q_DECL_OVERRIDE;
virtual void terminateParser() 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 parseSourceFile(const Location& location, const QString& filePath) Q_DECL_OVERRIDE;
virtual void doneParsingHeaderFiles() Q_DECL_OVERRIDE; virtual void doneParsingHeaderFiles() Q_DECL_OVERRIDE;
virtual void doneParsingSourceFiles() Q_DECL_OVERRIDE; virtual void doneParsingSourceFiles() Q_DECL_OVERRIDE;
bool parseParameters(const QString& parameters, QVector<Parameter>& pvect, bool& isQPrivateSignal);
protected: protected:
const QSet<QString>& topicCommands(); const QSet<QString>& topicCommands();
@ -126,7 +118,7 @@ protected:
bool matchTemplateAngles(CodeChunk *type = 0); bool matchTemplateAngles(CodeChunk *type = 0);
bool matchTemplateHeader(); bool matchTemplateHeader();
bool matchDataType(CodeChunk *type, QString *var = 0); bool matchDataType(CodeChunk *type, QString *var = 0);
bool matchParameter(ParsedParameterList& pplist); bool matchParameter(QVector<Parameter>& pvect, bool& isQPrivateSignal);
bool matchFunctionDecl(Aggregate *parent, bool matchFunctionDecl(Aggregate *parent,
QStringList *parentPathPtr, QStringList *parentPathPtr,
FunctionNode **funcPtr, FunctionNode **funcPtr,
@ -184,10 +176,10 @@ protected:
static QStringList exampleFiles; static QStringList exampleFiles;
static QStringList exampleDirs; static QStringList exampleDirs;
static CppCodeParser* cppParser_;
QString exampleNameFilter; QString exampleNameFilter;
QString exampleImageFilter; QString exampleImageFilter;
}; };
Q_DECLARE_TYPEINFO(CppCodeParser::ParsedParameter, Q_MOVABLE_TYPE);
#define COMMAND_ABSTRACT Doc::alias("abstract") #define COMMAND_ABSTRACT Doc::alias("abstract")
#define COMMAND_CLASS Doc::alias("class") #define COMMAND_CLASS Doc::alias("class")

View File

@ -1839,8 +1839,13 @@
\li \c {\l QWidget} - The name of a class documented with the \l \li \c {\l QWidget} - The name of a class documented with the \l
{class-command} {\\class} command. {class-command} {\\class} command.
\li \c {\l QWidget::sizeHint()} - The name of a member function, \li \c {\l QWidget::sizeHint()} - The signature of a function without
documented with or without an \l {fn-command} {\\fn} command. 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} \li \c {\l <QtGlobal>} - The subject of a \l {headerfile-command}
{\\headerfile} command. {\\headerfile} command.

View File

@ -804,9 +804,9 @@ void Generator::generateBody(const Node *node, CodeMarker *marker)
else if (node->type() == Node::Function) { else if (node->type() == Node::Function) {
const FunctionNode *func = static_cast<const FunctionNode *>(node); const FunctionNode *func = static_cast<const FunctionNode *>(node);
QSet<QString> definedParams; QSet<QString> definedParams;
QList<Parameter>::ConstIterator p = func->parameters().constBegin(); QVector<Parameter>::ConstIterator p = func->parameters().constBegin();
while (p != func->parameters().constEnd()) { 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++")
&& func->name() != QLatin1String("operator--")) { && func->name() != QLatin1String("operator--")) {
node->doc().location().warning(tr("Missing parameter name")); 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)) { else if (!(*a).isEmpty() && !documentedParams.contains(*a)) {
bool needWarning = (func->status() > Node::Obsolete); bool needWarning = (func->status() > Node::Obsolete);
if (func->overloadNumber() > 0) { if (func->overloadNumber() > 0) {
FunctionNode *primaryFunc = func->parent()->findFunctionNode(func->name()); FunctionNode *primaryFunc = func->parent()->findFunctionNode(func->name(), QString());
if (primaryFunc) { if (primaryFunc) {
foreach (const Parameter &param, foreach (const Parameter &param,
primaryFunc->parameters()) { primaryFunc->parameters()) {
@ -1504,7 +1504,7 @@ void Generator::generateOverloadedSignal(const Node* node, CodeMarker* marker)
if (i != 0) if (i != 0)
code += ", "; code += ", ";
const Parameter &p = func->parameters().at(i); const Parameter &p = func->parameters().at(i);
code += p.leftType() + p.rightType(); code += p.dataType() + p.rightType();
} }
code += ")"; code += ")";
@ -1516,7 +1516,7 @@ void Generator::generateOverloadedSignal(const Node* node, CodeMarker* marker)
if (i != 0) if (i != 0)
code += ", "; code += ", ";
const Parameter &p = func->parameters().at(i); const Parameter &p = func->parameters().at(i);
code += p.leftType(); code += p.dataType();
if (code[code.size()-1].isLetterOrNumber()) if (code[code.size()-1].isLetterOrNumber())
code += " "; code += " ";
code += p.name() + p.rightType(); 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) { if (func->name().startsWith("set") && func->name().size() >= 4) {
alternateName = func->name()[3].toLower(); alternateName = func->name()[3].toLower();
alternateName += func->name().mid(4); alternateName += func->name().mid(4);
alternateFunc = func->parent()->findFunctionNode(alternateName); alternateFunc = func->parent()->findFunctionNode(alternateName, QString());
if (!alternateFunc) { if (!alternateFunc) {
alternateName = "is" + func->name().mid(3); alternateName = "is" + func->name().mid(3);
alternateFunc = func->parent()->findFunctionNode(alternateName); alternateFunc = func->parent()->findFunctionNode(alternateName, QString());
if (!alternateFunc) { if (!alternateFunc) {
alternateName = "has" + func->name().mid(3); 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 = "set";
alternateName += func->name()[0].toUpper(); alternateName += func->name()[0].toUpper();
alternateName += func->name().mid(1); alternateName += func->name().mid(1);
alternateFunc = func->parent()->findFunctionNode(alternateName); alternateFunc = func->parent()->findFunctionNode(alternateName, QString());
} }
if (alternateFunc && alternateFunc->access() != Node::Private) { if (alternateFunc && alternateFunc->access() != Node::Private) {

View File

@ -34,11 +34,12 @@
#include "node.h" #include "node.h"
#include "tree.h" #include "tree.h"
#include "codemarker.h" #include "codemarker.h"
#include "codeparser.h" #include "cppcodeparser.h"
#include <quuid.h> #include <quuid.h>
#include "qdocdatabase.h" #include "qdocdatabase.h"
#include <qdebug.h> #include <qdebug.h>
#include "generator.h" #include "generator.h"
#include "tokenizer.h"
QT_BEGIN_NAMESPACE 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 Find a function node that is a child of this nose, such
that the function node has the specified \a name. that the function node has the specified \a name.
*/ */
FunctionNode *Aggregate::findFunctionNode(const QString& name) const FunctionNode *Aggregate::findFunctionNode(const QString& name, const QString& params) const
{ {
return static_cast<FunctionNode *>(primaryFunctionMap_.value(name)); 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) 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; return false;
if (f1->isConst() != f2->isConst()) if (f1->isConst() != f2->isConst())
return false; return false;
QList<Parameter>::ConstIterator p1 = f1->parameters().constBegin(); QVector<Parameter>::ConstIterator p1 = f1->parameters().constBegin();
QList<Parameter>::ConstIterator p2 = f2->parameters().constBegin(); QVector<Parameter>::ConstIterator p2 = f2->parameters().constBegin();
while (p2 != f2->parameters().constEnd()) { while (p2 != f2->parameters().constEnd()) {
if ((*p1).hasType() && (*p2).hasType()) { if ((*p1).hasType() && (*p2).hasType()) {
if ((*p1).rightType() != (*p2).rightType()) if ((*p1).rightType() != (*p2).rightType())
return false; return false;
QString t1 = p1->leftType(); QString t1 = p1->dataType();
QString t2 = p2->leftType(); QString t2 = p2->dataType();
if (t1.length() < t2.length()) if (t1.length() < t2.length())
qSwap(t1, t2); qSwap(t1, t2);
@ -1751,33 +1799,40 @@ void TypedefNode::setAssociatedEnum(const EnumNode *enume)
/*! /*!
Constructs this parameter from the left and right types 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, \a defaultValue. In practice, \a rightType is not used,
and I don't know what is was meant for. 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& rightType,
const QString& name, const QString& name,
const QString& defaultValue) 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) 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 standard assignment operator assigns \p.
strings across.
*/ */
Parameter& Parameter::operator=(const Parameter& p) Parameter& Parameter::operator=(const Parameter& p)
{ {
leftType_ = p.leftType_; dataType_ = p.dataType_;
rightType_ = p.rightType_; rightType_ = p.rightType_;
name_ = p.name_; name_ = p.name_;
defaultValue_ = p.defaultValue_; defaultValue_ = p.defaultValue_;
@ -1791,7 +1846,7 @@ Parameter& Parameter::operator=(const Parameter& p)
*/ */
QString Parameter::reconstruct(bool value) const QString Parameter::reconstruct(bool value) const
{ {
QString p = leftType_ + rightType_; QString p = dataType_ + rightType_;
if (!p.endsWith(QChar('*')) && !p.endsWith(QChar('&')) && !p.endsWith(QChar(' '))) if (!p.endsWith(QChar('*')) && !p.endsWith(QChar('&')) && !p.endsWith(QChar(' ')))
p += QLatin1Char(' '); p += QLatin1Char(' ');
p += name_; p += name_;
@ -1902,8 +1957,8 @@ void FunctionNode::addParameter(const Parameter& parameter)
*/ */
void FunctionNode::borrowParameterNames(const FunctionNode *source) void FunctionNode::borrowParameterNames(const FunctionNode *source)
{ {
QList<Parameter>::Iterator t = parameters_.begin(); QVector<Parameter>::Iterator t = parameters_.begin();
QList<Parameter>::ConstIterator s = source->parameters_.constBegin(); QVector<Parameter>::ConstIterator s = source->parameters_.constBegin();
while (s != source->parameters_.constEnd() && t != parameters_.end()) { while (s != source->parameters_.constEnd() && t != parameters_.end()) {
if (!(*s).name().isEmpty()) if (!(*s).name().isEmpty())
(*t).setName((*s).name()); (*t).setName((*s).name());
@ -1958,7 +2013,7 @@ bool FunctionNode::hasActiveAssociatedProperty() const
QStringList FunctionNode::parameterNames() const QStringList FunctionNode::parameterNames() const
{ {
QStringList names; QStringList names;
QList<Parameter>::ConstIterator p = parameters().constBegin(); QVector<Parameter>::ConstIterator p = parameters().constBegin();
while (p != parameters().constEnd()) { while (p != parameters().constEnd()) {
names << (*p).name(); names << (*p).name();
++p; ++p;
@ -1975,7 +2030,7 @@ QString FunctionNode::rawParameters(bool names, bool values) const
{ {
QString raw; QString raw;
foreach (const Parameter &parameter, parameters()) { foreach (const Parameter &parameter, parameters()) {
raw += parameter.leftType() + parameter.rightType(); raw += parameter.dataType() + parameter.rightType();
if (names) if (names)
raw += parameter.name(); raw += parameter.name();
if (values) if (values)
@ -1991,7 +2046,7 @@ QString FunctionNode::rawParameters(bool names, bool values) const
QStringList FunctionNode::reconstructParameters(bool values) const QStringList FunctionNode::reconstructParameters(bool values) const
{ {
QStringList reconstructedParameters; QStringList reconstructedParameters;
QList<Parameter>::ConstIterator p = parameters().constBegin(); QVector<Parameter>::ConstIterator p = parameters().constBegin();
while (p != parameters().constEnd()) { while (p != parameters().constEnd()) {
reconstructedParameters << (*p).reconstruct(values); reconstructedParameters << (*p).reconstruct(values);
++p; ++p;

View File

@ -376,7 +376,7 @@ public:
Node* findChildNode(const QString& name, Node::Genus genus) const; Node* findChildNode(const QString& name, Node::Genus genus) const;
Node* findChildNode(const QString& name, NodeType type); Node* findChildNode(const QString& name, NodeType type);
virtual void findChildren(const QString& name, NodeList& nodes) const Q_DECL_OVERRIDE; 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; FunctionNode* findFunctionNode(const FunctionNode* clone) const;
void addInclude(const QString &include); void addInclude(const QString &include);
void setIncludes(const QStringList &includes); void setIncludes(const QStringList &includes);
@ -815,12 +815,11 @@ inline void EnumNode::setFlagsType(TypedefNode* t)
t->setAssociatedEnum(this); t->setAssociatedEnum(this);
} }
class Parameter class Parameter
{ {
public: public:
Parameter() {} Parameter() {}
Parameter(const QString& leftType, Parameter(const QString& dataType,
const QString& rightType = QString(), const QString& rightType = QString(),
const QString& name = QString(), const QString& name = QString(),
const QString& defaultValue = QString()); const QString& defaultValue = QString());
@ -830,21 +829,24 @@ public:
void setName(const QString& name) { name_ = name; } void setName(const QString& name) { name_ = name; }
bool hasType() const { return leftType_.length() + rightType_.length() > 0; } bool hasType() const { return dataType_.length() + rightType_.length() > 0; }
const QString& leftType() const { return leftType_; } const QString& dataType() const { return dataType_; }
const QString& rightType() const { return rightType_; } const QString& rightType() const { return rightType_; }
const QString& name() const { return name_; } const QString& name() const { return name_; }
const QString& defaultValue() const { return defaultValue_; } const QString& defaultValue() const { return defaultValue_; }
QString reconstruct(bool value = false) const; QString reconstruct(bool value = false) const;
private: public:
QString leftType_; QString dataType_;
QString rightType_; QString rightType_; // mws says remove this 04/08/2015
QString name_; QString name_;
QString defaultValue_; QString defaultValue_;
}; };
//friend class QTypeInfo<Parameter>;
//Q_DECLARE_TYPEINFO(Parameter, Q_MOVABLE_TYPE);
class FunctionNode : public LeafNode class FunctionNode : public LeafNode
{ {
public: public:
@ -874,7 +876,7 @@ public:
void setOverloadNumber(unsigned char n) { overloadNumber_ = n; } void setOverloadNumber(unsigned char n) { overloadNumber_ = n; }
void setReimplemented(bool b); void setReimplemented(bool b);
void addParameter(const Parameter& parameter); 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 borrowParameterNames(const FunctionNode* source);
void setReimplementedFrom(FunctionNode* from); void setReimplementedFrom(FunctionNode* from);
@ -907,7 +909,7 @@ public:
virtual bool isJsMethod() const Q_DECL_OVERRIDE { virtual bool isJsMethod() const Q_DECL_OVERRIDE {
return (type() == Node::QmlMethod) && (genus() == Node::JS); 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(); } void clearParams() { parameters_.clear(); }
QStringList parameterNames() const; QStringList parameterNames() const;
QString rawParameters(bool names = false, bool values = false) const; QString rawParameters(bool names = false, bool values = false) const;
@ -957,7 +959,7 @@ private:
bool privateSignal_: 1; bool privateSignal_: 1;
bool overload_ : 1; bool overload_ : 1;
unsigned char overloadNumber_; unsigned char overloadNumber_;
QList<Parameter> parameters_; QVector<Parameter> parameters_;
const FunctionNode* reimplementedFrom_; const FunctionNode* reimplementedFrom_;
PropNodeList associatedProperties_; PropNodeList associatedProperties_;
QList<FunctionNode*> reimplementedBy_; QList<FunctionNode*> reimplementedBy_;
@ -1030,7 +1032,7 @@ private:
const PropertyNode* overrides_; const PropertyNode* overrides_;
}; };
inline void FunctionNode::setParameters(const QList<Parameter> &p) inline void FunctionNode::setParameters(const QVector<Parameter> &p)
{ {
parameters_ = p; parameters_ = p;
} }

View File

@ -380,6 +380,30 @@ QString QDocForest::getLinkCounts(QStringList& strings, QVector<int>& counts)
return depends; 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 /*! \class QDocDatabase
This class provides exclusive access to the qdoc database, This class provides exclusive access to the qdoc database,
which consists of a forrest of trees and a lot of maps and 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, This function is called for autolinking to a \a type,
which could be a function return type or a parameter 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); Atom* atom = const_cast<Atom*>(a);
QStringList targetPath = atom->string().split("#"); QStringList targetPath = atom->string().split("#");
QString first = targetPath.first().trimmed(); QString first = targetPath.first().trimmed();
if (Generator::debugging())
qDebug() << " first:" << first;
Tree* domain = 0; Tree* domain = 0;
Node::Genus genus = Node::DontCare; Node::Genus genus = Node::DontCare;
@ -1659,8 +1693,14 @@ const Node* QDocDatabase::findNodeForAtom(const Atom* a, const Node* relative, Q
else if (domain) { else if (domain) {
if (first.endsWith(".html")) if (first.endsWith(".html"))
node = domain->findNodeByNameAndType(QStringList(first), Node::Document); node = domain->findNodeByNameAndType(QStringList(first), Node::Document);
else if (first.endsWith("()")) else if (first.endsWith(QChar(')'))) {
node = domain->findFunctionNode(first, 0, genus); 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 { else {
int flags = SearchBaseClasses | SearchEnumValues; int flags = SearchBaseClasses | SearchEnumValues;
QStringList nodePath = first.split("::"); QStringList nodePath = first.split("::");
@ -1683,8 +1723,11 @@ const Node* QDocDatabase::findNodeForAtom(const Atom* a, const Node* relative, Q
if (!node && first.contains("/")) if (!node && first.contains("/"))
return findNodeForTarget(targetPath, relative, genus, ref); return findNodeForTarget(targetPath, relative, genus, ref);
} }
else if (first.endsWith("()")) else if (first.endsWith(QChar(')'))) {
node = findFunctionNode(first, relative, genus); node = findFunctionNode(first, relative, genus);
if (Generator::debugging())
qDebug() << " node:" << node;
}
else { else {
node = findNodeForTarget(targetPath, relative, genus, ref); node = findNodeForTarget(targetPath, relative, genus, ref);
return node; return node;

View File

@ -141,15 +141,8 @@ class QDocForest
const Node* findFunctionNode(const QString& target, const Node* findFunctionNode(const QString& target,
const Node* relative, const Node* relative,
Node::Genus genus) { Node::Genus genus);
foreach (Tree* t, searchOrder()) {
const Node* n = t->findFunctionNode(target, relative, genus);
if (n)
return n;
relative = 0;
}
return 0;
}
const Node* findNodeForTarget(QStringList& targetPath, const Node* findNodeForTarget(QStringList& targetPath,
const Node* relative, const Node* relative,
Node::Genus genus, Node::Genus genus,

View File

@ -1238,7 +1238,7 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
for (int i = 0; i < functionNode->parameters().size(); ++i) { for (int i = 0; i < functionNode->parameters().size(); ++i) {
Parameter parameter = functionNode->parameters()[i]; Parameter parameter = functionNode->parameters()[i];
writer.writeStartElement("parameter"); writer.writeStartElement("parameter");
writer.writeAttribute("left", parameter.leftType()); writer.writeAttribute("left", parameter.dataType());
writer.writeAttribute("right", parameter.rightType()); writer.writeAttribute("right", parameter.rightType());
writer.writeAttribute("name", parameter.name()); writer.writeAttribute("name", parameter.name());
writer.writeAttribute("default", parameter.defaultValue()); writer.writeAttribute("default", parameter.defaultValue());

View File

@ -675,7 +675,7 @@ bool QmlDocVisitor::visit(QQmlJS::AST::UiPublicMember *member)
QString name = member->name.toString(); QString name = member->name.toString();
FunctionNode *qmlSignal = new FunctionNode(Node::QmlSignal, current, name, false); 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) { for (QQmlJS::AST::UiParameterList *it = member->parameters; it; it = it->next) {
if (!it->type.isEmpty() && !it->name.isEmpty()) if (!it->type.isEmpty() && !it->name.isEmpty())
parameters.append(Parameter(it->type.toString(), QString(), it->name.toString())); parameters.append(Parameter(it->type.toString(), QString(), it->name.toString()));
@ -754,7 +754,7 @@ bool QmlDocVisitor::visit(QQmlJS::AST::FunctionDeclaration* fd)
} }
if (overloads > 1) if (overloads > 1)
qmlMethod->setOverloadFlag(true); qmlMethod->setOverloadFlag(true);
QList<Parameter> parameters; QVector<Parameter> parameters;
QQmlJS::AST::FormalParameterList* formals = fd->formals; QQmlJS::AST::FormalParameterList* formals = fd->formals;
if (formals) { if (formals) {
QQmlJS::AST::FormalParameterList* fpl = formals; QQmlJS::AST::FormalParameterList* fpl = formals;

View File

@ -33,6 +33,7 @@
#include "config.h" #include "config.h"
#include "tokenizer.h" #include "tokenizer.h"
#include "generator.h"
#include <qfile.h> #include <qfile.h>
#include <qhash.h> #include <qhash.h>

View File

@ -220,6 +220,7 @@ QmlTypeNode* Tree::findQmlTypeNode(const QStringList& path)
used as the starting point. used as the starting point.
*/ */
const FunctionNode* Tree::findFunctionNode(const QStringList& path, const FunctionNode* Tree::findFunctionNode(const QStringList& path,
const QString& params,
const Node* relative, const Node* relative,
int findFlags, int findFlags,
Node::Genus genus) const Node::Genus genus) const
@ -234,7 +235,7 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path,
qcn = static_cast<QmlTypeNode*>(n); qcn = static_cast<QmlTypeNode*>(n);
} }
if (qcn) if (qcn)
return static_cast<const FunctionNode*>(qcn->findFunctionNode(path[2])); return static_cast<const FunctionNode*>(qcn->findFunctionNode(path[2], params));
} }
if (!relative) if (!relative)
@ -254,7 +255,7 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path,
const Node* next; const Node* next;
if (i == path.size() - 1) if (i == path.size() - 1)
next = ((const Aggregate*) node)->findFunctionNode(path.at(i)); next = ((const Aggregate*) node)->findFunctionNode(path.at(i), params);
else else
next = ((const Aggregate*) node)->findChildNode(path.at(i), genus); 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)); NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node));
foreach (const Node* baseClass, baseClasses) { foreach (const Node* baseClass, baseClasses) {
if (i == path.size() - 1) 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 else
next = static_cast<const Aggregate*>(baseClass)->findChildNode(path.at(i), genus); 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 Split \a target on "::" and find the function node with that
path. 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; QString t = target;
if (t.endsWith("()")) if (t.endsWith("()")) {
t.chop(2); t.chop(2);
}
QStringList path = t.split("::"); 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) if (fn && fn->metaness() != FunctionNode::MacroWithoutParams)
return fn; return fn;
return 0; return 0;

View File

@ -107,7 +107,10 @@ class Tree
ClassNode* findClassNode(const QStringList& path, const Node* start = 0) const; ClassNode* findClassNode(const QStringList& path, const Node* start = 0) const;
NamespaceNode* findNamespaceNode(const QStringList& path) const; NamespaceNode* findNamespaceNode(const QStringList& path) const;
FunctionNode* findFunctionNode(const QStringList& parentPath, const FunctionNode* clone); 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, Node* findNodeRecursive(const QStringList& path,
int pathIndex, int pathIndex,
@ -163,6 +166,7 @@ class Tree
NamespaceNode *root() { return &root_; } NamespaceNode *root() { return &root_; }
const FunctionNode *findFunctionNode(const QStringList &path, const FunctionNode *findFunctionNode(const QStringList &path,
const QString& params,
const Node *relative = 0, const Node *relative = 0,
int findFlags = 0, int findFlags = 0,
Node::Genus genus = Node::DontCare) const; Node::Genus genus = Node::DontCare) const;