Skip to content

Commit 8c5ce68

Browse files
author
Martin Smith
committed
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 <[email protected]>
1 parent 6dde874 commit 8c5ce68

16 files changed

+238
-111
lines changed

src/corelib/tools/qlist.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ void **QListData::erase(void **xi)
378378
references into a QVector and non-heap-allocating QLists.
379379
380380
Internally, QList\<T\> is represented as an array of T if
381-
If \c{sizeof(T) <= sizeof(void*)} and T has been declared to be
381+
\c{sizeof(T) <= sizeof(void*)} and T has been declared to be
382382
either a \c{Q_MOVABLE_TYPE} or a \c{Q_PRIMITIVE_TYPE} using
383383
\l {Q_DECLARE_TYPEINFO}. Otherwise, QList\<T\> is represented
384384
as an array of T* and the items are allocated on the heap.

src/tools/qdoc/codeparser.h

-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
QT_BEGIN_NAMESPACE
4141

4242
class Config;
43-
class Node;
4443
class QString;
4544
class QDocDatabase;
4645

src/tools/qdoc/cppcodemarker.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,11 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node,
157157
synopsis += "(";
158158
if (!func->parameters().isEmpty()) {
159159
//synopsis += QLatin1Char(' ');
160-
QList<Parameter>::ConstIterator p = func->parameters().constBegin();
160+
QVector<Parameter>::ConstIterator p = func->parameters().constBegin();
161161
while (p != func->parameters().constEnd()) {
162162
if (p != func->parameters().constBegin())
163163
synopsis += ", ";
164-
synopsis += typified((*p).leftType());
164+
synopsis += typified((*p).dataType());
165165
if (style != Subpage && !(*p).name().isEmpty())
166166
synopsis +=
167167
"<@param>" + protect((*p).name()) + "</@param>";
@@ -328,11 +328,11 @@ QString CppCodeMarker::markedUpQmlItem(const Node* node, bool summary)
328328
synopsis = name;
329329
synopsis += QLatin1Char('(');
330330
if (!func->parameters().isEmpty()) {
331-
QList<Parameter>::ConstIterator p = func->parameters().constBegin();
331+
QVector<Parameter>::ConstIterator p = func->parameters().constBegin();
332332
while (p != func->parameters().constEnd()) {
333333
if (p != func->parameters().constBegin())
334334
synopsis += ", ";
335-
synopsis += typified((*p).leftType());
335+
synopsis += typified((*p).dataType());
336336
if (!(*p).name().isEmpty()) {
337337
if (!synopsis.endsWith(QLatin1Char('(')))
338338
synopsis += QLatin1Char(' ');

src/tools/qdoc/cppcodeparser.cpp

+51-23
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ static bool inMacroCommand_ = false;
5454
static bool parsingHeaderFile_ = false;
5555
QStringList CppCodeParser::exampleFiles;
5656
QStringList CppCodeParser::exampleDirs;
57+
CppCodeParser* CppCodeParser::cppParser_ = 0;
5758

5859
/*!
5960
The constructor initializes some regular expressions
@@ -63,6 +64,7 @@ CppCodeParser::CppCodeParser()
6364
: varComment("/\\*\\s*([a-zA-Z_0-9]+)\\s*\\*/"), sep("(?:<[^>]+>)?::")
6465
{
6566
reset();
67+
cppParser_ = this;
6668
}
6769

6870
/*!
@@ -374,12 +376,12 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
374376
}
375377
else {
376378
func->setMetaness(FunctionNode::MacroWithParams);
377-
QList<Parameter> params = func->parameters();
379+
QVector<Parameter> params = func->parameters();
378380
for (int i = 0; i < params.size(); ++i) {
379381
Parameter &param = params[i];
380-
if (param.name().isEmpty() && !param.leftType().isEmpty()
381-
&& param.leftType() != "...")
382-
param = Parameter("", "", param.leftType());
382+
if (param.name().isEmpty() && !param.dataType().isEmpty()
383+
&& param.dataType() != "...")
384+
param = Parameter("", "", param.dataType());
383385
}
384386
func->setParameters(params);
385387
}
@@ -1308,23 +1310,23 @@ bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var)
13081310

13091311
/*!
13101312
Parse the next function parameter, if there is one, and
1311-
append it to parameter list \a p. Return true if a parameter
1312-
is parsed and appended to \a p. Otherwise return false.
1313+
append it to parameter vector \a pvect. Return true if
1314+
a parameter is parsed and appended to \a pvect.
1315+
Otherwise return false.
13131316
*/
1314-
bool CppCodeParser::matchParameter(ParsedParameterList& pplist)
1317+
bool CppCodeParser::matchParameter(QVector<Parameter>& pvect, bool& isQPrivateSignal)
13151318
{
1316-
ParsedParameter pp;
13171319
if (match(Tok_QPrivateSignal)) {
1318-
pp.qPrivateSignal_ = true;
1319-
pplist.append(pp);
1320+
isQPrivateSignal = true;
13201321
return true;
13211322
}
13221323

1324+
Parameter p;
13231325
CodeChunk chunk;
1324-
if (!matchDataType(&chunk, &pp.name_)) {
1326+
if (!matchDataType(&chunk, &p.name_)) {
13251327
return false;
13261328
}
1327-
pp.dataType_ = chunk.toString();
1329+
p.dataType_ = chunk.toString();
13281330
chunk.clear();
13291331
match(Tok_Comment);
13301332
if (match(Tok_Equal)) {
@@ -1336,8 +1338,8 @@ bool CppCodeParser::matchParameter(ParsedParameterList& pplist)
13361338
readToken();
13371339
}
13381340
}
1339-
pp.defaultValue_ = chunk.toString();
1340-
pplist.append(pp);
1341+
p.defaultValue_ = chunk.toString();
1342+
pvect.append(p);
13411343
return true;
13421344
}
13431345

@@ -1542,10 +1544,11 @@ bool CppCodeParser::matchFunctionDecl(Aggregate *parent,
15421544
readToken();
15431545

15441546
// A left paren was seen. Parse the parameters
1545-
ParsedParameterList pplist;
1547+
bool isQPrivateSignal = false;
1548+
QVector<Parameter> pvect;
15461549
if (tok != Tok_RightParen) {
15471550
do {
1548-
if (!matchParameter(pplist))
1551+
if (!matchParameter(pvect, isQPrivateSignal))
15491552
return false;
15501553
} while (match(Tok_Comma));
15511554
}
@@ -1629,13 +1632,10 @@ bool CppCodeParser::matchFunctionDecl(Aggregate *parent,
16291632
func->setStatic(matched_static);
16301633
func->setConst(matchedConst);
16311634
func->setVirtualness(virtuality);
1632-
if (!pplist.isEmpty()) {
1633-
foreach (const ParsedParameter& pp, pplist) {
1634-
if (pp.qPrivateSignal_)
1635-
func->setPrivateSignal();
1636-
else
1637-
func->addParameter(Parameter(pp.dataType_, "", pp.name_, pp.defaultValue_));
1638-
}
1635+
if (isQPrivateSignal)
1636+
func->setPrivateSignal();
1637+
if (!pvect.isEmpty()) {
1638+
func->setParameters(pvect);
16391639
}
16401640
}
16411641
if (parentPathPtr != 0)
@@ -2416,6 +2416,34 @@ bool CppCodeParser::makeFunctionNode(const QString& signature,
24162416
return ok;
24172417
}
24182418

2419+
/*!
2420+
This function uses a Tokenizer to parse the \a parameters of a
2421+
function into the parameter vector \a {pvect}.
2422+
*/
2423+
bool CppCodeParser::parseParameters(const QString& parameters,
2424+
QVector<Parameter>& pvect,
2425+
bool& isQPrivateSignal)
2426+
{
2427+
Tokenizer* outerTokenizer = tokenizer;
2428+
int outerTok = tok;
2429+
2430+
QByteArray latin1 = parameters.toLatin1();
2431+
Tokenizer stringTokenizer(Location(), latin1);
2432+
stringTokenizer.setParsingFnOrMacro(true);
2433+
tokenizer = &stringTokenizer;
2434+
readToken();
2435+
2436+
inMacroCommand_ = false;
2437+
do {
2438+
if (!matchParameter(pvect, isQPrivateSignal))
2439+
return false;
2440+
} while (match(Tok_Comma));
2441+
2442+
tokenizer = outerTokenizer;
2443+
tok = outerTok;
2444+
return true;
2445+
}
2446+
24192447
/*!
24202448
Create a new FunctionNode for a QML method or signal, as
24212449
specified by \a type, as a child of \a parent. \a sig is

src/tools/qdoc/cppcodeparser.h

+4-12
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,6 @@ class CppCodeParser : public CodeParser
5151
{
5252
Q_DECLARE_TR_FUNCTIONS(QDoc::CppCodeParser)
5353

54-
struct ParsedParameter {
55-
bool qPrivateSignal_;
56-
QString dataType_;
57-
QString name_;
58-
QString defaultValue_;
59-
ParsedParameter() : qPrivateSignal_(false) { }
60-
};
61-
friend class QTypeInfo<ParsedParameter>;
62-
typedef QVector<ParsedParameter> ParsedParameterList;
63-
6454
struct ExtraFuncData {
6555
Aggregate* root; // Used as the parent.
6656
Node::NodeType type; // The node type: Function, etc.
@@ -74,6 +64,7 @@ class CppCodeParser : public CodeParser
7464
public:
7565
CppCodeParser();
7666
~CppCodeParser();
67+
static CppCodeParser* cppParser() { return cppParser_; }
7768

7869
virtual void initializeParser(const Config& config) Q_DECL_OVERRIDE;
7970
virtual void terminateParser() Q_DECL_OVERRIDE;
@@ -84,6 +75,7 @@ class CppCodeParser : public CodeParser
8475
virtual void parseSourceFile(const Location& location, const QString& filePath) Q_DECL_OVERRIDE;
8576
virtual void doneParsingHeaderFiles() Q_DECL_OVERRIDE;
8677
virtual void doneParsingSourceFiles() Q_DECL_OVERRIDE;
78+
bool parseParameters(const QString& parameters, QVector<Parameter>& pvect, bool& isQPrivateSignal);
8779

8880
protected:
8981
const QSet<QString>& topicCommands();
@@ -126,7 +118,7 @@ class CppCodeParser : public CodeParser
126118
bool matchTemplateAngles(CodeChunk *type = 0);
127119
bool matchTemplateHeader();
128120
bool matchDataType(CodeChunk *type, QString *var = 0);
129-
bool matchParameter(ParsedParameterList& pplist);
121+
bool matchParameter(QVector<Parameter>& pvect, bool& isQPrivateSignal);
130122
bool matchFunctionDecl(Aggregate *parent,
131123
QStringList *parentPathPtr,
132124
FunctionNode **funcPtr,
@@ -184,10 +176,10 @@ class CppCodeParser : public CodeParser
184176

185177
static QStringList exampleFiles;
186178
static QStringList exampleDirs;
179+
static CppCodeParser* cppParser_;
187180
QString exampleNameFilter;
188181
QString exampleImageFilter;
189182
};
190-
Q_DECLARE_TYPEINFO(CppCodeParser::ParsedParameter, Q_MOVABLE_TYPE);
191183

192184
#define COMMAND_ABSTRACT Doc::alias("abstract")
193185
#define COMMAND_CLASS Doc::alias("class")

src/tools/qdoc/doc/qdoc-manual-markupcmds.qdoc

+7-2
Original file line numberDiff line numberDiff line change
@@ -1839,8 +1839,13 @@
18391839
\li \c {\l QWidget} - The name of a class documented with the \l
18401840
{class-command} {\\class} command.
18411841

1842-
\li \c {\l QWidget::sizeHint()} - The name of a member function,
1843-
documented with or without an \l {fn-command} {\\fn} command.
1842+
\li \c {\l QWidget::sizeHint()} - The signature of a function without
1843+
parameters. If a matching function without parameters can't be found,
1844+
the link is satisfied with the first matching function found.
1845+
1846+
\li \c {\l QWidget::removeAction(QAction* action)} - The signature
1847+
of a function with parameters. If an exact match is not found, the
1848+
link is not satisfied and qdoc reports a \e {Can't link to...} error.
18441849

18451850
\li \c {\l <QtGlobal>} - The subject of a \l {headerfile-command}
18461851
{\\headerfile} command.

src/tools/qdoc/generator.cpp

+9-9
Original file line numberDiff line numberDiff line change
@@ -804,9 +804,9 @@ void Generator::generateBody(const Node *node, CodeMarker *marker)
804804
else if (node->type() == Node::Function) {
805805
const FunctionNode *func = static_cast<const FunctionNode *>(node);
806806
QSet<QString> definedParams;
807-
QList<Parameter>::ConstIterator p = func->parameters().constBegin();
807+
QVector<Parameter>::ConstIterator p = func->parameters().constBegin();
808808
while (p != func->parameters().constEnd()) {
809-
if ((*p).name().isEmpty() && (*p).leftType() != QLatin1String("...")
809+
if ((*p).name().isEmpty() && (*p).dataType() != QLatin1String("...")
810810
&& func->name() != QLatin1String("operator++")
811811
&& func->name() != QLatin1String("operator--")) {
812812
node->doc().location().warning(tr("Missing parameter name"));
@@ -836,7 +836,7 @@ void Generator::generateBody(const Node *node, CodeMarker *marker)
836836
else if (!(*a).isEmpty() && !documentedParams.contains(*a)) {
837837
bool needWarning = (func->status() > Node::Obsolete);
838838
if (func->overloadNumber() > 0) {
839-
FunctionNode *primaryFunc = func->parent()->findFunctionNode(func->name());
839+
FunctionNode *primaryFunc = func->parent()->findFunctionNode(func->name(), QString());
840840
if (primaryFunc) {
841841
foreach (const Parameter &param,
842842
primaryFunc->parameters()) {
@@ -1504,7 +1504,7 @@ void Generator::generateOverloadedSignal(const Node* node, CodeMarker* marker)
15041504
if (i != 0)
15051505
code += ", ";
15061506
const Parameter &p = func->parameters().at(i);
1507-
code += p.leftType() + p.rightType();
1507+
code += p.dataType() + p.rightType();
15081508
}
15091509

15101510
code += ")";
@@ -1516,7 +1516,7 @@ void Generator::generateOverloadedSignal(const Node* node, CodeMarker* marker)
15161516
if (i != 0)
15171517
code += ", ";
15181518
const Parameter &p = func->parameters().at(i);
1519-
code += p.leftType();
1519+
code += p.dataType();
15201520
if (code[code.size()-1].isLetterOrNumber())
15211521
code += " ";
15221522
code += p.name() + p.rightType();
@@ -2049,22 +2049,22 @@ void Generator::supplementAlsoList(const Node *node, QList<Text> &alsoList)
20492049
if (func->name().startsWith("set") && func->name().size() >= 4) {
20502050
alternateName = func->name()[3].toLower();
20512051
alternateName += func->name().mid(4);
2052-
alternateFunc = func->parent()->findFunctionNode(alternateName);
2052+
alternateFunc = func->parent()->findFunctionNode(alternateName, QString());
20532053

20542054
if (!alternateFunc) {
20552055
alternateName = "is" + func->name().mid(3);
2056-
alternateFunc = func->parent()->findFunctionNode(alternateName);
2056+
alternateFunc = func->parent()->findFunctionNode(alternateName, QString());
20572057
if (!alternateFunc) {
20582058
alternateName = "has" + func->name().mid(3);
2059-
alternateFunc = func->parent()->findFunctionNode(alternateName);
2059+
alternateFunc = func->parent()->findFunctionNode(alternateName, QString());
20602060
}
20612061
}
20622062
}
20632063
else if (!func->name().isEmpty()) {
20642064
alternateName = "set";
20652065
alternateName += func->name()[0].toUpper();
20662066
alternateName += func->name().mid(1);
2067-
alternateFunc = func->parent()->findFunctionNode(alternateName);
2067+
alternateFunc = func->parent()->findFunctionNode(alternateName, QString());
20682068
}
20692069

20702070
if (alternateFunc && alternateFunc->access() != Node::Private) {

0 commit comments

Comments
 (0)