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