From 3d44c5621d7c69d4b8ef81bbab66f831b1978618 Mon Sep 17 00:00:00 2001
From: Roberto Raggi <roberto.raggi@nokia.com>
Date: Mon, 8 Feb 2010 21:37:59 +0100
Subject: [PATCH] Improved completion of JavaScript expressions.

---
 src/libs/qmljs/qmljsdocument.cpp              | 65 +++++++------------
 src/libs/qmljs/qmljsdocument.h                |  3 +
 src/libs/qmljs/qmljslink.cpp                  | 22 +++++--
 src/plugins/qmljseditor/qmlcodecompletion.cpp |  1 +
 src/plugins/qmljseditor/qmljseditor.cpp       | 10 +--
 5 files changed, 50 insertions(+), 51 deletions(-)

diff --git a/src/libs/qmljs/qmljsdocument.cpp b/src/libs/qmljs/qmljsdocument.cpp
index fc3fb9ec883..3ba72a4bee6 100644
--- a/src/libs/qmljs/qmljsdocument.cpp
+++ b/src/libs/qmljs/qmljsdocument.cpp
@@ -129,7 +129,7 @@ void Document::setDocumentRevision(int revision)
     _documentRevision = revision;
 }
 
-bool Document::parseQml()
+bool Document::parse_helper(int startToken)
 {
     Q_ASSERT(! _engine);
     Q_ASSERT(! _pool);
@@ -144,8 +144,21 @@ bool Document::parseQml()
 
     lexer.setCode(_source, /*line = */ 1);
 
-    _parsedCorrectly = parser.parse();
-    _ast = parser.ast();
+    switch (startToken) {
+    case QmlJSGrammar::T_FEED_UI_PROGRAM:
+        _parsedCorrectly = parser.parse();
+        break;
+    case QmlJSGrammar::T_FEED_JS_PROGRAM:
+        _parsedCorrectly = parser.parseProgram();
+        break;
+    case QmlJSGrammar::T_FEED_JS_EXPRESSION:
+        _parsedCorrectly = parser.parseExpression();
+        break;
+    default:
+        Q_ASSERT(0);
+    }
+
+    _ast = parser.rootNode();
     _diagnosticMessages = parser.diagnosticMessages();
 
     _bind = new Bind(this);
@@ -153,51 +166,19 @@ bool Document::parseQml()
     return _parsedCorrectly;
 }
 
-bool Document::parseJavaScript()
+bool Document::parseQml()
 {
-    Q_ASSERT(! _engine);
-    Q_ASSERT(! _pool);
-    Q_ASSERT(! _ast);
-    Q_ASSERT(! _bind);
-
-    _engine = new Engine();
-    _pool = new NodePool(_fileName, _engine);
-
-    Lexer lexer(_engine);
-    Parser parser(_engine);
-
-    lexer.setCode(_source, /*line = */ 1);
-
-    _parsedCorrectly = parser.parseProgram();
-    _ast = cast<Program*>(parser.rootNode());
-    _diagnosticMessages = parser.diagnosticMessages();
-
-    _bind = new Bind(this);
+    return parse_helper(QmlJSGrammar::T_FEED_UI_PROGRAM);
+}
 
-    return _parsedCorrectly;
+bool Document::parseJavaScript()
+{
+    return parse_helper(QmlJSGrammar::T_FEED_JS_PROGRAM);
 }
 
 bool Document::parseExpression()
 {
-    Q_ASSERT(! _engine);
-    Q_ASSERT(! _pool);
-    Q_ASSERT(! _ast);
-
-    _engine = new Engine();
-    _pool = new NodePool(_fileName, _engine);
-
-    Lexer lexer(_engine);
-    Parser parser(_engine);
-
-    lexer.setCode(_source, /*line = */ 1);
-
-    _parsedCorrectly = parser.parseExpression();
-    _ast = parser.rootNode();
-    if (_ast)
-        _ast = _ast->expressionCast();
-    _diagnosticMessages = parser.diagnosticMessages();
-
-    return _parsedCorrectly;
+    return parse_helper(QmlJSGrammar::T_FEED_JS_EXPRESSION);
 }
 
 Bind *Document::bind() const
diff --git a/src/libs/qmljs/qmljsdocument.h b/src/libs/qmljs/qmljsdocument.h
index 5cc07ccf6bb..767ca281235 100644
--- a/src/libs/qmljs/qmljsdocument.h
+++ b/src/libs/qmljs/qmljsdocument.h
@@ -81,6 +81,9 @@ public:
     QString path() const { return _path; }
     QString componentName() const { return _componentName; }
 
+private:
+    bool parse_helper(int kind);
+
 private:
     QmlJS::Engine *_engine;
     NodePool *_pool;
diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp
index f39b91c04e3..e2f9316df33 100644
--- a/src/libs/qmljs/qmljslink.cpp
+++ b/src/libs/qmljs/qmljslink.cpp
@@ -45,17 +45,31 @@ void Link::scopeChainAt(Document::Ptr doc, Node *currentObject)
 
     // ### FIXME: May want to link to instantiating components from here.
 
-    if (bind->_rootObjectValue)
-        _context->pushScope(bind->_rootObjectValue);
+    qDebug() << "**** here" << currentObject;
 
     ObjectValue *scopeObject = 0;
     if (UiObjectDefinition *definition = cast<UiObjectDefinition *>(currentObject))
         scopeObject = bind->_qmlObjects.value(definition);
     else if (UiObjectBinding *binding = cast<UiObjectBinding *>(currentObject))
         scopeObject = bind->_qmlObjects.value(binding);
+    else if (FunctionDeclaration *fun = cast<FunctionDeclaration *>(currentObject)) {
+        _context->pushScope(bind->_rootObjectValue);
 
-    if (scopeObject && scopeObject != bind->_rootObjectValue)
-        _context->pushScope(scopeObject);
+        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());
+        }
+        _context->pushScope(activation);
+    }
+
+    if (scopeObject) {
+        if (bind->_rootObjectValue)
+            _context->pushScope(bind->_rootObjectValue);
+
+        if (scopeObject != bind->_rootObjectValue)
+            _context->pushScope(scopeObject);
+    }
 
     const QStringList &includedScripts = bind->includedScripts();
     for (int index = includedScripts.size() - 1; index != -1; --index) {
diff --git a/src/plugins/qmljseditor/qmlcodecompletion.cpp b/src/plugins/qmljseditor/qmlcodecompletion.cpp
index 6d1bb3f064f..e063819295d 100644
--- a/src/plugins/qmljseditor/qmlcodecompletion.cpp
+++ b/src/plugins/qmljseditor/qmlcodecompletion.cpp
@@ -654,6 +654,7 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
 
     // Set up the current scope chain.
     AST::Node *declaringMember = semanticInfo.declaringMember(editor->position());
+    qDebug() << "*** declaring member:" << declaringMember;
     context.build(declaringMember, document, snapshot);
 
     // Search for the operator that triggered the completion.
diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp
index 786d6e76418..65ddfe75489 100644
--- a/src/plugins/qmljseditor/qmljseditor.cpp
+++ b/src/plugins/qmljseditor/qmljseditor.cpp
@@ -387,8 +387,8 @@ public:
     {
         _textDocument = textDocument;
         _ranges.clear();
-        if (doc && doc->qmlProgram() != 0)
-            doc->qmlProgram()->accept(this);
+        if (doc && doc->ast() != 0)
+            doc->ast()->accept(this);
         return _ranges;
     }
 
@@ -409,7 +409,6 @@ protected:
         return true;
     }
 
-#if 0 // ### create ranges for function declarations.
     virtual bool visit(AST::FunctionExpression *ast)
     {
         _ranges.append(createRange(ast));
@@ -421,7 +420,6 @@ protected:
         _ranges.append(createRange(ast));
         return true;
     }
-#endif
 
     Range createRange(AST::UiObjectMember *member, AST::UiObjectInitializer *ast)
     {
@@ -448,6 +446,7 @@ protected:
 
         range.end = QTextCursor(_textDocument);
         range.end.setPosition(ast->rbraceToken.end());
+
         return range;
     }
 
@@ -649,8 +648,9 @@ void QmlJSTextEditor::updateDocumentNow()
 
 void QmlJSTextEditor::onDocumentUpdated(QmlJS::Document::Ptr doc)
 {
-    if (file()->fileName() != doc->fileName())
+    if (file()->fileName() != doc->fileName()) {
         return;
+    }
 
     if (doc->documentRevision() != document()->revision()) {
         // got an outdated document.
-- 
GitLab