diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index 33392da27c454d075ccfb986f6e4aeacf1b530f0..383ab9ee0082c5ac52d644ef6dc98862c4700101 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -76,11 +76,10 @@ QList<DiagnosticMessage> Check::operator()() return _messages; } -bool Check::visit(UiProgram *ast) +bool Check::visit(UiProgram *) { // build the initial scope chain - if (ast->members && ast->members->member) - _link.scopeChainAt(_doc, ast->members->member); + _link.scopeChainAt(_doc); return true; } diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp index f7dc0c5393ddbcadaed2aa8aa6f584919f711ab4..2ea8eb71b6236f92167947b8e7f679a61ce2c537 100644 --- a/src/libs/qmljs/qmljsinterpreter.cpp +++ b/src/libs/qmljs/qmljsinterpreter.cpp @@ -776,10 +776,10 @@ Context::~Context() { } -void Context::build(Node *node, QmlJS::Document::Ptr doc, const QmlJS::Snapshot &snapshot) +void Context::build(const QList<AST::Node *> &astPath, Document::Ptr doc, const Snapshot &snapshot) { Link link(this, doc, snapshot); - link.scopeChainAt(doc, node); + link.scopeChainAt(doc, astPath); } Engine *Context::engine() const diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h index f91add8847e5c0bf5a50584b7b538cb6e926e65b..91e60573c4e7d8aea21330a2990b7b1bac8b74e2 100644 --- a/src/libs/qmljs/qmljsinterpreter.h +++ b/src/libs/qmljs/qmljsinterpreter.h @@ -264,7 +264,7 @@ public: Context(Engine *engine); ~Context(); - void build(AST::Node *node, const Document::Ptr doc, const Snapshot &snapshot); + void build(const QList<AST::Node *> &astPath, const Document::Ptr doc, const Snapshot &snapshot); Engine *engine() const; const ScopeChain &scopeChain() const; diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp index 6080ff1168c15aec681043c3d63705a79983ddc3..b41c7b11ccd283456c4162a13416c8c5a3026ba5 100644 --- a/src/libs/qmljs/qmljslink.cpp +++ b/src/libs/qmljs/qmljslink.cpp @@ -29,38 +29,52 @@ Interpreter::Engine *Link::engine() return _context->engine(); } -void Link::scopeChainAt(Document::Ptr doc, Node *currentObject) +void Link::scopeChainAt(Document::Ptr doc, const QList<Node *> &astPath) { ScopeChain &scopeChain = _context->scopeChain(); // ### TODO: This object ought to contain the global namespace additions by QML. scopeChain.globalScope = engine()->globalObject(); - if (! doc) + if (! doc) { + scopeChain.update(); return; + } Bind *bind = doc->bind(); QHash<Document *, ScopeChain::QmlComponentChain *> componentScopes; + int qmlScopeObjectIndex = -1; + if (doc->qmlProgram()) { _context->setLookupMode(Context::QmlLookup); makeComponentChain(doc, &scopeChain.qmlComponentScope, &componentScopes); - ObjectValue *scopeObject = 0; - if (UiObjectDefinition *definition = cast<UiObjectDefinition *>(currentObject)) - scopeObject = bind->findQmlObject(definition); - else if (UiObjectBinding *binding = cast<UiObjectBinding *>(currentObject)) - scopeObject = bind->findQmlObject(binding); - - if (scopeObject && scopeObject != scopeChain.qmlComponentScope.rootObject) - scopeChain.qmlScopeObjects += scopeObject; + // find the last object definition or object binding: that is the scope object + for (int i = astPath.size() - 1; i >= 0; --i) { + Node *node = astPath.at(i); + + ObjectValue *scopeObject = 0; + if (UiObjectDefinition *definition = cast<UiObjectDefinition *>(node)) + scopeObject = bind->findQmlObject(definition); + else if (UiObjectBinding *binding = cast<UiObjectBinding *>(node)) + scopeObject = bind->findQmlObject(binding); + + if (scopeObject) { + if (scopeObject != scopeChain.qmlComponentScope.rootObject) + scopeChain.qmlScopeObjects += scopeObject; + qmlScopeObjectIndex = i; + break; + } + } if (const ObjectValue *typeEnvironment = _context->typeEnvironment(doc.data())) scopeChain.qmlTypes = typeEnvironment; } else { // the global scope of a js file does not see the instantiating component - if (currentObject != 0) { + qDebug() << "ast path length: " << astPath.size(); + if (astPath.size() != 0) { // add scope chains for all components that source this document foreach (Document::Ptr otherDoc, _docs) { if (otherDoc->bind()->includedScripts().contains(doc->fileName())) { @@ -77,13 +91,17 @@ void Link::scopeChainAt(Document::Ptr doc, Node *currentObject) scopeChain.jsScopes += bind->rootObjectValue(); } - if (FunctionDeclaration *fun = cast<FunctionDeclaration *>(currentObject)) { - ObjectValue *activation = engine()->newObject(/*prototype = */ 0); - for (FormalParameterList *it = fun->formals; it; it = it->next) { - if (it->name) - activation->setProperty(it->name->asString(), engine()->undefinedValue()); + for (int i = qmlScopeObjectIndex + 1; i < astPath.size(); ++i) { + Node *node = astPath.at(i); + + if (FunctionDeclaration *fun = cast<FunctionDeclaration *>(node)) { + ObjectValue *activation = engine()->newObject(/*prototype = */ 0); + for (FormalParameterList *it = fun->formals; it; it = it->next) { + if (it->name) + activation->setProperty(it->name->asString(), engine()->undefinedValue()); + } + scopeChain.jsScopes += activation; } - scopeChain.jsScopes += activation; } scopeChain.update(); diff --git a/src/libs/qmljs/qmljslink.h b/src/libs/qmljs/qmljslink.h index ba767523e20d734e67aaf201fdbc600e465bddcd..9bea65b0ea4b238a853e9af1ec8f825f4713d81a 100644 --- a/src/libs/qmljs/qmljslink.h +++ b/src/libs/qmljs/qmljslink.h @@ -23,7 +23,7 @@ public: ~Link(); // Get the scope chain for the currentObject inside doc. - void scopeChainAt(Document::Ptr doc, AST::Node *currentObject); + void scopeChainAt(Document::Ptr doc, const QList<AST::Node *> &astPath = QList<AST::Node *>()); private: Interpreter::Engine *engine(); diff --git a/src/plugins/qmljseditor/qmljscodecompletion.cpp b/src/plugins/qmljseditor/qmljscodecompletion.cpp index 5d00f7a65ac7bb7842059e8150c52a7026d164a8..46e91114c055521facb74a953f319c52adf6f30f 100644 --- a/src/plugins/qmljseditor/qmljscodecompletion.cpp +++ b/src/plugins/qmljseditor/qmljscodecompletion.cpp @@ -670,8 +670,8 @@ int CodeCompletion::startCompletion(TextEditor::ITextEditable *editor) Interpreter::Context context(&interp); // Set up the current scope chain. - AST::Node *declaringMember = semanticInfo.declaringMember(editor->position()); - context.build(declaringMember, document, snapshot); + QList<AST::Node *> astPath = semanticInfo.astPath(editor->position()); + context.build(astPath , document, snapshot); // Search for the operator that triggered the completion. QChar completionOperator; diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp index c0ebfcf273b9cc0f1b390eec221d8e64c2157036..4f6b32ca10322b103ac695a01f121e57bff647e6 100644 --- a/src/plugins/qmljseditor/qmljseditor.cpp +++ b/src/plugins/qmljseditor/qmljseditor.cpp @@ -904,7 +904,7 @@ TextEditor::BaseTextEditor::Link QmlJSTextEditor::findLinkAt(const QTextCursor & Interpreter::Engine interp; Interpreter::Context context(&interp); - context.build(semanticInfo.declaringMember(cursorPosition), semanticInfo.document, semanticInfo.snapshot); + context.build(semanticInfo.astPath(cursorPosition), semanticInfo.document, semanticInfo.snapshot); Evaluate check(&context); const Interpreter::Value *value = check.reference(node); diff --git a/src/plugins/qmljseditor/qmljshoverhandler.cpp b/src/plugins/qmljseditor/qmljshoverhandler.cpp index 9f06b6687827d9b3d15f90132c9b996089742382..0a561b79720e5ad4a52da6537388adf5f4dc9fd1 100644 --- a/src/plugins/qmljseditor/qmljshoverhandler.cpp +++ b/src/plugins/qmljseditor/qmljshoverhandler.cpp @@ -168,11 +168,11 @@ void HoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, int p if (m_helpId.isEmpty() && m_toolTip.isEmpty()) { AST::Node *node = semanticInfo.nodeUnderCursor(pos); if (node && !(AST::cast<AST::StringLiteral *>(node) != 0 || AST::cast<AST::NumericLiteral *>(node) != 0)) { - AST::Node *declaringMember = semanticInfo.declaringMember(pos); + QList<AST::Node *> astPath = semanticInfo.astPath(pos); Interpreter::Engine interp; Interpreter::Context context(&interp); - context.build(declaringMember, qmlDocument, snapshot); + context.build(astPath, qmlDocument, snapshot); Evaluate check(&context); const Interpreter::Value *value = check(node);