From 678f7d3e949887ea12f13ad6a9890a3579704117 Mon Sep 17 00:00:00 2001
From: Roberto Raggi <roberto.raggi@nokia.com>
Date: Mon, 29 Mar 2010 15:30:53 +0200
Subject: [PATCH] Fixed `look at symbol under cursor' when symbol is a Qt
 method (e.g. a signal).

Done with: erikv
---
 src/libs/cplusplus/BackwardsScanner.cpp    |  2 +-
 src/libs/cplusplus/BackwardsScanner.h      |  2 +-
 src/libs/cplusplus/ExpressionUnderCursor.h |  1 -
 src/libs/cplusplus/ResolveExpression.cpp   | 28 ++++++-
 src/libs/cplusplus/ResolveExpression.h     |  1 +
 src/libs/cplusplus/TokenUnderCursor.cpp    | 15 +---
 src/libs/cplusplus/TokenUnderCursor.h      |  2 -
 src/plugins/cppeditor/cppeditor.cpp        | 98 +++++++++++++++++-----
 8 files changed, 108 insertions(+), 41 deletions(-)

diff --git a/src/libs/cplusplus/BackwardsScanner.cpp b/src/libs/cplusplus/BackwardsScanner.cpp
index 70829a3d077..7d1f812a11c 100644
--- a/src/libs/cplusplus/BackwardsScanner.cpp
+++ b/src/libs/cplusplus/BackwardsScanner.cpp
@@ -119,7 +119,7 @@ QStringRef BackwardsScanner::textRef(int index) const
     return _text.midRef(firstToken.begin(), firstToken.length());
 }
 
-int BackwardsScanner::previousBlockState(const QTextBlock &block) const
+int BackwardsScanner::previousBlockState(const QTextBlock &block)
 {
     const QTextBlock prevBlock = block.previous();
 
diff --git a/src/libs/cplusplus/BackwardsScanner.h b/src/libs/cplusplus/BackwardsScanner.h
index 4f82ac28d4c..8ab0685bb12 100644
--- a/src/libs/cplusplus/BackwardsScanner.h
+++ b/src/libs/cplusplus/BackwardsScanner.h
@@ -67,7 +67,7 @@ public:
     int startOfMatchingBrace(int index) const;
     int startOfBlock(int index) const;
 
-    int previousBlockState(const QTextBlock &block) const;
+    static int previousBlockState(const QTextBlock &block);
 
     int size() const;
 
diff --git a/src/libs/cplusplus/ExpressionUnderCursor.h b/src/libs/cplusplus/ExpressionUnderCursor.h
index c8dbbcdf665..e7ef2f9912a 100644
--- a/src/libs/cplusplus/ExpressionUnderCursor.h
+++ b/src/libs/cplusplus/ExpressionUnderCursor.h
@@ -56,7 +56,6 @@ public:
 private:
     int startOfExpression(BackwardsScanner &tk, int index);
     int startOfExpression_helper(BackwardsScanner &tk, int index);
-    int previousBlockState(const QTextBlock &block);
     bool isAccessToken(const SimpleToken &tk);
 
 private:
diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp
index 0dc42ca9cca..1b19ed4d13b 100644
--- a/src/libs/cplusplus/ResolveExpression.cpp
+++ b/src/libs/cplusplus/ResolveExpression.cpp
@@ -120,6 +120,25 @@ QList<Scope *> ResolveExpression::visibleScopes(const LookupItem &result) const
 
 bool ResolveExpression::visit(BinaryExpressionAST *ast)
 {
+    if (tokenKind(ast->binary_op_token) == T_COMMA && ast->right_expression && ast->right_expression->asQtMethod() != 0) {
+
+        if (ast->left_expression && ast->left_expression->asQtMethod() != 0)
+            thisObject();
+        else
+            accept(ast->left_expression);
+
+        QtMethodAST *qtMethod = ast->right_expression->asQtMethod();
+        if (DeclaratorAST *d = qtMethod->declarator) {
+            if (d->core_declarator) {
+                if (DeclaratorIdAST *declaratorId = d->core_declarator->asDeclaratorId())
+                    if (NameAST *nameAST = declaratorId->name)
+                        _results = resolveMemberExpression(_results, T_ARROW, nameAST->name);
+            }
+        }
+
+        return false;
+    }
+
     accept(ast->left_expression);
     return false;
 }
@@ -263,9 +282,15 @@ bool ResolveExpression::visit(BoolLiteralAST *)
 }
 
 bool ResolveExpression::visit(ThisExpressionAST *)
+{
+    thisObject();
+    return false;
+}
+
+void ResolveExpression::thisObject()
 {
     if (! _context.symbol())
-        return false;
+        return;
 
     Scope *scope = _context.symbol()->scope();
     for (; scope; scope = scope->enclosingScope()) {
@@ -290,7 +315,6 @@ bool ResolveExpression::visit(ThisExpressionAST *)
             }
         }
     }
-    return false;
 }
 
 bool ResolveExpression::visit(CompoundExpressionAST *ast)
diff --git a/src/libs/cplusplus/ResolveExpression.h b/src/libs/cplusplus/ResolveExpression.h
index 39290ffa24b..eba5b29f910 100644
--- a/src/libs/cplusplus/ResolveExpression.h
+++ b/src/libs/cplusplus/ResolveExpression.h
@@ -63,6 +63,7 @@ public:
 protected:
     QList<LookupItem> switchResults(const QList<LookupItem> &symbols);
 
+    void thisObject();
     void addResult(const FullySpecifiedType &ty, Symbol *symbol = 0);
     void addResult(const LookupItem &result);
     void addResults(const QList<LookupItem> &results);
diff --git a/src/libs/cplusplus/TokenUnderCursor.cpp b/src/libs/cplusplus/TokenUnderCursor.cpp
index cf0468cab2f..5cbcdfc7a22 100644
--- a/src/libs/cplusplus/TokenUnderCursor.cpp
+++ b/src/libs/cplusplus/TokenUnderCursor.cpp
@@ -28,6 +28,7 @@
 **************************************************************************/
 
 #include "TokenUnderCursor.h"
+#include "BackwardsScanner.h"
 #include <Token.h>
 
 #include <QTextCursor>
@@ -52,7 +53,7 @@ SimpleToken TokenUnderCursor::operator()(const QTextCursor &cursor, QTextBlock *
     int column = cursor.position() - cursor.block().position();
 
     _text = block.text();
-    _tokens = tokenize(_text, previousBlockState(block));
+    _tokens = tokenize(_text, BackwardsScanner::previousBlockState(block));
     for (int index = _tokens.size() - 1; index != -1; --index) {
         const SimpleToken &tk = _tokens.at(index);
         if (tk.position() < column) {
@@ -64,15 +65,3 @@ SimpleToken TokenUnderCursor::operator()(const QTextCursor &cursor, QTextBlock *
 
     return SimpleToken();
 }
-
-int TokenUnderCursor::previousBlockState(const QTextBlock &block) const
-{
-    const QTextBlock prevBlock = block.previous();
-    if (prevBlock.isValid()) {
-        int state = prevBlock.userState();
-
-        if (state != -1)
-            return state;
-    }
-    return 0;
-}
diff --git a/src/libs/cplusplus/TokenUnderCursor.h b/src/libs/cplusplus/TokenUnderCursor.h
index 319467d330b..af1da311ec1 100644
--- a/src/libs/cplusplus/TokenUnderCursor.h
+++ b/src/libs/cplusplus/TokenUnderCursor.h
@@ -52,8 +52,6 @@ public:
     { return _tokens; }
 
 private:
-    int previousBlockState(const QTextBlock &block) const;
-
     QList<SimpleToken> _tokens;
     QString _text;
 };
diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp
index 37772f4b8ca..438da7697c7 100644
--- a/src/plugins/cppeditor/cppeditor.cpp
+++ b/src/plugins/cppeditor/cppeditor.cpp
@@ -1347,40 +1347,96 @@ CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor,
             tc.movePosition(QTextCursor::Right);
     }
 
-    static TokenUnderCursor tokenUnderCursor;
-
-    QTextBlock block;
-    const SimpleToken tk = tokenUnderCursor(tc, &block);
-
-    const int beginOfToken = block.position() + tk.begin();
-    const int endOfToken = block.position() + tk.end();
-
-    // Handle include directives
-    if (tk.is(T_STRING_LITERAL) || tk.is(T_ANGLE_STRING_LITERAL)) {
-        const unsigned lineno = cursor.blockNumber() + 1;
-        foreach (const Document::Include &incl, doc->includes()) {
-            if (incl.line() == lineno && incl.resolved()) {
-                link.fileName = incl.fileName();
-                link.begin = beginOfToken + 1;
-                link.end = endOfToken - 1;
-                return link;
+
+    int beginOfToken = 0;
+    int endOfToken = 0;
+
+    SimpleLexer tokenize;
+    tokenize.setQtMocRunEnabled(true);
+    const QString blockText = cursor.block().text();
+    const QList<SimpleToken> tokens = tokenize(blockText, BackwardsScanner::previousBlockState(cursor.block()));
+
+    bool recognizedQtMethod = false;
+
+    for (int i = 0; i < tokens.size(); ++i) {
+        const SimpleToken &tk = tokens.at(i);
+
+        if (column >= tk.begin() && column <= tk.end()) {
+            if (i >= 2 && tokens.at(i).is(T_IDENTIFIER) && tokens.at(i - 1).is(T_LPAREN)
+                && (tokens.at(i - 2).is(T_SIGNAL) || tokens.at(i - 2).is(T_SLOT))) {
+
+                // token[i] == T_IDENTIFIER
+                // token[i + 1] == T_LPAREN
+                // token[.....] == ....
+                // token[i + n] == T_RPAREN
+
+                if (i + 1 < tokens.size() && tokens.at(i + 1).is(T_LPAREN)) {
+                    // skip matched parenthesis
+                    int j = i - 1;
+                    int depth = 0;
+
+                    for (; j < tokens.size(); ++j) {
+                        if (tokens.at(j).is(T_LPAREN))
+                            ++depth;
+
+                        else if (tokens.at(j).is(T_RPAREN)) {
+                            if (! --depth)
+                                break;
+                        }
+                    }
+
+                    if (j < tokens.size()) {
+                        QTextBlock block = cursor.block();
+
+                        beginOfToken = block.position() + tokens.at(i).begin();
+                        endOfToken = block.position() + tokens.at(i).end();
+
+                        tc.setPosition(block.position() + tokens.at(j).end());
+                        recognizedQtMethod = true;
+                    }
+                }
             }
+            break;
         }
     }
 
-    if (tk.isNot(T_IDENTIFIER))
-        return link;
+    if (! recognizedQtMethod) {
+        static TokenUnderCursor tokenUnderCursor;
+
+        QTextBlock block;
+        const SimpleToken tk = tokenUnderCursor(tc, &block);
+
+        beginOfToken = block.position() + tk.begin();
+        endOfToken = block.position() + tk.end();
+
+        // Handle include directives
+        if (tk.is(T_STRING_LITERAL) || tk.is(T_ANGLE_STRING_LITERAL)) {
+            const unsigned lineno = cursor.blockNumber() + 1;
+            foreach (const Document::Include &incl, doc->includes()) {
+                if (incl.line() == lineno && incl.resolved()) {
+                    link.fileName = incl.fileName();
+                    link.begin = beginOfToken + 1;
+                    link.end = endOfToken - 1;
+                    return link;
+                }
+            }
+        }
+
+        if (tk.isNot(T_IDENTIFIER))
+            return link;
+
+        tc.setPosition(endOfToken);
+    }
 
     // Find the last symbol up to the cursor position
     Symbol *lastSymbol = doc->findSymbolAt(line, column);
     if (!lastSymbol)
         return link;
 
-    tc.setPosition(endOfToken);
-
     // Evaluate the type of the expression under the cursor
     ExpressionUnderCursor expressionUnderCursor;
     const QString expression = expressionUnderCursor(tc);
+
     TypeOfExpression typeOfExpression;
     typeOfExpression.setSnapshot(snapshot);
     QList<LookupItem> resolvedSymbols =
-- 
GitLab