From c2a40ce9cff9b7eaeddbd19b1fb078fb3357cc36 Mon Sep 17 00:00:00 2001
From: Roberto Raggi <roberto.raggi@nokia.com>
Date: Wed, 3 Jun 2009 10:50:06 +0200
Subject: [PATCH] Introduced CppTools::Internal::SemanticSearch.

---
 src/plugins/cpptools/cppsemanticsearch.cpp | 252 +++++++++++++++++++++
 src/plugins/cpptools/cppsemanticsearch.h   | 112 +++++++++
 src/plugins/cpptools/cpptools.pro          |   6 +-
 src/plugins/cpptools/cpptoolsplugin.cpp    | 182 +--------------
 4 files changed, 373 insertions(+), 179 deletions(-)
 create mode 100644 src/plugins/cpptools/cppsemanticsearch.cpp
 create mode 100644 src/plugins/cpptools/cppsemanticsearch.h

diff --git a/src/plugins/cpptools/cppsemanticsearch.cpp b/src/plugins/cpptools/cppsemanticsearch.cpp
new file mode 100644
index 00000000000..dda7585475a
--- /dev/null
+++ b/src/plugins/cpptools/cppsemanticsearch.cpp
@@ -0,0 +1,252 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact:  Qt Software Information (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#include "cppsemanticsearch.h"
+#include "cppmodelmanager.h"
+
+#include <AST.h>
+#include <TranslationUnit.h>
+
+#include <cplusplus/PreprocessorClient.h>
+#include <cplusplus/pp.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QPointer>
+#include <QtCore/QtConcurrentRun>
+#include <QtCore/QFutureSynchronizer>
+#include <qtconcurrent/runextensions.h>
+
+using namespace CppTools::Internal;
+using namespace CPlusPlus;
+
+namespace {
+
+class SimpleClient: public Client
+{
+    Environment _env;
+    QPointer<CppModelManager> _modelManager;
+    Snapshot _snapshot;
+    Preprocessor _preproc;
+    QSet<QString> _merged;
+
+public:
+    SimpleClient(QPointer<CppModelManager> modelManager)
+        : _modelManager(modelManager),
+          _snapshot(_modelManager->snapshot()),
+          _preproc(this, &_env)
+    { }
+
+    QByteArray run(QString fileName, const QByteArray &source)
+    {
+        const QByteArray preprocessed = _preproc(fileName, source);
+        return preprocessed;
+    }
+
+    virtual void sourceNeeded(QString &fileName, IncludeType, unsigned)
+    { mergeEnvironment(fileName); }
+
+    virtual void macroAdded(const Macro &) {}
+
+    virtual void startExpandingMacro(unsigned,
+                                     const Macro &,
+                                     const QByteArray &,
+                                     const QVector<MacroArgumentReference> &) {}
+
+    virtual void stopExpandingMacro(unsigned, const Macro &) {}
+
+    virtual void startSkippingBlocks(unsigned) {}
+    virtual void stopSkippingBlocks(unsigned) {}
+
+    void mergeEnvironment(const QString &fileName)
+    {
+        if (! _merged.contains(fileName)) {
+            _merged.insert(fileName);
+
+            if (Document::Ptr doc = _snapshot.value(fileName)) {
+                foreach (const Document::Include &i, doc->includes())
+                    mergeEnvironment(i.fileName());
+
+                _env.addMacros(doc->definedMacros());
+            }
+        }
+    }
+};
+
+class FindClass: public SemanticSearch
+{
+    QString _text;
+    QTextDocument::FindFlags _findFlags;
+
+public:
+    FindClass(QFutureInterface<Core::Utils::FileSearchResult> &future, Document::Ptr doc, Snapshot snapshot)
+        : SemanticSearch(future, doc, snapshot)
+    { }
+
+    void setText(const QString &text)
+    { _text = text; }
+
+    void setFindFlags(QTextDocument::FindFlags findFlags)
+    { _findFlags = findFlags; }
+
+    virtual void run(AST *ast)
+    { accept(ast); }
+
+protected:
+    using ASTVisitor::visit;
+
+    virtual bool visit(ClassSpecifierAST *ast)
+    {
+        if (ast->name) {
+            Qt::CaseSensitivity cs = Qt::CaseInsensitive;
+
+            if (_findFlags & QTextDocument::FindCaseSensitively)
+                cs = Qt::CaseSensitive;
+
+            Token start = tokenAt(ast->name->firstToken());
+            Token end = tokenAt(ast->name->lastToken() - 1);
+            const QString className = QString::fromUtf8(source().constData() + start.begin(),
+                                                        end.end() - start.begin());
+
+            if (className.contains(_text, cs))
+                reportResult(ast->name->firstToken());
+        }
+
+        return true;
+    }
+};
+
+} // end of anonymous namespace
+
+SemanticSearch::SemanticSearch(QFutureInterface<Core::Utils::FileSearchResult> &future,
+                               Document::Ptr doc,
+                               Snapshot snapshot)
+    : ASTVisitor(doc->control()),
+      _future(future),
+      _doc(doc),
+      _snapshot(snapshot)
+{
+    _thisDocument = _snapshot.value(_doc->fileName());
+}
+
+SemanticSearch::~SemanticSearch()
+{ }
+
+const QByteArray &SemanticSearch::source() const
+{ return _source; }
+
+void SemanticSearch::setSource(const QByteArray &source)
+{ _source = source; }
+
+QString SemanticSearch::matchingLine(const Token &tk) const
+{
+    const char *beg = _source.constData();
+    const char *cp = beg + tk.offset;
+    for (; cp != beg - 1; --cp) {
+        if (*cp == '\n')
+            break;
+    }
+
+    ++cp;
+
+    const char *lineEnd = cp + 1;
+    for (; *lineEnd; ++lineEnd) {
+        if (*lineEnd == '\n')
+            break;
+    }
+
+    const QString matchingLine = QString::fromUtf8(cp, lineEnd - cp);
+    return matchingLine;
+}
+
+void SemanticSearch::reportResult(unsigned tokenIndex)
+{
+    const Token &tk = tokenAt(tokenIndex);
+    const QString lineText = matchingLine(tk);
+
+    unsigned line, col;
+    getTokenStartPosition(tokenIndex, &line, &col);
+
+    if (col)
+        --col;  // adjust the column position.
+
+    _future.reportResult(Core::Utils::FileSearchResult(QDir::toNativeSeparators(_doc->fileName()),
+                                                       line, lineText, col, tk.length));
+}
+
+SemanticSearch *SearchClassDeclarationsFactory::create(QFutureInterface<Core::Utils::FileSearchResult> &future,
+                                                       Document::Ptr doc,
+                                                       Snapshot snapshot)
+{
+    FindClass *findClass = new FindClass(future, doc, snapshot);
+    findClass->setText(_text);
+    findClass->setFindFlags(_findFlags);
+    return findClass;
+}
+
+static void semanticSearch_helper(QFutureInterface<Core::Utils::FileSearchResult> &future,
+                                  QPointer<CppModelManager> modelManager,
+                                  SemanticSearchFactory::Ptr factory)
+{
+    const Snapshot snapshot = modelManager->snapshot();
+
+    future.setProgressRange(0, snapshot.size());
+    future.setProgressValue(0);
+
+    int progress = 0;
+    foreach (Document::Ptr doc, snapshot) {
+        const QString fileName = doc->fileName();
+
+        QFile file(fileName);
+        if (! file.open(QFile::ReadOnly))
+            continue;
+
+        const QString contents = QTextStream(&file).readAll(); // ### FIXME
+
+        SimpleClient r(modelManager);
+        const QByteArray source = r.run(fileName, contents.toUtf8());
+
+        Document::Ptr newDoc = Document::create(fileName);
+        newDoc->setSource(source);
+        newDoc->parse();
+
+        if (SemanticSearch *search = factory->create(future, newDoc, snapshot)) {
+            search->setSource(source);
+            search->run(newDoc->translationUnit()->ast());
+            delete search;
+        }
+
+        future.setProgressValue(++progress);
+    }
+}
+
+QFuture<Core::Utils::FileSearchResult> CppTools::Internal::semanticSearch(QPointer<CppModelManager> modelManager,
+                                                                          SemanticSearchFactory::Ptr factory)
+{
+    return QtConcurrent::run(&semanticSearch_helper, modelManager, factory);
+}
diff --git a/src/plugins/cpptools/cppsemanticsearch.h b/src/plugins/cpptools/cppsemanticsearch.h
new file mode 100644
index 00000000000..68c233c8474
--- /dev/null
+++ b/src/plugins/cpptools/cppsemanticsearch.h
@@ -0,0 +1,112 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact:  Qt Software Information (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#ifndef CPPSEMANTICSEARCH_H
+#define CPPSEMANTICSEARCH_H
+
+#include <ASTVisitor.h>
+#include <cplusplus/CppDocument.h>
+
+#include <utils/filesearch.h>
+
+#include <QtCore/QFutureInterface>
+#include <QtCore/QPointer>
+#include <QtCore/QSharedPointer>
+#include <QtGui/QTextDocument>
+
+namespace CppTools {
+namespace Internal {
+
+class CppModelManager;
+class SemanticSearchFactory;
+
+class SemanticSearch: protected CPlusPlus::ASTVisitor
+{
+    QFutureInterface<Core::Utils::FileSearchResult> &_future;
+    CPlusPlus::Document::Ptr _doc;
+    CPlusPlus::Snapshot _snapshot;
+    CPlusPlus::Document::Ptr _thisDocument;
+    QByteArray _source;
+
+public:
+    SemanticSearch(QFutureInterface<Core::Utils::FileSearchResult> &future,
+                   CPlusPlus::Document::Ptr doc,
+                   CPlusPlus::Snapshot snapshot);
+
+    virtual ~SemanticSearch();
+
+    virtual void run(CPlusPlus::AST *ast) = 0;
+
+    const QByteArray &source() const;
+    void setSource(const QByteArray &source);
+
+protected:
+    QString matchingLine(const CPlusPlus::Token &tk) const;
+    void reportResult(unsigned tokenIndex);
+};
+
+class SemanticSearchFactory
+{
+    Q_DISABLE_COPY(SemanticSearchFactory)
+
+public:
+    typedef QSharedPointer<SemanticSearchFactory> Ptr;
+
+    SemanticSearchFactory() {}
+    virtual ~SemanticSearchFactory() {}
+
+    virtual SemanticSearch *create(QFutureInterface<Core::Utils::FileSearchResult> &future,
+                                   CPlusPlus::Document::Ptr doc,
+                                   CPlusPlus::Snapshot snapshot) = 0;
+};
+
+class SearchClassDeclarationsFactory: public SemanticSearchFactory
+{
+    QString _text;
+    QTextDocument::FindFlags _findFlags;
+
+public:
+    SearchClassDeclarationsFactory(const QString &text, QTextDocument::FindFlags findFlags)
+        : _text(text), _findFlags(findFlags)
+    { }
+
+    virtual SemanticSearch *create(QFutureInterface<Core::Utils::FileSearchResult> &future,
+                                   CPlusPlus::Document::Ptr doc,
+                                   CPlusPlus::Snapshot snapshot);
+};
+
+
+QFuture<Core::Utils::FileSearchResult> semanticSearch(QPointer<CppModelManager> modelManager,
+                                                      SemanticSearchFactory::Ptr factory);
+
+
+} // end of namespace Internal
+} // end of namespace CppTools
+
+#endif // CPPSEMANTICSEARCH_H
diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro
index 8a943ff4b79..955145ca619 100644
--- a/src/plugins/cpptools/cpptools.pro
+++ b/src/plugins/cpptools/cpptools.pro
@@ -21,7 +21,8 @@ HEADERS += completionsettingspage.h \
     cpptoolsplugin.h \
     searchsymbols.h \
     cppdoxygen.h \
-    cppfilesettingspage.h
+    cppfilesettingspage.h \
+    cppsemanticsearch.h
 
 SOURCES += completionsettingspage.cpp \
     cppclassesfilter.cpp \
@@ -34,7 +35,8 @@ SOURCES += completionsettingspage.cpp \
     searchsymbols.cpp \
     cppdoxygen.cpp \
     cppfilesettingspage.cpp \
-    abstracteditorsupport.cpp
+    abstracteditorsupport.cpp \
+    cppsemanticsearch.cpp
 
 FORMS += completionsettingspage.ui \
     cppfilesettingspage.ui
diff --git a/src/plugins/cpptools/cpptoolsplugin.cpp b/src/plugins/cpptools/cpptoolsplugin.cpp
index 59ba2ec6fd1..3554805ac06 100644
--- a/src/plugins/cpptools/cpptoolsplugin.cpp
+++ b/src/plugins/cpptools/cpptoolsplugin.cpp
@@ -36,6 +36,7 @@
 #include "cppmodelmanager.h"
 #include "cpptoolsconstants.h"
 #include "cppquickopenfilter.h"
+#include "cppsemanticsearch.h"
 
 #include <extensionsystem/pluginmanager.h>
 
@@ -56,14 +57,6 @@
 #include <find/searchresultwindow.h>
 #include <utils/filesearch.h>
 
-#include <Control.h>
-#include <AST.h>
-#include <ASTVisitor.h>
-#include <TranslationUnit.h>
-
-#include <cplusplus/PreprocessorEnvironment.h>
-#include <cplusplus/pp.h>
-
 #include <QtCore/QtPlugin>
 #include <QtCore/QFileInfo>
 #include <QtCore/QDir>
@@ -81,172 +74,6 @@ enum { debug = 0 };
 
 CppToolsPlugin *CppToolsPlugin::m_instance = 0;
 
-namespace {
-
-class SimpleClient: public Client
-{
-    Environment _env;
-    QPointer<CppModelManager> _modelManager;
-    Snapshot _snapshot;
-    Preprocessor _preproc;
-    QSet<QString> _merged;
-
-public:
-    SimpleClient(QPointer<CppModelManager> modelManager)
-        : _modelManager(modelManager),
-          _snapshot(_modelManager->snapshot()),
-          _preproc(this, &_env)
-    { }
-
-    QByteArray run(QString fileName, const QByteArray &source)
-    {
-        const QByteArray preprocessed = _preproc(fileName, source);
-        return preprocessed;
-    }
-
-    virtual void sourceNeeded(QString &fileName, IncludeType, unsigned)
-    { mergeEnvironment(fileName); }
-
-    virtual void macroAdded(const Macro &) {}
-
-    virtual void startExpandingMacro(unsigned,
-                                     const Macro &,
-                                     const QByteArray &,
-                                     const QVector<MacroArgumentReference> &) {}
-
-    virtual void stopExpandingMacro(unsigned, const Macro &) {}
-
-    virtual void startSkippingBlocks(unsigned) {}
-    virtual void stopSkippingBlocks(unsigned) {}
-
-    void mergeEnvironment(const QString &fileName)
-    {
-        if (! _merged.contains(fileName)) {
-            _merged.insert(fileName);
-
-            if (Document::Ptr doc = _snapshot.value(fileName)) {
-                foreach (const Document::Include &i, doc->includes())
-                    mergeEnvironment(i.fileName());
-
-                _env.addMacros(doc->definedMacros());
-            }
-        }
-    }
-};
-
-class FindClass: protected ASTVisitor
-{
-    QFutureInterface<Core::Utils::FileSearchResult> &_future;
-    Document::Ptr _doc;
-    Snapshot _snapshot;
-    Document::Ptr _thisDocument;
-
-    QByteArray _source;
-    QString _text;
-    QTextDocument::FindFlags _findFlags;
-
-public:
-    FindClass(QFutureInterface<Core::Utils::FileSearchResult> &future, Document::Ptr doc, Snapshot snapshot)
-        : ASTVisitor(doc->control()),
-          _future(future),
-          _doc(doc),
-          _snapshot(snapshot)
-    {
-        _thisDocument = _snapshot.value(_doc->fileName());
-    }
-
-    void operator()(AST *ast, const QByteArray &source, const QString &text,
-                    QTextDocument::FindFlags findFlags)
-    {
-        _source = source;
-        _text = text;
-        _findFlags = findFlags;
-        accept(ast);
-    }
-
-protected:
-    using ASTVisitor::visit;
-
-    virtual bool visit(ClassSpecifierAST *ast)
-    {
-        if (ast->name) {
-            Qt::CaseSensitivity cs = Qt::CaseInsensitive;
-            if (_findFlags & QTextDocument::FindCaseSensitively)
-                cs = Qt::CaseSensitive;
-
-            Token start = tokenAt(ast->name->firstToken());
-            Token end = tokenAt(ast->name->lastToken() - 1);
-            const QString className = QString::fromUtf8(_source.constData() + start.begin(),
-                                                        end.end() - start.begin());
-
-            int idx = className.indexOf(_text, 0, cs);
-            if (idx != -1) {
-                const char *beg = _source.constData();
-                const char *cp = beg + start.offset;
-                for (; cp != beg - 1; --cp) {
-                    if (*cp == '\n')
-                        break;
-                }
-
-                ++cp;
-
-                const char *lineEnd = cp + 1;
-                for (; *lineEnd; ++lineEnd) {
-                    if (*lineEnd == '\n')
-                        break;
-                }
-
-                const QString matchingLine = QString::fromUtf8(cp, lineEnd - cp);
-
-                unsigned line, col;
-                getTokenStartPosition(ast->name->firstToken(), &line, &col);
-
-                _future.reportResult(Core::Utils::FileSearchResult(QDir::toNativeSeparators(_doc->fileName()),
-                                                                   line, matchingLine,
-                                                                   col + idx - 1, _text.length()));
-            }
-        }
-
-        return true;
-    }
-};
-
-static void searchClassDeclarations(QFutureInterface<Core::Utils::FileSearchResult> &future,
-                                    QPointer<CppModelManager> modelManager,
-                                    QString text,
-                                    QTextDocument::FindFlags findFlags)
-{
-    const Snapshot snapshot = modelManager->snapshot();
-
-    future.setProgressRange(0, snapshot.size());
-    future.setProgressValue(0);
-
-    int progress = 0;
-    foreach (Document::Ptr doc, snapshot) {
-        const QString fileName = doc->fileName();
-
-        QFile file(fileName);
-        if (! file.open(QFile::ReadOnly))
-            continue;
-
-        const QString contents = QTextStream(&file).readAll();
-
-        SimpleClient r(modelManager);
-        const QByteArray source = r.run(fileName, contents.toUtf8());
-
-        Document::Ptr newDoc = Document::create(fileName);
-        newDoc->setSource(source);
-        newDoc->parse();
-
-        FindClass findClass(future, newDoc, snapshot);
-        findClass(newDoc->translationUnit()->ast(), source, text, findFlags);
-
-        future.setProgressValue(++progress);
-    }
-}
-
-} // end of anonymous namespace
-
 FindClassDeclarations::FindClassDeclarations(CppModelManager *modelManager)
     : _modelManager(modelManager),
       _resultWindow(ExtensionSystem::PluginManager::instance()->getObject<Find::SearchResultWindow>())
@@ -256,15 +83,16 @@ FindClassDeclarations::FindClassDeclarations(CppModelManager *modelManager)
     connect(&m_watcher, SIGNAL(finished()), this, SLOT(searchFinished()));
 }
 
-void FindClassDeclarations::findAll(const QString &txt, QTextDocument::FindFlags findFlags)
+void FindClassDeclarations::findAll(const QString &text, QTextDocument::FindFlags findFlags)
 {
     _resultWindow->clearContents();
     _resultWindow->popup(true);
 
     Core::ProgressManager *progressManager = Core::ICore::instance()->progressManager();
 
-    QFuture<Core::Utils::FileSearchResult> result =
-            QtConcurrent::run(&searchClassDeclarations, _modelManager, txt, findFlags);
+    SemanticSearchFactory::Ptr factory(new SearchClassDeclarationsFactory(text, findFlags));
+
+    QFuture<Core::Utils::FileSearchResult> result = semanticSearch(_modelManager, factory);
 
     m_watcher.setFuture(result);
 
-- 
GitLab