Commit 9246e78d authored by Erik Verbruggen's avatar Erik Verbruggen
Browse files

C++: started to make indexing plug-able.



Change-Id: Iff35840d73882a212dd77b54e4223c0b4111ac1c
Reviewed-by: default avatarErik Verbruggen <erik.verbruggen@digia.com>
parent 80b73725
...@@ -58,6 +58,7 @@ namespace CppTools { ...@@ -58,6 +58,7 @@ namespace CppTools {
class CppCompletionAssistProvider; class CppCompletionAssistProvider;
class CppHighlightingSupport; class CppHighlightingSupport;
class CppHighlightingSupportFactory; class CppHighlightingSupportFactory;
class CppIndexingSupport;
} }
namespace CPlusPlus { namespace CPlusPlus {
...@@ -220,6 +221,8 @@ public: ...@@ -220,6 +221,8 @@ public:
virtual CppTools::CppHighlightingSupport *highlightingSupport(Core::IEditor *editor) const = 0; virtual CppTools::CppHighlightingSupport *highlightingSupport(Core::IEditor *editor) const = 0;
virtual void setHighlightingSupportFactory(CppTools::CppHighlightingSupportFactory *highlightingFactory) = 0; virtual void setHighlightingSupportFactory(CppTools::CppHighlightingSupportFactory *highlightingFactory) = 0;
virtual void addIndexingSupport(CppTools::CppIndexingSupport *indexingSupport) = 0;
Q_SIGNALS: Q_SIGNALS:
void documentUpdated(CPlusPlus::Document::Ptr doc); void documentUpdated(CPlusPlus::Document::Ptr doc);
void sourceFilesRefreshed(const QStringList &files); void sourceFilesRefreshed(const QStringList &files);
......
/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "cppindexingsupport.h"
namespace CppTools {
CppIndexingSupport::~CppIndexingSupport()
{
}
} // namespace CppTools
/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CPPTOOLS_CPPINDEXINGSUPPORT_H
#define CPPTOOLS_CPPINDEXINGSUPPORT_H
#include "cpptools_global.h"
#include <QFuture>
#include <QStringList>
namespace CppTools {
class CPPTOOLS_EXPORT CppIndexingSupport
{
public:
virtual ~CppIndexingSupport() = 0;
virtual QFuture<void> refreshSourceFiles(const QStringList &sourceFiles) = 0;
};
} // namespace CppTools
#endif // CPPTOOLS_CPPINDEXINGSUPPORT_H
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "cppcompletionassist.h" #include "cppcompletionassist.h"
#include "cpphighlightingsupport.h" #include "cpphighlightingsupport.h"
#include "cpphighlightingsupportinternal.h" #include "cpphighlightingsupportinternal.h"
#include "cppindexingsupport.h"
#include "abstracteditorsupport.h" #include "abstracteditorsupport.h"
#include "cpptoolsconstants.h" #include "cpptoolsconstants.h"
#include "cpptoolseditorsupport.h" #include "cpptoolseditorsupport.h"
...@@ -661,6 +662,144 @@ void CppModelManager::updateModifiedSourceFiles() ...@@ -661,6 +662,144 @@ void CppModelManager::updateModifiedSourceFiles()
updateSourceFiles(sourceFiles); updateSourceFiles(sourceFiles);
} }
namespace {
class IndexingSupport: public CppIndexingSupport {
public:
typedef CppModelManagerInterface::WorkingCopy WorkingCopy;
public:
IndexingSupport()
: m_revision(0)
{
m_synchronizer.setCancelOnWait(true);
m_dumpFileNameWhileParsing = !qgetenv("QTCREATOR_DUMP_FILENAME_WHILE_PARSING").isNull();
}
~IndexingSupport()
{}
QFuture<void> refreshSourceFiles(const QStringList &sourceFiles)
{
CppModelManager *mgr = CppModelManager::instance();
const WorkingCopy workingCopy = mgr->workingCopy();
CppPreprocessor *preproc = new CppPreprocessor(mgr, m_dumpFileNameWhileParsing);
preproc->setRevision(++m_revision);
preproc->setProjectFiles(mgr->projectFiles());
preproc->setIncludePaths(mgr->includePaths());
preproc->setFrameworkPaths(mgr->frameworkPaths());
preproc->setWorkingCopy(workingCopy);
QFuture<void> result = QtConcurrent::run(&parse, preproc, sourceFiles);
if (m_synchronizer.futures().size() > 10) {
QList<QFuture<void> > futures = m_synchronizer.futures();
m_synchronizer.clearFutures();
foreach (const QFuture<void> &future, futures) {
if (! (future.isFinished() || future.isCanceled()))
m_synchronizer.addFuture(future);
}
}
m_synchronizer.addFuture(result);
if (sourceFiles.count() > 1) {
Core::ICore::progressManager()->addTask(result,
QCoreApplication::translate("IndexingSupport", "Parsing"),
CppTools::Constants::TASK_INDEX);
}
return result;
}
private:
static void parse(QFutureInterface<void> &future,
CppPreprocessor *preproc,
QStringList files)
{
if (files.isEmpty())
return;
const Core::MimeDatabase *mimeDb = Core::ICore::mimeDatabase();
Core::MimeType cSourceTy = mimeDb->findByType(QLatin1String("text/x-csrc"));
Core::MimeType cppSourceTy = mimeDb->findByType(QLatin1String("text/x-c++src"));
Core::MimeType mSourceTy = mimeDb->findByType(QLatin1String("text/x-objcsrc"));
QStringList sources;
QStringList headers;
QStringList suffixes = cSourceTy.suffixes();
suffixes += cppSourceTy.suffixes();
suffixes += mSourceTy.suffixes();
foreach (const QString &file, files) {
QFileInfo info(file);
preproc->snapshot.remove(file);
if (suffixes.contains(info.suffix()))
sources.append(file);
else
headers.append(file);
}
const int sourceCount = sources.size();
files = sources;
files += headers;
preproc->setTodo(files);
future.setProgressRange(0, files.size());
QString conf = QLatin1String(pp_configuration_file);
bool processingHeaders = false;
for (int i = 0; i < files.size(); ++i) {
if (future.isPaused())
future.waitForResume();
if (future.isCanceled())
break;
const QString fileName = files.at(i);
const bool isSourceFile = i < sourceCount;
if (isSourceFile)
(void) preproc->run(conf);
else if (! processingHeaders) {
(void) preproc->run(conf);
processingHeaders = true;
}
preproc->run(fileName);
future.setProgressValue(files.size() - preproc->todo().size());
if (isSourceFile)
preproc->resetEnvironment();
}
future.setProgressValue(files.size());
preproc->modelManager()->finishedRefreshingSourceFiles(files);
delete preproc;
}
private:
QFutureSynchronizer<void> m_synchronizer;
unsigned m_revision;
bool m_dumpFileNameWhileParsing;
};
} // anonymous namespace
/*! /*!
\class CppTools::CppModelManager \class CppTools::CppModelManager
\brief The CppModelManager keeps track of one CppCodeModel instance \brief The CppModelManager keeps track of one CppCodeModel instance
...@@ -689,10 +828,6 @@ CppModelManager::CppModelManager(QObject *parent) ...@@ -689,10 +828,6 @@ CppModelManager::CppModelManager(QObject *parent)
{ {
m_findReferences = new CppFindReferences(this); m_findReferences = new CppFindReferences(this);
m_indexerEnabled = qgetenv("QTCREATOR_NO_CODE_INDEXER").isNull(); m_indexerEnabled = qgetenv("QTCREATOR_NO_CODE_INDEXER").isNull();
m_dumpFileNameWhileParsing = !qgetenv("QTCREATOR_DUMP_FILENAME_WHILE_PARSING").isNull();
m_revision = 0;
m_synchronizer.setCancelOnWait(true);
m_dirty = true; m_dirty = true;
...@@ -737,6 +872,7 @@ CppModelManager::CppModelManager(QObject *parent) ...@@ -737,6 +872,7 @@ CppModelManager::CppModelManager(QObject *parent)
ExtensionSystem::PluginManager::addObject(m_completionAssistProvider); ExtensionSystem::PluginManager::addObject(m_completionAssistProvider);
m_highlightingFallback = new CppHighlightingSupportInternalFactory; m_highlightingFallback = new CppHighlightingSupportInternalFactory;
m_highlightingFactory = m_highlightingFallback; m_highlightingFactory = m_highlightingFallback;
m_internalIndexingSupport = new IndexingSupport;
} }
CppModelManager::~CppModelManager() CppModelManager::~CppModelManager()
...@@ -744,6 +880,7 @@ CppModelManager::~CppModelManager() ...@@ -744,6 +880,7 @@ CppModelManager::~CppModelManager()
ExtensionSystem::PluginManager::removeObject(m_completionAssistProvider); ExtensionSystem::PluginManager::removeObject(m_completionAssistProvider);
delete m_completionFallback; delete m_completionFallback;
delete m_highlightingFallback; delete m_highlightingFallback;
delete m_internalIndexingSupport;
} }
Snapshot CppModelManager::snapshot() const Snapshot CppModelManager::snapshot() const
...@@ -899,7 +1036,15 @@ CppModelManager::WorkingCopy CppModelManager::workingCopy() const ...@@ -899,7 +1036,15 @@ CppModelManager::WorkingCopy CppModelManager::workingCopy() const
} }
QFuture<void> CppModelManager::updateSourceFiles(const QStringList &sourceFiles) QFuture<void> CppModelManager::updateSourceFiles(const QStringList &sourceFiles)
{ return refreshSourceFiles(sourceFiles); } {
if (sourceFiles.isEmpty() || !m_indexerEnabled)
return QFuture<void>();
foreach (CppIndexingSupport *indexer, m_indexingSupporters)
indexer->refreshSourceFiles(sourceFiles);
return m_internalIndexingSupport->refreshSourceFiles(sourceFiles);
}
QList<CppModelManager::ProjectInfo> CppModelManager::projectInfos() const QList<CppModelManager::ProjectInfo> CppModelManager::projectInfos() const
{ {
...@@ -979,44 +1124,6 @@ QList<CppModelManager::ProjectPart::Ptr> CppModelManager::projectPart(const QStr ...@@ -979,44 +1124,6 @@ QList<CppModelManager::ProjectPart::Ptr> CppModelManager::projectPart(const QStr
return parts; return parts;
} }
QFuture<void> CppModelManager::refreshSourceFiles(const QStringList &sourceFiles)
{
if (! sourceFiles.isEmpty() && m_indexerEnabled) {
const WorkingCopy workingCopy = buildWorkingCopyList();
CppPreprocessor *preproc = new CppPreprocessor(this, m_dumpFileNameWhileParsing);
preproc->setRevision(++m_revision);
preproc->setProjectFiles(projectFiles());
preproc->setIncludePaths(includePaths());
preproc->setFrameworkPaths(frameworkPaths());
preproc->setWorkingCopy(workingCopy);
QFuture<void> result = QtConcurrent::run(&CppModelManager::parse,
preproc, sourceFiles);
if (m_synchronizer.futures().size() > 10) {
QList<QFuture<void> > futures = m_synchronizer.futures();
m_synchronizer.clearFutures();
foreach (const QFuture<void> &future, futures) {
if (! (future.isFinished() || future.isCanceled()))
m_synchronizer.addFuture(future);
}
}
m_synchronizer.addFuture(result);
if (sourceFiles.count() > 1) {
Core::ICore::progressManager()->addTask(result, tr("Parsing"),
CppTools::Constants::TASK_INDEX);
}
return result;
}
return QFuture<void>();
}
/*! /*!
\fn void CppModelManager::editorOpened(Core::IEditor *editor) \fn void CppModelManager::editorOpened(Core::IEditor *editor)
\brief If a C++ editor is opened, the model manager listens to content changes \brief If a C++ editor is opened, the model manager listens to content changes
...@@ -1243,81 +1350,6 @@ void CppModelManager::onAboutToUnloadSession() ...@@ -1243,81 +1350,6 @@ void CppModelManager::onAboutToUnloadSession()
GC(); GC();
} }
void CppModelManager::parse(QFutureInterface<void> &future,
CppPreprocessor *preproc,
QStringList files)
{
if (files.isEmpty())
return;
const Core::MimeDatabase *mimeDb = Core::ICore::mimeDatabase();
Core::MimeType cSourceTy = mimeDb->findByType(QLatin1String("text/x-csrc"));
Core::MimeType cppSourceTy = mimeDb->findByType(QLatin1String("text/x-c++src"));
Core::MimeType mSourceTy = mimeDb->findByType(QLatin1String("text/x-objcsrc"));
QStringList sources;
QStringList headers;
QStringList suffixes = cSourceTy.suffixes();
suffixes += cppSourceTy.suffixes();
suffixes += mSourceTy.suffixes();
foreach (const QString &file, files) {
QFileInfo info(file);
preproc->snapshot.remove(file);
if (suffixes.contains(info.suffix()))
sources.append(file);
else
headers.append(file);
}
const int sourceCount = sources.size();
files = sources;
files += headers;
preproc->setTodo(files);
future.setProgressRange(0, files.size());
QString conf = QLatin1String(pp_configuration_file);
bool processingHeaders = false;
for (int i = 0; i < files.size(); ++i) {
if (future.isPaused())
future.waitForResume();
if (future.isCanceled())
break;
const QString fileName = files.at(i);
const bool isSourceFile = i < sourceCount;
if (isSourceFile)
(void) preproc->run(conf);
else if (! processingHeaders) {
(void) preproc->run(conf);
processingHeaders = true;
}
preproc->run(fileName);
future.setProgressValue(files.size() - preproc->todo().size());
if (isSourceFile)
preproc->resetEnvironment();
}
future.setProgressValue(files.size());
preproc->modelManager()->finishedRefreshingSourceFiles(files);
delete preproc;
}
void CppModelManager::GC() void CppModelManager::GC()
{ {
protectSnapshot.lock(); protectSnapshot.lock();
...@@ -1399,6 +1431,12 @@ void CppModelManager::setHighlightingSupportFactory(CppHighlightingSupportFactor ...@@ -1399,6 +1431,12 @@ void CppModelManager::setHighlightingSupportFactory(CppHighlightingSupportFactor
m_highlightingFactory = m_highlightingFallback; m_highlightingFactory = m_highlightingFallback;
} }
void CppModelManager::addIndexingSupport(CppIndexingSupport *indexingSupport)
{
if (indexingSupport)
m_indexingSupporters.append(indexingSupport);
}
void CppModelManager::setExtraDiagnostics(const QString &fileName, int kind, void CppModelManager::setExtraDiagnostics(const QString &fileName, int kind,
const QList<Document::DiagnosticMessage> &diagnostics) const QList<Document::DiagnosticMessage> &diagnostics)
{ {
......
...@@ -96,8 +96,6 @@ public: ...@@ -96,8 +96,6 @@ public:
virtual CPlusPlus::Snapshot snapshot() const; virtual CPlusPlus::Snapshot snapshot() const;
virtual void GC(); virtual void GC();
QFuture<void> refreshSourceFiles(const QStringList &sourceFiles);
virtual bool isCppEditor(Core::IEditor *editor) const; virtual bool isCppEditor(Core::IEditor *editor) const;
CppEditorSupport *editorSupport(TextEditor::ITextEditor *editor) const CppEditorSupport *editorSupport(TextEditor::ITextEditor *editor) const
...@@ -133,30 +131,7 @@ public: ...@@ -133,30 +131,7 @@ public:
virtual CppHighlightingSupport *highlightingSupport(Core::IEditor *editor) const; virtual CppHighlightingSupport *highlightingSupport(Core::IEditor *editor) const;
virtual void setHighlightingSupportFactory(CppHighlightingSupportFactory *highlightingFactory); virtual void setHighlightingSupportFactory(CppHighlightingSupportFactory *highlightingFactory);
Q_SIGNALS: virtual void addIndexingSupport(CppIndexingSupport *indexingSupport);
void projectPathChanged(const QString &projectPath);
void aboutToRemoveFiles(const QStringList &files);
public Q_SLOTS:
void editorOpened(Core::IEditor *editor);
void editorAboutToClose(Core::IEditor *editor);
virtual void updateModifiedSourceFiles();
private Q_SLOTS:
// this should be executed in the GUI thread.
void onDocumentUpdated(CPlusPlus::Document::Ptr doc);
void onExtraDiagnosticsUpdated(const QString &fileName);
void onAboutToRemoveProject(ProjectExplorer::Project *project);
void onAboutToUnloadSession();
void onProjectAdded(ProjectExplorer::Project *project);
void postEditorUpdate();
void updateEditorSelections();
private:
void updateEditor(CPlusPlus::Document::Ptr doc);
WorkingCopy buildWorkingCopyList();
QStringList projectFiles() QStringList projectFiles()
{ {
...@@ -182,16 +157,37 @@ private: ...@@ -182,16 +157,37 @@ private:
return m_definedMacros; return m_definedMacros;
} }
Q_SIGNALS:
void projectPathChanged(const QString &projectPath);
void aboutToRemoveFiles(const QStringList &files);
public Q_SLOTS:
void editorOpened(Core::IEditor *editor);
void editorAboutToClose(Core::IEditor *editor);
virtual void updateModifiedSourceFiles();
private Q_SLOTS:
// this should be executed in the GUI thread.
void onDocumentUpdated(CPlusPlus::Document::Ptr doc);
void onExtraDiagnosticsUpdated(const QString &fileName);
void onAboutToRemoveProject(ProjectExplorer::Project *project);
void onAboutToUnloadSession();
void onProjectAdded(ProjectExplorer::Project *project);
void postEditorUpdate();
void updateEditorSelections();
private:
void updateEditor(CPlusPlus::Document::Ptr doc);
WorkingCopy buildWorkingCopyList();
void ensureUpdated(); void ensureUpdated();
QStringList internalProjectFiles() const; QStringList internalProjectFiles() const;
QStringList internalIncludePaths() const; QStringList internalIncludePaths() const;
QStringList internalFrameworkPaths() const; QStringList internalFrameworkPaths() const;
QByteArray internalDefinedMacros() const; QByteArray internalDefinedMacros() const;
static void parse(QFutureInterface<void> &future,
CppPreprocessor *preproc,
QStringList files);
private: private:
static QMutex m_modelManagerMutex; static QMutex m_modelManagerMutex;
static CppModelManager *m_modelManagerInstance; static CppModelManager *m_modelManagerInstance;
...@@ -233,12 +229,8 @@ private: ...@@ -233,12 +229,8 @@ private:
QTimer *m_updateEditorSelectionsTimer; QTimer *m_updateEditorSelectionsTimer;
QFutureSynchronizer<void> m_synchronizer;
unsigned m_revision;
CppFindReferences *m_findReferences; CppFindReferences *m_findReferences;
bool m_indexerEnabled; bool m_indexerEnabled;
bool m_dumpFileNameWhileParsing;