From 576a1ee31f87ea20e5b9b63ba88b8da901f2dd7c Mon Sep 17 00:00:00 2001
From: Roberto Raggi <roberto.raggi@nokia.com>
Date: Mon, 16 Nov 2009 16:18:08 +0100
Subject: [PATCH] Build the list of the visible AST nodes (aka AST path).

---
 src/plugins/cppeditor/cppquickfix.cpp | 113 ++++++++++++++++++++------
 src/plugins/cppeditor/cppquickfix.h   |   9 +-
 2 files changed, 94 insertions(+), 28 deletions(-)

diff --git a/src/plugins/cppeditor/cppquickfix.cpp b/src/plugins/cppeditor/cppquickfix.cpp
index 601b717c65f..db3a8142543 100644
--- a/src/plugins/cppeditor/cppquickfix.cpp
+++ b/src/plugins/cppeditor/cppquickfix.cpp
@@ -33,6 +33,8 @@
 #include <cplusplus/CppDocument.h>
 
 #include <TranslationUnit.h>
+#include <ASTVisitor.h>
+#include <AST.h>
 #include <Token.h>
 
 #include <cpptools/cppmodelmanagerinterface.h>
@@ -43,11 +45,58 @@ using namespace CPlusPlus;
 
 namespace {
 
+class ASTPath: public ASTVisitor
+{
+    Document::Ptr _doc;
+    unsigned _line;
+    unsigned _column;
+    QList<AST *> _nodes;
+
+public:
+    ASTPath(Document::Ptr doc)
+        : ASTVisitor(doc->control()), _doc(doc), _line(0), _column(0) {}
+
+    QList<AST *> operator()(const QTextCursor &cursor)
+    {
+        _nodes.clear();
+        _line = cursor.blockNumber() + 1;
+        _column = cursor.columnNumber() + 1;
+        accept(_doc->translationUnit()->ast());
+        return _nodes;
+    }
+
+protected:
+    virtual bool preVisit(AST *ast)
+    {
+        unsigned firstToken = ast->firstToken();
+        unsigned lastToken = ast->lastToken();
+
+        if (firstToken > 0 && lastToken > firstToken) {
+            unsigned startLine, startColumn;
+            getTokenStartPosition(firstToken, &startLine, &startColumn);
+
+            if (_line > startLine || (_line == startLine && _column >= startColumn)) {
+
+                unsigned endLine, endColumn;
+                getTokenEndPosition(lastToken - 1, &endLine, &endColumn);
+
+                if (_line < endLine || (_line == endLine && _column < endColumn)) {
+                    _nodes.append(ast);
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+};
+
 class HelloQuickFixOp: public QuickFixOperation
 {
 public:
-    HelloQuickFixOp(Document::Ptr doc, const Snapshot &snapshot)
-        : QuickFixOperation(doc, snapshot)
+    HelloQuickFixOp(Document::Ptr doc, const Snapshot &snapshot,
+                    const QTextCursor &textCursor)
+        : QuickFixOperation(doc, snapshot, textCursor)
     {}
 
     virtual QString description() const
@@ -55,22 +104,19 @@ public:
         return QLatin1String("Hello"); // ### tr?
     }
 
-    virtual void apply(QTextCursor cursor)
+    virtual void apply(QTextCursor)
     {
-        cursor.beginEditBlock();
-        cursor.insertBlock();
-        cursor.insertText(QLatin1String("Hello, QuickFix!\n"));
-        cursor.insertText(document()->fileName());
-        cursor.insertBlock();
-        cursor.endEditBlock();
+        // nothing to do.
     }
 };
 
 } // end of anonymous namespace
 
 
-QuickFixOperation::QuickFixOperation(CPlusPlus::Document::Ptr doc, const CPlusPlus::Snapshot &snapshot)
-    : _doc(doc), _snapshot(snapshot)
+QuickFixOperation::QuickFixOperation(CPlusPlus::Document::Ptr doc,
+                                     const CPlusPlus::Snapshot &snapshot,
+                                     const QTextCursor &textCursor)
+    : _doc(doc), _snapshot(snapshot), _textCursor(textCursor)
 { }
 
 QuickFixOperation::~QuickFixOperation()
@@ -79,8 +125,21 @@ QuickFixOperation::~QuickFixOperation()
 QTextCursor QuickFixOperation::textCursor() const
 { return _textCursor; }
 
-void QuickFixOperation::setTextCursor(const QTextCursor &tc)
-{ _textCursor = tc; }
+QTextCursor QuickFixOperation::cursor(AST *ast) const
+{
+    TranslationUnit *unit = document()->translationUnit();
+    unsigned startLine, startColumn, endLine, endColumn;
+    unit->getTokenStartPosition(ast->firstToken(), &startLine, &startColumn);
+    unit->getTokenEndPosition(ast->lastToken() - 1, &endLine, &endColumn);
+
+    QTextDocument *textDocument = _textCursor.document();
+    QTextCursor tc(textDocument);
+    tc.setPosition(textDocument->findBlockByNumber(startLine - 1).position() + startColumn - 1);
+    tc.setPosition(textDocument->findBlockByNumber(endLine - 1).position() + endColumn - 1,
+                   QTextCursor::KeepAnchor);
+
+    return tc;
+}
 
 const CPlusPlus::Token &QuickFixOperation::tokenAt(unsigned index) const
 { return _doc->translationUnit()->tokenAt(index); }
@@ -134,14 +193,10 @@ bool CPPQuickFixCollector::supportsEditor(TextEditor::ITextEditable *editor)
 { return qobject_cast<CPPEditorEditable *>(editor) != 0; }
 
 bool CPPQuickFixCollector::triggersCompletion(TextEditor::ITextEditable *)
-{
-    qDebug() << Q_FUNC_INFO;
-    return false;
-}
+{ return false; }
 
 int CPPQuickFixCollector::startCompletion(TextEditor::ITextEditable *editable)
 {
-    qDebug() << Q_FUNC_INFO;
     Q_ASSERT(editable != 0);
 
     _editor = qobject_cast<CPPEditor *>(editable->widget());
@@ -149,10 +204,22 @@ int CPPQuickFixCollector::startCompletion(TextEditor::ITextEditable *editable)
 
     const SemanticInfo info = _editor->semanticInfo();
 
+    QTextCursor textCursor = _editor->textCursor();
+
+    if (info.revision != _editor->document()->revision()) {
+        // outdated
+        qWarning() << "TODO: outdated semantic info, force a reparse.";
+        return -1;
+    }
+
     if (info.doc) {
-        QuickFixOperationPtr op(new HelloQuickFixOp(info.doc, info.snapshot));
-        _quickFixes.append(op);
-        return editable->position();
+        ASTPath astPath(info.doc);
+
+        const QList<AST *> path = astPath(_editor->textCursor());
+        // ### build the list of the quick fix ops by scanning path.
+
+        if (! _quickFixes.isEmpty())
+            return editable->position();
     }
 
     return -1;
@@ -160,8 +227,6 @@ int CPPQuickFixCollector::startCompletion(TextEditor::ITextEditable *editable)
 
 void CPPQuickFixCollector::completions(QList<TextEditor::CompletionItem> *quickFixItems)
 {
-    qDebug() << Q_FUNC_INFO;
-
     for (int i = 0; i < _quickFixes.size(); ++i) {
         QuickFixOperationPtr op = _quickFixes.at(i);
 
@@ -174,8 +239,6 @@ void CPPQuickFixCollector::completions(QList<TextEditor::CompletionItem> *quickF
 
 void CPPQuickFixCollector::complete(const TextEditor::CompletionItem &item)
 {
-    qDebug() << Q_FUNC_INFO;
-
     const int index = item.data.toInt();
 
     if (index < _quickFixes.size()) {
diff --git a/src/plugins/cppeditor/cppquickfix.h b/src/plugins/cppeditor/cppquickfix.h
index 0f4320cc5ab..5059a753ccf 100644
--- a/src/plugins/cppeditor/cppquickfix.h
+++ b/src/plugins/cppeditor/cppquickfix.h
@@ -33,6 +33,7 @@
 #include <texteditor/icompletioncollector.h>
 
 #include <cplusplus/CppDocument.h>
+#include <ASTfwd.h>
 
 #include <QtCore/QSharedPointer>
 #include <QtGui/QTextCursor>
@@ -54,18 +55,18 @@ class QuickFixOperation
 
 public:
     QuickFixOperation(CPlusPlus::Document::Ptr doc,
-                      const CPlusPlus::Snapshot &snapshot);
+                      const CPlusPlus::Snapshot &snapshot,
+                      const QTextCursor &textCursor);
 
     virtual ~QuickFixOperation();
 
     virtual QString description() const = 0;
-    virtual void apply(QTextCursor cursor) = 0;
+    virtual void apply(QTextCursor tc) = 0;
 
     CPlusPlus::Document::Ptr document() const { return _doc; }
     CPlusPlus::Snapshot snapshot() const { return _snapshot; }
 
     QTextCursor textCursor() const;
-    void setTextCursor(const QTextCursor &tc);
 
 protected:
     const CPlusPlus::Token &tokenAt(unsigned index) const;
@@ -75,6 +76,8 @@ protected:
                              unsigned *column) const;
 
     QTextCursor cursor(unsigned index) const;
+    QTextCursor cursor(CPlusPlus::AST *ast) const;
+
     QTextCursor moveAtStartOfToken(unsigned index) const;
     QTextCursor moveAtEndOfToken(unsigned index) const;
 
-- 
GitLab