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.
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.

View File

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

View 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(' ');

View 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

View 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")

View File

@ -1839,8 +1839,13 @@
\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.

View 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) {

View File

@ -34,11 +34,12 @@
#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
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)
{
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;

View 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;
}

View 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;

View 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,

View 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());

View 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;

View File

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

View 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;

View 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;