forked from qt-creator/qt-creator
Add support for new javascript methods to QML/JS outline
Extened AST visitor for outline, declaration and locator to include Javascript methods, prototype functions with formal parameters for better readability. Change-Id: Ifbb2b157699c929412196f356b0c28ae0564f866 Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
This commit is contained in:
committed by
Orgad Shaneh
parent
4320aeea18
commit
af56457ab6
@@ -327,6 +327,34 @@ protected:
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(AST::BinaryExpression *ast)
|
||||
{
|
||||
AST::FieldMemberExpression *field = AST::cast<AST::FieldMemberExpression *>(ast->left);
|
||||
AST::FunctionExpression *funcExpr = AST::cast<AST::FunctionExpression *>(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::FieldMemberExpression *>(ast->left);
|
||||
auto funcExpr = AST::cast<AST::FunctionExpression *>(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::Block *>(ast->statement))
|
||||
|
||||
@@ -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<AST::FieldMemberExpression *>(binExp->left);
|
||||
auto rhsFuncExpr = AST::cast<AST::FunctionExpression *>(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<int, QVariant> 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<int, QVariant> objectData;
|
||||
|
||||
QString display = functionDisplayName(expression->name, functionExpression->formals);
|
||||
while (expression) {
|
||||
if (auto field = AST::cast<AST::FieldMemberExpression *>(expression->base)) {
|
||||
display.prepend(field->name.toString() + QLatin1Char('.'));
|
||||
expression = field;
|
||||
} else {
|
||||
if (auto ident = AST::cast<AST::IdentifierExpression *>(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<int, QVariant> objectData;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -171,6 +171,46 @@ protected:
|
||||
accept(ast->initializer, contextString(context));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(AST::BinaryExpression *ast)
|
||||
{
|
||||
auto fieldExpr = AST::cast<AST::FieldMemberExpression *>(ast->left);
|
||||
auto funcExpr = AST::cast<AST::FunctionExpression *>(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<AST::FieldMemberExpression *>(fieldExpr->base)) {
|
||||
entry.displayName.prepend(field->name.toString() + QLatin1Char('.'));
|
||||
fieldExpr = field;
|
||||
} else {
|
||||
if (auto ident = AST::cast<AST::IdentifierExpression *>(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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user