Commit 08cfc8f2 authored by Christian Kamm's avatar Christian Kamm

Pass in the whole AST path for scope creation.

Just the declaring member isn't enough.
parent 82741973
......@@ -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;
}
......
......@@ -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
......
......@@ -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;
......
......@@ -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();
......
......@@ -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();
......
......@@ -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;
......
......@@ -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);
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment