diff --git a/src/plugins/qmljseditor/qmljseditordocument.cpp b/src/plugins/qmljseditor/qmljseditordocument.cpp index d5bdc269ff7..45a01ee5d3c 100644 --- a/src/plugins/qmljseditor/qmljseditordocument.cpp +++ b/src/plugins/qmljseditor/qmljseditordocument.cpp @@ -327,6 +327,34 @@ protected: return false; } + + bool visit(AST::BinaryExpression *ast) + { + AST::FieldMemberExpression *field = AST::cast(ast->left); + AST::FunctionExpression *funcExpr = AST::cast(ast->right); + + if (field && funcExpr && funcExpr->body && (ast->op == QSOperator::Assign)) { + Declaration decl; + init(&decl, ast); + + decl.text.fill(QLatin1Char(' '), _depth); + decl.text += field->name; + + decl.text += QLatin1Char('('); + for (FormalParameterList *it = funcExpr->formals; it; it = it->next) { + if (!it->name.isEmpty()) + decl.text += it->name; + + if (it->next) + decl.text += QLatin1String(", "); + } + decl.text += QLatin1Char(')'); + + _declarations.append(decl); + } + + return true; + } }; class CreateRanges: protected AST::Visitor @@ -373,6 +401,16 @@ protected: return true; } + bool visit(AST::BinaryExpression *ast) + { + auto field = AST::cast(ast->left); + auto funcExpr = AST::cast(ast->right); + + if (field && funcExpr && funcExpr->body && (ast->op == QSOperator::Assign)) + _ranges.append(createRange(ast, ast->firstSourceLocation(), ast->lastSourceLocation())); + return true; + } + virtual bool visit(AST::UiScriptBinding *ast) { if (AST::Block *block = AST::cast(ast->statement)) diff --git a/src/plugins/qmljseditor/qmloutlinemodel.cpp b/src/plugins/qmljseditor/qmloutlinemodel.cpp index 7102c078d76..3cffb0f449f 100644 --- a/src/plugins/qmljseditor/qmloutlinemodel.cpp +++ b/src/plugins/qmljseditor/qmloutlinemodel.cpp @@ -274,7 +274,19 @@ private: visitProperties(properties); m_model->leaveTestCase(); + return true; } + + // Collect method assignments for prototypes and objects and show as functions + auto lhsField = AST::cast(binExp->left); + auto rhsFuncExpr = AST::cast(binExp->right); + + if (lhsField && rhsFuncExpr && rhsFuncExpr->body && (binExp->op == QSOperator::Assign)) { + QModelIndex index = m_model->enterFieldMemberExpression(lhsField, rhsFuncExpr); + m_nodeToIndex.insert(lhsField, index); + m_model->leaveFieldMemberExpression(); + } + return true; } @@ -568,12 +580,29 @@ void QmlOutlineModel::leavePublicMember() leaveNode(); } +static QString functionDisplayName(QStringRef name, AST::FormalParameterList *formals) +{ + QString display; + + if (!name.isEmpty()) + display += name.toString() + QLatin1Char('('); + for (AST::FormalParameterList *param = formals; param; param = param->next) { + display += param->name.toString(); + if (param->next) + display += QLatin1String(", "); + } + if (!name.isEmpty()) + display += QLatin1Char(')'); + + return display; +} + QModelIndex QmlOutlineModel::enterFunctionDeclaration(AST::FunctionDeclaration *functionDeclaration) { QMap objectData; - if (!functionDeclaration->name.isEmpty()) - objectData.insert(Qt::DisplayRole, functionDeclaration->name.toString()); + objectData.insert(Qt::DisplayRole, functionDisplayName(functionDeclaration->name, + functionDeclaration->formals)); objectData.insert(ItemTypeRole, ElementBindingType); QmlOutlineItem *item = enterNode(objectData, functionDeclaration, 0, Icons::functionDeclarationIcon()); @@ -586,6 +615,36 @@ void QmlOutlineModel::leaveFunctionDeclaration() leaveNode(); } +QModelIndex QmlOutlineModel::enterFieldMemberExpression(AST::FieldMemberExpression *expression, + AST::FunctionExpression *functionExpression) +{ + QMap objectData; + + QString display = functionDisplayName(expression->name, functionExpression->formals); + while (expression) { + if (auto field = AST::cast(expression->base)) { + display.prepend(field->name.toString() + QLatin1Char('.')); + expression = field; + } else { + if (auto ident = AST::cast(expression->base)) + display.prepend(ident->name.toString() + QLatin1Char('.')); + break; + } + } + + objectData.insert(Qt::DisplayRole, display); + objectData.insert(ItemTypeRole, ElementBindingType); + + QmlOutlineItem *item = enterNode(objectData, expression, 0, m_icons->functionDeclarationIcon()); + + return item->index(); +} + +void QmlOutlineModel::leaveFieldMemberExpression() +{ + leaveNode(); +} + QModelIndex QmlOutlineModel::enterTestCase(AST::ObjectLiteral *objectLiteral) { QMap objectData; diff --git a/src/plugins/qmljseditor/qmloutlinemodel.h b/src/plugins/qmljseditor/qmloutlinemodel.h index 86094c656a5..54f143ae968 100644 --- a/src/plugins/qmljseditor/qmloutlinemodel.h +++ b/src/plugins/qmljseditor/qmloutlinemodel.h @@ -115,6 +115,10 @@ private: QModelIndex enterFunctionDeclaration(QmlJS::AST::FunctionDeclaration *functionDeclaration); void leaveFunctionDeclaration(); + QModelIndex enterFieldMemberExpression(QmlJS::AST::FieldMemberExpression *expression, + QmlJS::AST::FunctionExpression *functionExpression); + void leaveFieldMemberExpression(); + QModelIndex enterTestCase(QmlJS::AST::ObjectLiteral *objectLiteral); void leaveTestCase(); diff --git a/src/plugins/qmljstools/qmljslocatordata.cpp b/src/plugins/qmljstools/qmljslocatordata.cpp index 5806e577b5d..c0febafdc74 100644 --- a/src/plugins/qmljstools/qmljslocatordata.cpp +++ b/src/plugins/qmljstools/qmljslocatordata.cpp @@ -171,6 +171,46 @@ protected: accept(ast->initializer, contextString(context)); return false; } + + bool visit(AST::BinaryExpression *ast) + { + auto fieldExpr = AST::cast(ast->left); + auto funcExpr = AST::cast(ast->right); + + if (fieldExpr && funcExpr && funcExpr->body && (ast->op == QSOperator::Assign)) { + LocatorData::Entry entry = basicEntry(ast->operatorToken); + + entry.type = LocatorData::Function; + entry.displayName = fieldExpr->name.toString(); + while (fieldExpr) { + if (auto field = AST::cast(fieldExpr->base)) { + entry.displayName.prepend(field->name.toString() + QLatin1Char('.')); + fieldExpr = field; + } else { + if (auto ident = AST::cast(fieldExpr->base)) + entry.displayName.prepend(ident->name.toString() + QLatin1Char('.')); + break; + } + } + + entry.displayName += QLatin1Char('('); + for (FormalParameterList *it = funcExpr->formals; it; it = it->next) { + if (it != funcExpr->formals) + entry.displayName += QLatin1String(", "); + if (!it->name.isEmpty()) + entry.displayName += it->name.toString(); + } + entry.displayName += QLatin1Char(')'); + entry.symbolName = entry.displayName; + + m_entries += entry; + + accept(funcExpr->body, contextString(QString::fromLatin1("function %1").arg(entry.displayName))); + return false; + } + + return true; + } }; } // anonymous namespace