From d22de18fae2ee42ba314879f56b6c86c46de6f4b Mon Sep 17 00:00:00 2001
From: Roberto Raggi <roberto.raggi@nokia.com>
Date: Tue, 2 Feb 2010 13:18:56 +0100
Subject: [PATCH] Introduced SemanticInfo::nodeUnderCursor().

---
 src/plugins/qmljseditor/qmlhoverhandler.cpp | 53 ++++++-------
 src/plugins/qmljseditor/qmljseditor.cpp     | 83 +++++++++++++--------
 src/plugins/qmljseditor/qmljseditor.h       |  3 +
 3 files changed, 76 insertions(+), 63 deletions(-)

diff --git a/src/plugins/qmljseditor/qmlhoverhandler.cpp b/src/plugins/qmljseditor/qmlhoverhandler.cpp
index 44b5e8184d4..f247aa9a800 100644
--- a/src/plugins/qmljseditor/qmlhoverhandler.cpp
+++ b/src/plugins/qmljseditor/qmlhoverhandler.cpp
@@ -39,6 +39,7 @@
 #include <qmljs/qmljsbind.h>
 #include <qmljs/qmljscheck.h>
 #include <qmljs/qmljsinterpreter.h>
+#include <qmljs/parser/qmljsast_p.h>
 #include <texteditor/itexteditor.h>
 #include <texteditor/basetexteditor.h>
 
@@ -151,9 +152,6 @@ void QmlHoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, in
         m_helpEngineNeedsSetup = false;
     }
 
-    QTextCursor tc(edit->document());
-    tc.setPosition(pos);
-
     // We only want to show F1 if the tooltip matches the help id
     bool showF1 = true;
 
@@ -166,36 +164,27 @@ void QmlHoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, in
 
     QString symbolName = QLatin1String("<unknown>");
     if (m_helpId.isEmpty()) {
-        // Move to the end of a qualified name
-        bool stop = false;
-        while (!stop) {
-            const QChar ch = editor->characterAt(tc.position());
-            if (ch.isLetterOrNumber() || ch == QLatin1Char('_')) {
-                tc.setPosition(tc.position() + 1);
-            } else {
-                stop = true;
-            }
-        }
+        AST::Node *node = semanticInfo.nodeUnderCursor(pos);
+        if (node && !(AST::cast<AST::StringLiteral *>(node) != 0 || AST::cast<AST::NumericLiteral *>(node) != 0)) {
+            AST::UiObjectMember *declaringMember = semanticInfo.declaringMember(pos);
+
+            Interpreter::Engine interp;
+            Interpreter::ObjectValue *scope = Bind::scopeChainAt(qmlDocument, snapshot, &interp, declaringMember);
+
+            Check check(&interp);
+            const Interpreter::Value *value = check(node->expressionCast(), scope);
+
+            QStringList baseClasses;
+            m_toolTip = prettyPrint(value, &interp, &baseClasses);
+
+            foreach (const QString &baseClass, baseClasses) {
+                QString helpId = QLatin1String("QML.");
+                helpId += baseClass;
 
-        // Fetch the expression's code
-        QmlExpressionUnderCursor expressionUnderCursor;
-        QmlJS::AST::ExpressionNode *expression = expressionUnderCursor(tc);
-
-        AST::UiObjectMember *declaringMember = semanticInfo.declaringMember(pos);
-
-        Interpreter::Engine interp;
-        Interpreter::ObjectValue *scope = Bind::scopeChainAt(qmlDocument, snapshot, &interp, declaringMember);
-        Check check(&interp);
-        const Interpreter::Value *value = check(expression, scope);
-        QStringList baseClasses;
-        m_toolTip = prettyPrint(value, &interp, &baseClasses);
-        foreach (const QString &baseClass, baseClasses) {
-            QString helpId = QLatin1String("QML.");
-            helpId += baseClass;
-
-            if (! m_helpEngine->linksForIdentifier(helpId).isEmpty()) {
-                m_helpId = helpId;
-                break;
+                if (! m_helpEngine->linksForIdentifier(helpId).isEmpty()) {
+                    m_helpId = helpId;
+                    break;
+                }
             }
         }
     }
diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp
index 34398fcc81b..0b25fccbbad 100644
--- a/src/plugins/qmljseditor/qmljseditor.cpp
+++ b/src/plugins/qmljseditor/qmljseditor.cpp
@@ -481,6 +481,38 @@ AST::UiObjectMember *SemanticInfo::declaringMember(int cursorPosition) const
     return declaringMember;
 }
 
+AST::Node *SemanticInfo::nodeUnderCursor(int pos) const
+{
+    if (! document)
+        return 0;
+
+    const unsigned cursorPosition = pos;
+
+    CollectASTNodes nodes;
+    nodes.accept(document->ast());
+
+    foreach (AST::UiQualifiedId *q, nodes.qualifiedIds) {
+        if (cursorPosition >= q->identifierToken.begin()) {
+            for (AST::UiQualifiedId *tail = q; tail; tail = tail->next) {
+                if (! tail->next && cursorPosition <= tail->identifierToken.end())
+                    return q;
+            }
+        }
+    }
+
+    foreach (AST::IdentifierExpression *id, nodes.identifiers) {
+        if (cursorPosition >= id->identifierToken.begin() && cursorPosition <= id->identifierToken.end())
+            return id;
+    }
+
+    foreach (AST::FieldMemberExpression *mem, nodes.fieldMembers) {
+        if (mem->name && cursorPosition >= mem->identifierToken.begin() && cursorPosition <= mem->identifierToken.end())
+            return mem;
+    }
+
+    return 0;
+}
+
 int SemanticInfo::revision() const
 {
     if (document)
@@ -834,46 +866,35 @@ void QmlJSTextEditor::createToolBar(QmlJSEditorEditable *editable)
 
 TextEditor::BaseTextEditor::Link QmlJSTextEditor::findLinkAt(const QTextCursor &cursor, bool /*resolveTarget*/)
 {
-    Link link;
     const SemanticInfo semanticInfo = m_semanticInfo;
+    const unsigned cursorPosition = cursor.position();
 
-    if (semanticInfo.document && semanticInfo.revision() == document()->revision()) {
-        CollectASTNodes nodes;
-        nodes.accept(semanticInfo.document->ast());
-
-        const unsigned cursorPosition = cursor.position();
-
-        foreach (AST::UiQualifiedId *q, nodes.qualifiedIds) {
-            if (cursorPosition >= q->identifierToken.begin()) {
-                for (AST::UiQualifiedId *tail = q; tail; tail = tail->next) {
-                    if (! tail->next && cursorPosition <= tail->identifierToken.end()) {
-                        link.begin = tail->identifierToken.begin();
-                        link.end = tail->identifierToken.end();
-                        return link;
-                    }
-                }
-            }
-        }
-
-        foreach (AST::IdentifierExpression *id, nodes.identifiers) {
-            if (cursorPosition >= id->identifierToken.begin() && cursorPosition <= id->identifierToken.end()) {
-                link.begin = id->firstSourceLocation().begin();
-                link.end = id->lastSourceLocation().end();
-                return link;
-            }
-        }
+    AST::Node *node = semanticInfo.nodeUnderCursor(cursorPosition);
 
-        foreach (AST::FieldMemberExpression *mem, nodes.fieldMembers) {
-            if (mem->name && cursorPosition >= mem->identifierToken.begin() && cursorPosition <= mem->identifierToken.end()) {
-                link.begin = mem->lastSourceLocation().begin();
-                link.end = mem->lastSourceLocation().end();
+    if (AST::UiQualifiedId *q = AST::cast<AST::UiQualifiedId *>(node)) {
+        for (AST::UiQualifiedId *tail = q; tail; tail = tail->next) {
+            if (! tail->next && cursorPosition <= tail->identifierToken.end()) {
+                Link link;
+                link.begin = tail->identifierToken.begin();
+                link.end = tail->identifierToken.end();
                 return link;
             }
         }
 
+    } else if (AST::IdentifierExpression *id = AST::cast<AST::IdentifierExpression *>(node)) {
+        Link link;
+        link.begin = id->firstSourceLocation().begin();
+        link.end = id->lastSourceLocation().end();
+        return link;
+
+    } else if (AST::FieldMemberExpression *mem = AST::cast<AST::FieldMemberExpression *>(node)) {
+        Link link;
+        link.begin = mem->lastSourceLocation().begin();
+        link.end = mem->lastSourceLocation().end();
+        return link;
     }
 
-    return link;
+    return Link();
 }
 
 void QmlJSTextEditor::contextMenuEvent(QContextMenuEvent *e)
diff --git a/src/plugins/qmljseditor/qmljseditor.h b/src/plugins/qmljseditor/qmljseditor.h
index 139644e75bc..3991eefa19a 100644
--- a/src/plugins/qmljseditor/qmljseditor.h
+++ b/src/plugins/qmljseditor/qmljseditor.h
@@ -108,6 +108,9 @@ public:
     // Returns the declaring member
     QmlJS::AST::UiObjectMember *declaringMember(int cursorPosition) const;
 
+    // Returns the AST node under cursor
+    QmlJS::AST::Node *nodeUnderCursor(int cursorPosition) const;
+
 public: // attributes
     QmlJS::Document::Ptr document;
     QmlJS::Snapshot snapshot;
-- 
GitLab