From 70f92f8cee3f76385a426f62f4ee7e79945da5f2 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Wed, 11 Mar 2015 14:58:54 +0100 Subject: [PATCH] qdoc: Show correct method signatures for QML types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The return type was not printed, for \qmlmethod commands used in QML files. The parameter types and default values weren't being printed either. This update corrects those problems. Change-Id: I68301fb2040c9dc5f5650e7dd3fee9c42197e3f7 Task-number: QTBUG-44064 Reviewed-by: Caroline Chao Reviewed-by: Topi Reiniƶ --- src/tools/qdoc/codechunk.h | 1 + src/tools/qdoc/htmlgenerator.cpp | 1 + src/tools/qdoc/node.cpp | 1 + src/tools/qdoc/node.h | 1 + src/tools/qdoc/qmlvisitor.cpp | 199 +++++++++++++++++++++++++++++++ 5 files changed, 203 insertions(+) diff --git a/src/tools/qdoc/codechunk.h b/src/tools/qdoc/codechunk.h index ed898bcdc7..259012df90 100644 --- a/src/tools/qdoc/codechunk.h +++ b/src/tools/qdoc/codechunk.h @@ -76,6 +76,7 @@ public: void appendHotspot(); bool isEmpty() const { return s.isEmpty(); } + void clear() { s.clear(); } QString toString() const; QStringList toPath() const; QString left() const { return s.left(hotspot == -1 ? s.length() : hotspot); } diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp index f0369c989a..00a292b17f 100644 --- a/src/tools/qdoc/htmlgenerator.cpp +++ b/src/tools/qdoc/htmlgenerator.cpp @@ -3349,6 +3349,7 @@ void HtmlGenerator::generateSectionInheritedList(const Section& section, const N } } +// generateSynopsis(qmn,relative,marker,CodeMarker::Detailed,false); void HtmlGenerator::generateSynopsis(const Node *node, const Node *relative, CodeMarker *marker, diff --git a/src/tools/qdoc/node.cpp b/src/tools/qdoc/node.cpp index a5b1f466bc..a6999d3856 100644 --- a/src/tools/qdoc/node.cpp +++ b/src/tools/qdoc/node.cpp @@ -1863,6 +1863,7 @@ void FunctionNode::setReimp(bool r) } /*! + Append \a parameter to the parameter list. */ void FunctionNode::addParameter(const Parameter& parameter) { diff --git a/src/tools/qdoc/node.h b/src/tools/qdoc/node.h index 2c6e703103..654004e425 100644 --- a/src/tools/qdoc/node.h +++ b/src/tools/qdoc/node.h @@ -904,6 +904,7 @@ public: } int overloadNumber() const; const QList& parameters() const { return params; } + void clearParams() { params.clear(); } QStringList parameterNames() const; QString rawParameters(bool names = false, bool values = false) const; const FunctionNode* reimplementedFrom() const { return rf; } diff --git a/src/tools/qdoc/qmlvisitor.cpp b/src/tools/qdoc/qmlvisitor.cpp index 6179e80085..190c9f0444 100644 --- a/src/tools/qdoc/qmlvisitor.cpp +++ b/src/tools/qdoc/qmlvisitor.cpp @@ -42,6 +42,7 @@ #include "codeparser.h" #include "qmlvisitor.h" #include "qdocdatabase.h" +#include "tokenizer.h" QT_BEGIN_NAMESPACE @@ -146,6 +147,29 @@ QQmlJS::AST::SourceLocation QmlDocVisitor::precedingComment(quint32 offset) cons return QQmlJS::AST::SourceLocation(); } +class QmlSignatureParser +{ + public: + QmlSignatureParser(FunctionNode* func, const QString& signature, const Location& loc); + void readToken() { tok_ = tokenizer_->getToken(); } + QString lexeme() { return tokenizer_->lexeme(); } + QString previousLexeme() { return tokenizer_->previousLexeme(); } + + bool match(int target); + bool matchDataType(CodeChunk* dataType, QString* var); + bool matchParameter(); + bool matchFunctionDecl(); + + private: + QString signature_; + QStringList names_; + QString funcName_; + Tokenizer* tokenizer_; + int tok_; + FunctionNode* func_; + const Location& location_; +}; + /*! Finds the nearest unused qdoc comment above the QML entity represented by the \a node and processes the qdoc commands @@ -216,6 +240,13 @@ bool QmlDocVisitor::applyDocumentation(QQmlJS::AST::SourceLocation location, Nod else qDebug() << " FAILED TO PARSE QML OR JS PROPERTY:" << topic << args; } + else if ((topic == COMMAND_QMLMETHOD) || (topic == COMMAND_QMLATTACHEDMETHOD) || + (topic == COMMAND_JSMETHOD) || (topic == COMMAND_JSATTACHEDMETHOD)) { + if (node->isFunction()) { + FunctionNode* fn = static_cast(node); + QmlSignatureParser qsp(fn, args, doc.location()); + } + } } } for (int i=0; iappend(previousLexeme()); + virgin = false; + } + } + + if (virgin) { + if (match(Tok_Ident)) { + dataType->append(previousLexeme()); + } + else if (match(Tok_void) || + match(Tok_int) || + match(Tok_char) || + match(Tok_double) || + match(Tok_Ellipsis)) + dataType->append(previousLexeme()); + else + return false; + } + else if (match(Tok_int) || + match(Tok_char) || + match(Tok_double)) { + dataType->append(previousLexeme()); + } + + if (match(Tok_Gulbrandsen)) + dataType->append(previousLexeme()); + else + break; + } + + while (match(Tok_Ampersand) || + match(Tok_Aster) || + match(Tok_const) || + match(Tok_Caret)) + dataType->append(previousLexeme()); + + /* + The usual case: Look for an optional identifier, then for + some array brackets. + */ + dataType->appendHotspot(); + + if ((var != 0) && match(Tok_Ident)) + *var = previousLexeme(); + + if (tok_ == Tok_LeftBracket) { + int bracketDepth0 = tokenizer_->bracketDepth(); + while ((tokenizer_->bracketDepth() >= bracketDepth0 && tok_ != Tok_Eoi) || + tok_ == Tok_RightBracket) { + dataType->append(lexeme()); + readToken(); + } + } + return true; +} + +bool QmlSignatureParser::matchParameter() +{ + QString name; + CodeChunk dataType; + CodeChunk defaultValue; + + bool result = matchDataType(&dataType, &name); + if (name.isEmpty()) { + name = dataType.toString(); + dataType.clear(); + } + + if (!result) + return false; + if (match(Tok_Equal)) { + int parenDepth0 = tokenizer_->parenDepth(); + while (tokenizer_->parenDepth() >= parenDepth0 && + (tok_ != Tok_Comma || + tokenizer_->parenDepth() > parenDepth0) && + tok_ != Tok_Eoi) { + defaultValue.append(lexeme()); + readToken(); + } + } + func_->addParameter(Parameter(dataType.toString(), "", name, defaultValue.toString())); + return true; +} + +bool QmlSignatureParser::matchFunctionDecl() +{ + CodeChunk returnType; + + int firstBlank = signature_.indexOf(QChar(' ')); + int leftParen = signature_.indexOf(QChar('(')); + if ((firstBlank > 0) && (leftParen - firstBlank) > 1) { + if (!matchDataType(&returnType, 0)) + return false; + } + + while (match(Tok_Ident)) { + names_.append(previousLexeme()); + if (!match(Tok_Gulbrandsen)) { + funcName_ = previousLexeme(); + names_.pop_back(); + break; + } + } + + if (tok_ != Tok_LeftParen) + return false; + + readToken(); + + func_->setLocation(location_); + func_->setReturnType(returnType.toString()); + + if (tok_ != Tok_RightParen) { + func_->clearParams(); + do { + if (!matchParameter()) + return false; + } while (match(Tok_Comma)); + } + if (!match(Tok_RightParen)) + return false; + return true; +} + /*! A QML property argument has the form...