forked from qt-creator/qt-creator
QmlJS: Add variables and functions in a JS function to code model.
Allows completion of local variable and function names. Task-number: QTCREATORBUG-942 Reviewed-by: Roberto Raggi
This commit is contained in:
@@ -107,6 +107,11 @@ bool Bind::usesQmlPrototype(ObjectValue *prototype,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Interpreter::ObjectValue *Bind::findFunctionScope(AST::FunctionDeclaration *node) const
|
||||||
|
{
|
||||||
|
return _functionScopes.value(node);
|
||||||
|
}
|
||||||
|
|
||||||
ObjectValue *Bind::switchObjectValue(ObjectValue *newObjectValue)
|
ObjectValue *Bind::switchObjectValue(ObjectValue *newObjectValue)
|
||||||
{
|
{
|
||||||
ObjectValue *oldObjectValue = _currentObjectValue;
|
ObjectValue *oldObjectValue = _currentObjectValue;
|
||||||
@@ -289,9 +294,37 @@ bool Bind::visit(FunctionDeclaration *ast)
|
|||||||
// return false;
|
// return false;
|
||||||
|
|
||||||
ASTFunctionValue *function = new ASTFunctionValue(ast, &_engine);
|
ASTFunctionValue *function = new ASTFunctionValue(ast, &_engine);
|
||||||
// ### set the function's scope.
|
|
||||||
|
|
||||||
_currentObjectValue->setProperty(ast->name->asString(), function);
|
_currentObjectValue->setProperty(ast->name->asString(), function);
|
||||||
|
|
||||||
return false; // ### eventually want to visit function bodies
|
// build function scope
|
||||||
|
ObjectValue *functionScope = _engine.newObject(/*prototype=*/0);
|
||||||
|
_functionScopes.insert(ast, functionScope);
|
||||||
|
ObjectValue *parent = switchObjectValue(functionScope);
|
||||||
|
|
||||||
|
// The order of the following is important. Example: A function with name "arguments"
|
||||||
|
// overrides the arguments object, a variable doesn't.
|
||||||
|
|
||||||
|
// 1. Function formal arguments
|
||||||
|
for (FormalParameterList *it = ast->formals; it; it = it->next) {
|
||||||
|
if (it->name)
|
||||||
|
functionScope->setProperty(it->name->asString(), _engine.undefinedValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Functions defined inside the function body
|
||||||
|
// ### TODO, currently covered by the accept(body)
|
||||||
|
|
||||||
|
// 3. Arguments object
|
||||||
|
ObjectValue *arguments = _engine.newObject(/*prototype=*/0);
|
||||||
|
arguments->setProperty(QLatin1String("callee"), function);
|
||||||
|
arguments->setProperty(QLatin1String("length"), _engine.numberValue());
|
||||||
|
functionScope->setProperty(QLatin1String("arguments"), arguments);
|
||||||
|
|
||||||
|
// 4. Variables defined inside the function body
|
||||||
|
// ### TODO, currently covered by the accept(body)
|
||||||
|
|
||||||
|
// visit body
|
||||||
|
accept(ast->body);
|
||||||
|
switchObjectValue(parent);
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -63,6 +63,8 @@ public:
|
|||||||
bool usesQmlPrototype(Interpreter::ObjectValue *prototype,
|
bool usesQmlPrototype(Interpreter::ObjectValue *prototype,
|
||||||
Interpreter::Context *context) const;
|
Interpreter::Context *context) const;
|
||||||
|
|
||||||
|
Interpreter::ObjectValue *findFunctionScope(AST::FunctionDeclaration *node) const;
|
||||||
|
|
||||||
static QString toString(AST::UiQualifiedId *qualifiedId, QChar delimiter = QChar('.'));
|
static QString toString(AST::UiQualifiedId *qualifiedId, QChar delimiter = QChar('.'));
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -101,6 +103,7 @@ private:
|
|||||||
Interpreter::ObjectValue *_rootObjectValue;
|
Interpreter::ObjectValue *_rootObjectValue;
|
||||||
|
|
||||||
QHash<AST::Node *, Interpreter::ObjectValue *> _qmlObjects;
|
QHash<AST::Node *, Interpreter::ObjectValue *> _qmlObjects;
|
||||||
|
QHash<AST::FunctionDeclaration *, Interpreter::ObjectValue *> _functionScopes;
|
||||||
QStringList _includedScripts;
|
QStringList _includedScripts;
|
||||||
|
|
||||||
QStringList _fileImports;
|
QStringList _fileImports;
|
||||||
|
@@ -32,12 +32,8 @@ void ScopeBuilder::push(AST::Node *node)
|
|||||||
|
|
||||||
// JS scopes
|
// JS scopes
|
||||||
if (FunctionDeclaration *fun = cast<FunctionDeclaration *>(node)) {
|
if (FunctionDeclaration *fun = cast<FunctionDeclaration *>(node)) {
|
||||||
ObjectValue *activation = _context->engine()->newObject(/*prototype = */ 0);
|
ObjectValue *functionScope = _doc->bind()->findFunctionScope(fun);
|
||||||
for (FormalParameterList *it = fun->formals; it; it = it->next) {
|
_context->scopeChain().jsScopes += functionScope;
|
||||||
if (it->name)
|
|
||||||
activation->setProperty(it->name->asString(), _context->engine()->undefinedValue());
|
|
||||||
}
|
|
||||||
_context->scopeChain().jsScopes += activation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_context->scopeChain().update();
|
_context->scopeChain().update();
|
||||||
|
Reference in New Issue
Block a user