From e6ab82964cbdfb0075395eb9f81fc9d3d621b270 Mon Sep 17 00:00:00 2001
From: Erik Verbruggen <erik.verbruggen@nokia.com>
Date: Fri, 11 Sep 2009 15:47:16 +0200
Subject: [PATCH] Fix for navigating to IDs in the DUI editor.

---
 src/plugins/duieditor/duieditor.cpp           |  5 ++-
 src/plugins/duieditor/duieditor.pro           |  6 ++-
 src/plugins/duieditor/idcollector.cpp         | 38 ++++++++++++++++
 src/plugins/duieditor/idcollector.h           | 32 ++++++++++++++
 .../duieditor/navigationtokenfinder.cpp       | 43 ++++++++-----------
 src/plugins/duieditor/navigationtokenfinder.h |  9 ++--
 6 files changed, 103 insertions(+), 30 deletions(-)
 create mode 100644 src/plugins/duieditor/idcollector.cpp
 create mode 100644 src/plugins/duieditor/idcollector.h

diff --git a/src/plugins/duieditor/duieditor.cpp b/src/plugins/duieditor/duieditor.cpp
index bacbf9d6240..bca8cb5d5ff 100644
--- a/src/plugins/duieditor/duieditor.cpp
+++ b/src/plugins/duieditor/duieditor.cpp
@@ -40,6 +40,7 @@
 
 #include "rewriter_p.h"
 
+#include "idcollector.h"
 #include "navigationtokenfinder.h"
 
 #include <coreplugin/icore.h>
@@ -715,8 +716,10 @@ TextEditor::BaseTextEditor::Link ScriptEditor::findLinkAt(const QTextCursor &cur
     if (!doc)
         return link;
 
+    QMap<QString, QmlJS::AST::SourceLocation> idPositions = IdCollector()(doc->program());
+
     NavigationTokenFinder finder;
-    if (finder(doc->program(), cursor.position(), resolveTarget)) {
+    if (finder(doc->program(), cursor.position(), resolveTarget, idPositions)) {
         link.fileName = file()->fileName();
         link.pos = finder.linkPosition();
         link.length = finder.linkLength();
diff --git a/src/plugins/duieditor/duieditor.pro b/src/plugins/duieditor/duieditor.pro
index 6a400aa9480..66946d7908b 100644
--- a/src/plugins/duieditor/duieditor.pro
+++ b/src/plugins/duieditor/duieditor.pro
@@ -21,7 +21,8 @@ HEADERS += duieditor.h \
     duieditor_global.h \
     duimodelmanager.h \
     duicodeformatter.h \
-    navigationtokenfinder.h
+    navigationtokenfinder.h \
+    idcollector.h
 SOURCES += duieditor.cpp \
     duieditorfactory.cpp \
     duieditorplugin.cpp \
@@ -34,5 +35,6 @@ SOURCES += duieditor.cpp \
     duimodelmanagerinterface.cpp \
     duimodelmanager.cpp \
     duicodeformatter.cpp \
-    navigationtokenfinder.cpp
+    navigationtokenfinder.cpp \
+    idcollector.cpp
 RESOURCES += duieditor.qrc
diff --git a/src/plugins/duieditor/idcollector.cpp b/src/plugins/duieditor/idcollector.cpp
new file mode 100644
index 00000000000..a2ab7cbed73
--- /dev/null
+++ b/src/plugins/duieditor/idcollector.cpp
@@ -0,0 +1,38 @@
+#include <QDebug>
+
+#include "idcollector.h"
+#include "qmljsast_p.h"
+#include "qmljsengine_p.h"
+
+using namespace QmlJS;
+using namespace QmlJS::AST;
+using namespace DuiEditor::Internal;
+
+QMap<QString, QmlJS::AST::SourceLocation> IdCollector::operator()(QmlJS::AST::UiProgram *ast)
+{
+    _idLocations.clear();
+
+    Node::accept(ast, this);
+
+    return _idLocations;
+}
+
+bool IdCollector::visit(QmlJS::AST::UiScriptBinding *ast)
+{
+    if (!(ast->qualifiedId->next) && ast->qualifiedId->name->asString() == "id")
+        if (ExpressionStatement *e = cast<ExpressionStatement*>(ast->statement))
+            if (IdentifierExpression *i = cast<IdentifierExpression*>(e->expression))
+                addId(i->name, i->identifierToken);
+
+    return false;
+}
+
+void IdCollector::addId(QmlJS::NameId* id, const QmlJS::AST::SourceLocation &idLocation)
+{
+    const QString idString = id->asString();
+
+    qDebug() << "Found ID" << idString;
+
+    if (!_idLocations.contains(idString))
+        _idLocations[idString] = idLocation;
+}
diff --git a/src/plugins/duieditor/idcollector.h b/src/plugins/duieditor/idcollector.h
new file mode 100644
index 00000000000..ac10b9c1e47
--- /dev/null
+++ b/src/plugins/duieditor/idcollector.h
@@ -0,0 +1,32 @@
+#ifndef IDCOLLECTOR_H
+#define IDCOLLECTOR_H
+
+#include <QMap>
+#include <QString>
+
+#include "qmljsastvisitor_p.h"
+
+namespace QmlJS { class NameId; }
+
+namespace DuiEditor {
+namespace Internal {
+
+class IdCollector: protected QmlJS::AST::Visitor
+{
+public:
+    QMap<QString, QmlJS::AST::SourceLocation> operator()(QmlJS::AST::UiProgram *ast);
+
+protected:
+    virtual bool visit(QmlJS::AST::UiScriptBinding *ast);
+
+private:
+    void addId(QmlJS::NameId* id, const QmlJS::AST::SourceLocation &idLocation);
+
+private:
+    QMap<QString, QmlJS::AST::SourceLocation> _idLocations;
+};
+
+} // namespace Internal
+} // namespace DuiEditor
+
+#endif // IDCOLLECTOR_H
diff --git a/src/plugins/duieditor/navigationtokenfinder.cpp b/src/plugins/duieditor/navigationtokenfinder.cpp
index 12e7ce7365b..df978ccedfd 100644
--- a/src/plugins/duieditor/navigationtokenfinder.cpp
+++ b/src/plugins/duieditor/navigationtokenfinder.cpp
@@ -9,11 +9,12 @@ using namespace QmlJS;
 using namespace QmlJS::AST;
 using namespace DuiEditor::Internal;
 
-bool NavigationTokenFinder::operator()(QmlJS::AST::UiProgram *ast, int position, bool resolveTarget)
+bool NavigationTokenFinder::operator()(QmlJS::AST::UiProgram *ast, int position, bool resolveTarget, const QMap<QString, QmlJS::AST::SourceLocation> &idPositions)
 {
     _resolveTarget = resolveTarget;
-    _scopes.clear();
     _pos = position;
+    _idPositions = idPositions;
+    _scopes.clear();
     _linkPosition = -1;
     _targetLine = -1;
 
@@ -34,7 +35,7 @@ bool NavigationTokenFinder::visit(QmlJS::AST::IdentifierExpression *ast)
         _linkPosition = ast->identifierToken.offset;
         _linkLength = ast->identifierToken.length;
 
-        if (Node *node = findDeclarationInScopes(ast->name))
+        if (Node *node = findDeclarationInScopesOrIds(ast->name))
             rememberStartPosition(node);
     }
 
@@ -122,7 +123,7 @@ bool NavigationTokenFinder::visit(QmlJS::AST::UiQualifiedId *ast)
                 for (UiQualifiedId *iter2 = ast; iter2; iter2 = iter2->next)
                     _linkLength = iter2->identifierToken.end() - _linkPosition;
 
-                if (Node *node = findDeclarationInScopes(ast))
+                if (Node *node = findDeclarationInScopesOrIds(ast))
                     rememberStartPosition(node);
 
                 return false;
@@ -150,10 +151,7 @@ bool NavigationTokenFinder::visit(QmlJS::AST::UiSourceElement * /*ast*/)
 
 void NavigationTokenFinder::rememberStartPosition(QmlJS::AST::Node *node)
 {
-    if (Statement *s = dynamic_cast<Statement*>(node)) {
-        _targetLine = s->firstSourceLocation().startLine;
-        _targetColumn = s->firstSourceLocation().startColumn;
-    } else if (UiObjectMember *om = dynamic_cast<UiObjectMember*>(node)) {
+    if (UiObjectMember *om = dynamic_cast<UiObjectMember*>(node)) {
         _targetLine = om->firstSourceLocation().startLine;
         _targetColumn = om->firstSourceLocation().startColumn;
     } else if (VariableDeclaration *vd = cast<VariableDeclaration*>(node)) {
@@ -164,18 +162,10 @@ void NavigationTokenFinder::rememberStartPosition(QmlJS::AST::Node *node)
     }
 }
 
-static inline bool isId(QmlJS::AST::UiQualifiedId *ast)
-{
-    return !(ast->next) && ast->name->asString() == "id";
-}
-
-static inline QString idToString(QmlJS::AST::Statement *stmt)
+void NavigationTokenFinder::rememberStartPosition(const QmlJS::AST::SourceLocation &location)
 {
-    if (ExpressionStatement *e = cast<ExpressionStatement*>(stmt))
-        if (IdentifierExpression *i = cast<IdentifierExpression*>(e->expression))
-            return i->name->asString();
-
-    return QString::null;
+    _targetLine = location.startLine;
+    _targetColumn = location.startColumn;
 }
 
 static QmlJS::AST::Node *findDeclaration(const QString &nameId, QmlJS::AST::UiObjectMember *m)
@@ -189,9 +179,6 @@ static QmlJS::AST::Node *findDeclaration(const QString &nameId, QmlJS::AST::UiOb
     } else if (UiArrayBinding *a = cast<UiArrayBinding*>(m)) {
         if (!(a->qualifiedId->next) && a->qualifiedId->name->asString() == nameId)
             return a;
-    } else if (UiScriptBinding *s = cast<UiScriptBinding*>(m)) {
-        if (isId(s->qualifiedId) && nameId == idToString(s->statement))
-            return s->statement;
     }
 
     return 0;
@@ -248,7 +235,7 @@ static QmlJS::AST::Node *findDeclarationInNode(QmlJS::AST::UiQualifiedId *qualif
         return findDeclarationInNode(qualifiedId->next, findDeclarationAsDirectChild(qualifiedId->name->asString(), node));
 }
 
-QmlJS::AST::Node *NavigationTokenFinder::findDeclarationInScopes(QmlJS::NameId *nameId)
+QmlJS::AST::Node *NavigationTokenFinder::findDeclarationInScopesOrIds(QmlJS::NameId *nameId)
 {
     if (!_resolveTarget)
         return 0;
@@ -262,10 +249,14 @@ QmlJS::AST::Node *NavigationTokenFinder::findDeclarationInScopes(QmlJS::NameId *
             return result;
     }
 
+    if (_idPositions.contains(nameAsString)) {
+        rememberStartPosition(_idPositions[nameAsString]);
+    }
+
     return 0;
 }
 
-QmlJS::AST::Node *NavigationTokenFinder::findDeclarationInScopes(QmlJS::AST::UiQualifiedId *qualifiedId)
+QmlJS::AST::Node *NavigationTokenFinder::findDeclarationInScopesOrIds(QmlJS::AST::UiQualifiedId *qualifiedId)
 {
     if (!_resolveTarget)
         return 0;
@@ -280,5 +271,9 @@ QmlJS::AST::Node *NavigationTokenFinder::findDeclarationInScopes(QmlJS::AST::UiQ
             return findDeclarationInNode(qualifiedId->next, result);
     }
 
+    if (_idPositions.contains(nameAsString)) {
+        rememberStartPosition(_idPositions[nameAsString]);
+    }
+
     return 0;
 }
diff --git a/src/plugins/duieditor/navigationtokenfinder.h b/src/plugins/duieditor/navigationtokenfinder.h
index ab8c23c0d42..bcd8c73b46b 100644
--- a/src/plugins/duieditor/navigationtokenfinder.h
+++ b/src/plugins/duieditor/navigationtokenfinder.h
@@ -1,6 +1,7 @@
 #ifndef NAVIGATIONTOKENFINDER_H
 #define NAVIGATIONTOKENFINDER_H
 
+#include <QMap>
 #include <QStack>
 #include <QString>
 
@@ -16,7 +17,7 @@ namespace Internal {
 class NavigationTokenFinder: protected QmlJS::AST::Visitor
 {
 public:
-    bool operator()(QmlJS::AST::UiProgram *ast, int position, bool resolveTarget);
+    bool operator()(QmlJS::AST::UiProgram *ast, int position, bool resolveTarget, const QMap<QString, QmlJS::AST::SourceLocation> &idPositions);
 
     bool targetFound() const { return _targetLine != -1; }
     bool linkFound() const { return _linkPosition != -1; }
@@ -42,14 +43,16 @@ protected:
     virtual void endVisit(QmlJS::AST::UiObjectDefinition *);
 
 private:
-    QmlJS::AST::Node *findDeclarationInScopes(QmlJS::AST::UiQualifiedId *ast);
-    QmlJS::AST::Node *findDeclarationInScopes(QmlJS::NameId *id);
+    QmlJS::AST::Node *findDeclarationInScopesOrIds(QmlJS::AST::UiQualifiedId *ast);
+    QmlJS::AST::Node *findDeclarationInScopesOrIds(QmlJS::NameId *id);
 
     void rememberStartPosition(QmlJS::AST::Node *node);
+    void rememberStartPosition(const QmlJS::AST::SourceLocation &location);
 
 private:
     bool _resolveTarget;
     quint32 _pos;
+    QMap<QString, QmlJS::AST::SourceLocation> _idPositions;
     int _linkPosition;
     int _linkLength;
     int _targetLine;
-- 
GitLab