Commit c2a40ce9 authored by Roberto Raggi's avatar Roberto Raggi

Introduced CppTools::Internal::SemanticSearch.

parent b675fe20
/**************************************************************************
**
** 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);
}
/**************************************************************************
**
** 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
......@@ -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
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment