Commit 27e343b9 authored by Nikolai Kosjar's avatar Nikolai Kosjar Committed by Erik Verbruggen

CppTools: Extract BaseEditorDocumentParser out of SnapshotUpdater

Change-Id: If89e81eec6d600d3d39cc09203cf434d0768c1b4
Reviewed-by: default avatarErik Verbruggen <erik.verbruggen@digia.com>
parent 6b5298fa
...@@ -1413,7 +1413,7 @@ void CppCodeModelInspectorDialog::refresh() ...@@ -1413,7 +1413,7 @@ void CppCodeModelInspectorDialog::refresh()
// Project Parts // Project Parts
const ProjectPart::Ptr editorsProjectPart = editorSupport const ProjectPart::Ptr editorsProjectPart = editorSupport
? editorSupport->snapshotUpdater()->currentProjectPart() ? editorSupport->snapshotUpdater()->projectPart()
: ProjectPart::Ptr(); : ProjectPart::Ptr();
const QList<ProjectInfo> projectInfos = cmmi->projectInfos(); const QList<ProjectInfo> projectInfos = cmmi->projectInfos();
......
/****************************************************************************
**
** Copyright (C) 2014 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 "baseeditordocumentparser.h"
namespace CppTools {
/*!
\class CppTools::BaseEditorDocumentParser
\brief The BaseEditorDocumentParser class parses a source text as
precisely as possible.
It's meant to be used in the C++ editor to get precise results by using
the "best" project part for a file.
Derived classes are expected to implement update() by using the protected
mutex, updateProjectPart() and by respecting the options set by the client.
*/
BaseEditorDocumentParser::BaseEditorDocumentParser(const QString &filePath)
: m_mutex(QMutex::Recursive)
, m_filePath(filePath)
, m_usePrecompiledHeaders(false)
, m_editorDefinesChangedSinceLastUpdate(false)
{
}
BaseEditorDocumentParser::~BaseEditorDocumentParser()
{
}
QString BaseEditorDocumentParser::filePath() const
{
return m_filePath;
}
ProjectPart::Ptr BaseEditorDocumentParser::projectPart() const
{
QMutexLocker locker(&m_mutex);
return m_projectPart;
}
void BaseEditorDocumentParser::setProjectPart(ProjectPart::Ptr projectPart)
{
QMutexLocker locker(&m_mutex);
m_manuallySetProjectPart = projectPart;
}
bool BaseEditorDocumentParser::usePrecompiledHeaders() const
{
QMutexLocker locker(&m_mutex);
return m_usePrecompiledHeaders;
}
void BaseEditorDocumentParser::setUsePrecompiledHeaders(bool usePrecompiledHeaders)
{
QMutexLocker locker(&m_mutex);
m_usePrecompiledHeaders = usePrecompiledHeaders;
}
QByteArray BaseEditorDocumentParser::editorDefines() const
{
QMutexLocker locker(&m_mutex);
return m_editorDefines;
}
void BaseEditorDocumentParser::setEditorDefines(const QByteArray &editorDefines)
{
QMutexLocker locker(&m_mutex);
if (editorDefines != m_editorDefines) {
m_editorDefines = editorDefines;
m_editorDefinesChangedSinceLastUpdate = true;
}
}
void BaseEditorDocumentParser::updateProjectPart()
{
if (m_manuallySetProjectPart) {
m_projectPart = m_manuallySetProjectPart;
return;
}
CppModelManagerInterface *cmm = CppModelManagerInterface::instance();
QList<ProjectPart::Ptr> projectParts = cmm->projectPart(m_filePath);
if (projectParts.isEmpty()) {
if (m_projectPart)
// File is not directly part of any project, but we got one before. We will re-use it,
// because re-calculating this can be expensive when the dependency table is big.
return;
// Fall-back step 1: Get some parts through the dependency table:
projectParts = cmm->projectPartFromDependencies(m_filePath);
if (projectParts.isEmpty())
// Fall-back step 2: Use fall-back part from the model manager:
m_projectPart = cmm->fallbackProjectPart();
else
m_projectPart = projectParts.first();
} else {
if (!projectParts.contains(m_projectPart))
// Apparently the project file changed, so update our project part.
m_projectPart = projectParts.first();
}
}
bool BaseEditorDocumentParser::editorDefinesChanged() const
{
return m_editorDefinesChangedSinceLastUpdate;
}
void BaseEditorDocumentParser::resetEditorDefinesChanged()
{
m_editorDefinesChangedSinceLastUpdate = false;
}
} // namespace CppTools
/****************************************************************************
**
** Copyright (C) 2014 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 BASEEDITORDOCUMENTPARSER_H
#define BASEEDITORDOCUMENTPARSER_H
#include "cppmodelmanagerinterface.h"
#include "cpptools_global.h"
namespace CppTools {
class CPPTOOLS_EXPORT BaseEditorDocumentParser
{
Q_DISABLE_COPY(BaseEditorDocumentParser)
BaseEditorDocumentParser();
public:
BaseEditorDocumentParser(const QString &filePath);
virtual ~BaseEditorDocumentParser();
QString filePath() const;
virtual void update(WorkingCopy workingCopy) = 0;
ProjectPart::Ptr projectPart() const;
void setProjectPart(ProjectPart::Ptr projectPart);
bool usePrecompiledHeaders() const;
void setUsePrecompiledHeaders(bool usePrecompiledHeaders);
QByteArray editorDefines() const;
void setEditorDefines(const QByteArray &editorDefines);
protected:
void updateProjectPart();
bool editorDefinesChanged() const;
void resetEditorDefinesChanged();
protected:
mutable QMutex m_mutex;
private:
const QString m_filePath;
ProjectPart::Ptr m_projectPart;
ProjectPart::Ptr m_manuallySetProjectPart;
bool m_usePrecompiledHeaders;
QByteArray m_editorDefines;
bool m_editorDefinesChangedSinceLastUpdate;
};
} // namespace CppTools
#endif // BASEEDITORDOCUMENTPARSER_H
...@@ -36,11 +36,8 @@ using namespace CPlusPlus; ...@@ -36,11 +36,8 @@ using namespace CPlusPlus;
using namespace CppTools; using namespace CppTools;
using namespace CppTools::Internal; using namespace CppTools::Internal;
SnapshotUpdater::SnapshotUpdater(const QString &fileInEditor) SnapshotUpdater::SnapshotUpdater(const QString &filePath)
: m_mutex(QMutex::Recursive) : BaseEditorDocumentParser(filePath)
, m_fileInEditor(fileInEditor)
, m_editorDefinesChangedSinceLastUpdate(false)
, m_usePrecompiledHeaders(false)
, m_forceSnapshotInvalidation(false) , m_forceSnapshotInvalidation(false)
, m_releaseSourceAndAST(true) , m_releaseSourceAndAST(true)
{ {
...@@ -50,10 +47,10 @@ void SnapshotUpdater::update(WorkingCopy workingCopy) ...@@ -50,10 +47,10 @@ void SnapshotUpdater::update(WorkingCopy workingCopy)
{ {
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
if (m_fileInEditor.isEmpty()) if (filePath().isEmpty())
return; return;
bool invalidateSnapshot = false, invalidateConfig = false, editorDefinesChanged = false; bool invalidateSnapshot = false, invalidateConfig = false, editorDefinesChanged_ = false;
CppModelManager *modelManager CppModelManager *modelManager
= dynamic_cast<CppModelManager *>(CppModelManagerInterface::instance()); = dynamic_cast<CppModelManager *>(CppModelManagerInterface::instance());
...@@ -69,13 +66,13 @@ void SnapshotUpdater::update(WorkingCopy workingCopy) ...@@ -69,13 +66,13 @@ void SnapshotUpdater::update(WorkingCopy workingCopy)
m_forceSnapshotInvalidation = false; m_forceSnapshotInvalidation = false;
} }
if (m_projectPart) { if (const ProjectPart::Ptr part = projectPart()) {
configFile += m_projectPart->toolchainDefines; configFile += part->toolchainDefines;
configFile += m_projectPart->projectDefines; configFile += part->projectDefines;
headerPaths = m_projectPart->headerPaths; headerPaths = part->headerPaths;
projectConfigFile = m_projectPart->projectConfigFile; projectConfigFile = part->projectConfigFile;
if (m_usePrecompiledHeaders) if (usePrecompiledHeaders())
precompiledHeaders = m_projectPart->precompiledHeaders; precompiledHeaders = part->precompiledHeaders;
} }
if (configFile != m_configFile) { if (configFile != m_configFile) {
...@@ -84,10 +81,10 @@ void SnapshotUpdater::update(WorkingCopy workingCopy) ...@@ -84,10 +81,10 @@ void SnapshotUpdater::update(WorkingCopy workingCopy)
invalidateConfig = true; invalidateConfig = true;
} }
if (m_editorDefinesChangedSinceLastUpdate) { if (editorDefinesChanged()) {
invalidateSnapshot = true; invalidateSnapshot = true;
editorDefinesChanged = true; editorDefinesChanged_ = true;
m_editorDefinesChangedSinceLastUpdate = false; resetEditorDefinesChanged();
} }
if (headerPaths != m_headerPaths) { if (headerPaths != m_headerPaths) {
...@@ -144,18 +141,18 @@ void SnapshotUpdater::update(WorkingCopy workingCopy) ...@@ -144,18 +141,18 @@ void SnapshotUpdater::update(WorkingCopy workingCopy)
m_snapshot.remove(configurationFileName); m_snapshot.remove(configurationFileName);
if (!m_snapshot.contains(configurationFileName)) if (!m_snapshot.contains(configurationFileName))
workingCopy.insert(configurationFileName, m_configFile); workingCopy.insert(configurationFileName, m_configFile);
m_snapshot.remove(m_fileInEditor); m_snapshot.remove(filePath());
static const QString editorDefinesFileName static const QString editorDefinesFileName
= CppModelManagerInterface::editorConfigurationFileName(); = CppModelManagerInterface::editorConfigurationFileName();
if (editorDefinesChanged) { if (editorDefinesChanged_) {
m_snapshot.remove(editorDefinesFileName); m_snapshot.remove(editorDefinesFileName);
workingCopy.insert(editorDefinesFileName, m_editorDefines); workingCopy.insert(editorDefinesFileName, editorDefines());
} }
CppSourceProcessor sourceProcessor(m_snapshot, [&](const Document::Ptr &doc) { CppSourceProcessor sourceProcessor(m_snapshot, [&](const Document::Ptr &doc) {
const QString fileName = doc->fileName(); const QString fileName = doc->fileName();
const bool isInEditor = fileName == fileInEditor(); const bool isInEditor = fileName == filePath();
Document::Ptr otherDoc = modelManager->document(fileName); Document::Ptr otherDoc = modelManager->document(fileName);
unsigned newRev = otherDoc.isNull() ? 1U : otherDoc->revision() + 1; unsigned newRev = otherDoc.isNull() ? 1U : otherDoc->revision() + 1;
if (isInEditor) if (isInEditor)
...@@ -166,22 +163,21 @@ void SnapshotUpdater::update(WorkingCopy workingCopy) ...@@ -166,22 +163,21 @@ void SnapshotUpdater::update(WorkingCopy workingCopy)
doc->releaseSourceAndAST(); doc->releaseSourceAndAST();
}); });
Snapshot globalSnapshot = modelManager->snapshot(); Snapshot globalSnapshot = modelManager->snapshot();
globalSnapshot.remove(fileInEditor()); globalSnapshot.remove(filePath());
sourceProcessor.setGlobalSnapshot(globalSnapshot); sourceProcessor.setGlobalSnapshot(globalSnapshot);
sourceProcessor.setWorkingCopy(workingCopy); sourceProcessor.setWorkingCopy(workingCopy);
sourceProcessor.setHeaderPaths(m_headerPaths); sourceProcessor.setHeaderPaths(m_headerPaths);
sourceProcessor.run(configurationFileName); sourceProcessor.run(configurationFileName);
if (!m_projectConfigFile.isEmpty()) if (!m_projectConfigFile.isEmpty())
sourceProcessor.run(m_projectConfigFile); sourceProcessor.run(m_projectConfigFile);
if (m_usePrecompiledHeaders) { if (usePrecompiledHeaders()) {
foreach (const QString &precompiledHeader, m_precompiledHeaders) foreach (const QString &precompiledHeader, m_precompiledHeaders)
sourceProcessor.run(precompiledHeader); sourceProcessor.run(precompiledHeader);
} }
if (!m_editorDefines.isEmpty()) if (!editorDefines().isEmpty())
sourceProcessor.run(editorDefinesFileName); sourceProcessor.run(editorDefinesFileName);
sourceProcessor.run(m_fileInEditor, m_usePrecompiledHeaders ? m_precompiledHeaders sourceProcessor.run(filePath(), usePrecompiledHeaders() ? m_precompiledHeaders
: QStringList()); : QStringList());
m_snapshot = sourceProcessor.snapshot(); m_snapshot = sourceProcessor.snapshot();
Snapshot newSnapshot = m_snapshot.simplified(document()); Snapshot newSnapshot = m_snapshot.simplified(document());
for (Snapshot::const_iterator i = m_snapshot.begin(), ei = m_snapshot.end(); i != ei; ++i) { for (Snapshot::const_iterator i = m_snapshot.begin(), ei = m_snapshot.end(); i != ei; ++i) {
...@@ -193,7 +189,7 @@ void SnapshotUpdater::update(WorkingCopy workingCopy) ...@@ -193,7 +189,7 @@ void SnapshotUpdater::update(WorkingCopy workingCopy)
} }
} }
void SnapshotUpdater::releaseSnapshot() void SnapshotUpdater::releaseResources()
{ {
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
m_snapshot = Snapshot(); m_snapshot = Snapshot();
...@@ -204,7 +200,7 @@ void SnapshotUpdater::releaseSnapshot() ...@@ -204,7 +200,7 @@ void SnapshotUpdater::releaseSnapshot()
Document::Ptr SnapshotUpdater::document() const Document::Ptr SnapshotUpdater::document() const
{ {
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
return m_snapshot.document(m_fileInEditor); return m_snapshot.document(filePath());
} }
Snapshot SnapshotUpdater::snapshot() const Snapshot SnapshotUpdater::snapshot() const
...@@ -219,73 +215,16 @@ ProjectPart::HeaderPaths SnapshotUpdater::headerPaths() const ...@@ -219,73 +215,16 @@ ProjectPart::HeaderPaths SnapshotUpdater::headerPaths() const
return m_headerPaths; return m_headerPaths;
} }
ProjectPart::Ptr SnapshotUpdater::currentProjectPart() const
{
QMutexLocker locker(&m_mutex);
return m_projectPart;
}
void SnapshotUpdater::setProjectPart(ProjectPart::Ptr projectPart)
{
QMutexLocker locker(&m_mutex);
m_manuallySetProjectPart = projectPart;
}
void SnapshotUpdater::setUsePrecompiledHeaders(bool usePrecompiledHeaders)
{
QMutexLocker locker(&m_mutex);
m_usePrecompiledHeaders = usePrecompiledHeaders;
}
void SnapshotUpdater::setEditorDefines(const QByteArray &editorDefines)
{
QMutexLocker locker(&m_mutex);
if (editorDefines != m_editorDefines) {
m_editorDefines = editorDefines;
m_editorDefinesChangedSinceLastUpdate = true;
}
}
void SnapshotUpdater::setReleaseSourceAndAST(bool onoff) void SnapshotUpdater::setReleaseSourceAndAST(bool onoff)
{ {
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
m_releaseSourceAndAST = onoff; m_releaseSourceAndAST = onoff;
} }
void SnapshotUpdater::updateProjectPart()
{
if (m_manuallySetProjectPart) {
m_projectPart = m_manuallySetProjectPart;
return;
}
CppModelManager *cmm = dynamic_cast<CppModelManager *>(CppModelManagerInterface::instance());
QList<ProjectPart::Ptr> pParts = cmm->projectPart(m_fileInEditor);
if (pParts.isEmpty()) {
if (m_projectPart)
// File is not directly part of any project, but we got one before. We will re-use it,
// because re-calculating this can be expensive when the dependency table is big.
return;
// Fall-back step 1: Get some parts through the dependency table:
pParts = cmm->projectPartFromDependencies(m_fileInEditor);
if (pParts.isEmpty())
// Fall-back step 2: Use fall-back part from the model manager:
m_projectPart = cmm->fallbackProjectPart();
else
m_projectPart = pParts.first();
} else {
if (!pParts.contains(m_projectPart))
// Apparently the project file changed, so update our project part.
m_projectPart = pParts.first();
}
}
void SnapshotUpdater::addFileAndDependencies(QSet<QString> *toRemove, const QString &fileName) const void SnapshotUpdater::addFileAndDependencies(QSet<QString> *toRemove, const QString &fileName) const
{ {
toRemove->insert(fileName); toRemove->insert(fileName);
if (fileName != m_fileInEditor) { if (fileName != filePath()) {
QStringList deps = m_deps.filesDependingOn(fileName); QStringList deps = m_deps.filesDependingOn(fileName);
toRemove->unite(QSet<QString>::fromList(deps)); toRemove->unite(QSet<QString>::fromList(deps));
} }
......
...@@ -30,59 +30,45 @@ ...@@ -30,59 +30,45 @@
#ifndef CPPTOOLS_INTERNAL_SNAPSHOTUPDATER_H #ifndef CPPTOOLS_INTERNAL_SNAPSHOTUPDATER_H
#define CPPTOOLS_INTERNAL_SNAPSHOTUPDATER_H #define CPPTOOLS_INTERNAL_SNAPSHOTUPDATER_H
#include "baseeditordocumentparser.h"
#include "cpptools_global.h" #include "cpptools_global.h"
#include "cppmodelmanager.h" #include "cppmodelmanager.h"
#include <cplusplus/CppDocument.h> #include <cplusplus/CppDocument.h>
#include <cplusplus/DependencyTable.h> #include <cplusplus/DependencyTable.h>
#include <utils/qtcoverride.h>
#include <QMutex> #include <QMutex>
#include <QString> #include <QString>
namespace CppTools { namespace CppTools {
class CPPTOOLS_EXPORT SnapshotUpdater class CPPTOOLS_EXPORT SnapshotUpdater : public BaseEditorDocumentParser
{ {
Q_DISABLE_COPY(SnapshotUpdater)
public: public:
SnapshotUpdater(const QString &fileInEditor = QString()); SnapshotUpdater(const QString &filePath);
QString fileInEditor() const
{ return m_fileInEditor; }
void update(WorkingCopy workingCopy); void update(WorkingCopy workingCopy) QTC_OVERRIDE;
void releaseSnapshot(); void releaseResources();
CPlusPlus::Document::Ptr document() const; CPlusPlus::Document::Ptr document() const;
CPlusPlus::Snapshot snapshot() const; CPlusPlus::Snapshot snapshot() const;
ProjectPart::HeaderPaths headerPaths() const; ProjectPart::HeaderPaths headerPaths() const;
ProjectPart::Ptr currentProjectPart() const;
void setProjectPart(ProjectPart::Ptr projectPart);
void setUsePrecompiledHeaders(bool usePrecompiledHeaders);
void setEditorDefines(const QByteArray &editorDefines);
void setReleaseSourceAndAST(bool onoff); void setReleaseSourceAndAST(bool onoff);
private: private:
void updateProjectPart();
void addFileAndDependencies(QSet<QString> *toRemove, const QString &fileName) const; void addFileAndDependencies(QSet<QString> *toRemove, const QString &fileName) const;
private: private:
mutable QMutex m_mutex;
const QString m_fileInEditor;
ProjectPart::Ptr m_projectPart, m_manuallySetProjectPart;
QByteArray m_configFile; QByteArray m_configFile;
bool m_editorDefinesChangedSinceLastUpdate;
QByteArray m_editorDefines;
ProjectPart::HeaderPaths m_headerPaths; ProjectPart::HeaderPaths m_headerPaths;
QString m_projectConfigFile; QString m_projectConfigFile;
QStringList m_precompiledHeaders; QStringList m_precompiledHeaders;
CPlusPlus::Snapshot m_snapshot; CPlusPlus::Snapshot m_snapshot;
CPlusPlus::DependencyTable m_deps; CPlusPlus::DependencyTable m_deps;
bool m_usePrecompiledHeaders;
bool m_forceSnapshotInvalidation; bool m_forceSnapshotInvalidation;
bool m_releaseSourceAndAST; bool m_releaseSourceAndAST;
}; };
......
...@@ -4,6 +4,7 @@ include(../../qtcreatorplugin.pri) ...@@ -4,6 +4,7 @@ include(../../qtcreatorplugin.pri)
HEADERS += \ HEADERS += \
abstracteditorsupport.h \ abstracteditorsupport.h \
baseeditordocumentparser.h \
builtinindexingsupport.h \ builtinindexingsupport.h \
commentssettings.h \ commentssettings.h \
completionsettingspage.h \ completionsettingspage.h \
...@@ -62,6 +63,7 @@ HEADERS += \ ...@@ -62,6 +63,7 @@ HEADERS += \
SOURCES += \ SOURCES += \
abstracteditorsupport.cpp \ abstracteditorsupport.cpp \
baseeditordocumentparser.cpp \
builtinindexingsupport.cpp \ builtinindexingsupport.cpp \
commentssettings.cpp \ commentssettings.cpp \
completionsettingspage.cpp \ completionsettingspage.cpp \
......
...@@ -24,6 +24,7 @@ QtcPlugin { ...@@ -24,6 +24,7 @@ QtcPlugin {