Commit 7ee70554 authored by Roberto Raggi's avatar Roberto Raggi

Initial support for semantic searches.

parent 6d18c530
......@@ -368,6 +368,7 @@ QByteArray CppPreprocessor::tryIncludeFile(QString &fileName, IncludeType type)
path += frameworkName;
path += QLatin1String(".framework/Headers/");
path += name;
path = QDir::cleanPath(path);
QByteArray contents;
if (includeFile(path, &contents)) {
fileName = path;
......
......@@ -28,7 +28,6 @@
**************************************************************************/
#include "cpptoolsplugin.h"
#include "completionsettingspage.h"
#include "cppfilesettingspage.h"
#include "cppclassesfilter.h"
......@@ -38,14 +37,34 @@
#include "cpptoolsconstants.h"
#include "cppquickopenfilter.h"
#include <extensionsystem/pluginmanager.h>
#include <coreplugin/icore.h>
#include <coreplugin/mimedatabase.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/uniqueidmanager.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <cppeditor/cppeditorconstants.h>
#include <QtCore/QtConcurrentRun>
#include <QtCore/QFutureSynchronizer>
#include <qtconcurrent/runextensions.h>
#include <find/ifindfilter.h>
#include <find/searchresultwindow.h>
#include <utils/filesearch.h>
#include <Control.h>
#include <AST.h>
#include <ASTVisitor.h>
#include <TranslationUnit.h>
#include <PrettyPrinter.h>
#include <cplusplus/PreprocessorEnvironment.h>
#include <cplusplus/pp.h>
#include <QtCore/QtPlugin>
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
......@@ -54,13 +73,230 @@
#include <QtGui/QMenu>
#include <QtGui/QAction>
#include <sstream>
using namespace CppTools::Internal;
using namespace CPlusPlus;
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;
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)
{
}
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, 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>())
{
m_watcher.setPendingResultsLimit(1);
connect(&m_watcher, SIGNAL(resultReadyAt(int)), this, SLOT(displayResult(int)));
connect(&m_watcher, SIGNAL(finished()), this, SLOT(searchFinished()));
}
void FindClassDeclarations::findAll(const QString &txt, 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);
m_watcher.setFuture(result);
Core::FutureProgress *progress = progressManager->addTask(result, tr("Search class"),
CppTools::Constants::TASK_INDEX,
Core::ProgressManager::CloseOnSuccess);
connect(progress, SIGNAL(clicked()), _resultWindow, SLOT(popup()));
}
void FindClassDeclarations::displayResult(int index)
{
Core::Utils::FileSearchResult result = m_watcher.future().resultAt(index);
Find::ResultWindowItem *item = _resultWindow->addResult(result.fileName,
result.lineNumber,
result.matchingLine,
result.matchStart,
result.matchLength);
if (item)
connect(item, SIGNAL(activated(const QString&,int,int)),
this, SLOT(openEditor(const QString&,int,int)));
}
void FindClassDeclarations::searchFinished()
{
emit changed();
}
void FindClassDeclarations::openEditor(const QString &fileName, int line, int column)
{
TextEditor::BaseTextEditor::openEditorAt(fileName, line, column);
}
CppToolsPlugin::CppToolsPlugin() :
m_context(-1),
m_modelManager(0),
......@@ -95,6 +331,8 @@ bool CppToolsPlugin::initialize(const QStringList &arguments, QString *error)
addAutoReleasedObject(new CompletionSettingsPage(m_completion));
addAutoReleasedObject(new CppFileSettingsPage(m_fileSettings));
addAutoReleasedObject(new FindClassDeclarations(m_modelManager));
// Menus
Core::ActionContainer *mtools = am->actionContainer(Core::Constants::M_TOOLS);
Core::ActionContainer *mcpptools = am->createMenu(CppTools::Constants::M_TOOLS_CPP);
......
......@@ -32,13 +32,28 @@
#include <extensionsystem/iplugin.h>
#include <projectexplorer/projectexplorer.h>
#include <find/ifindfilter.h>
#include <utils/filesearch.h>
#include <QtGui/QTextDocument>
#include <QtCore/QSharedPointer>
#include <QtCore/QFutureInterface>
#include <QtCore/QPointer>
#include <QtCore/QFutureWatcher>
QT_BEGIN_NAMESPACE
class QFileInfo;
class QDir;
QT_END_NAMESPACE
namespace CPlusPlus {
class Snapshot;
}
namespace Find {
class SearchResultWindow;
}
namespace CppTools {
namespace Internal {
......@@ -46,6 +61,32 @@ class CppCodeCompletion;
class CppModelManager;
struct CppFileSettings;
class FindClassDeclarations: public Find::IFindFilter
{
Q_OBJECT
public:
FindClassDeclarations(CppModelManager *modelManager);
// Find::IFindFilter
virtual QString id() const { return QLatin1String("CppTools.Find.ClassDeclarations"); }
virtual QString name() const { return tr("Class Declarations"); }
virtual bool isEnabled() const { return true; }
virtual QKeySequence defaultShortcut() const { return QKeySequence(); }
virtual void findAll(const QString &txt, QTextDocument::FindFlags findFlags);
protected Q_SLOTS:
void displayResult(int);
void searchFinished();
void openEditor(const QString&, int, int);
private:
QPointer<CppModelManager> _modelManager;
Find::SearchResultWindow *_resultWindow;
QFutureWatcher<Core::Utils::FileSearchResult> m_watcher;
};
class CppToolsPlugin : public ExtensionSystem::IPlugin
{
Q_DISABLE_COPY(CppToolsPlugin)
......
......@@ -465,6 +465,12 @@ void TranslationUnit::fatal(unsigned index, const char *format, ...)
exit(EXIT_FAILURE);
}
unsigned TranslationUnit::findPreviousLineOffset(unsigned tokenIndex) const
{
unsigned lineOffset = _lineOffsets[findLineNumber(_tokens->at(tokenIndex).offset)];
return lineOffset;
}
void TranslationUnit::showErrorLine(unsigned index, unsigned column, FILE *out)
{
unsigned lineOffset = _lineOffsets[findLineNumber(_tokens->at(index).offset)];
......
......@@ -142,6 +142,8 @@ public:
unsigned line,
StringLiteral *fileName);
unsigned findPreviousLineOffset(unsigned tokenIndex) const;
public:
struct PPLine {
unsigned offset;
......
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