Clang: Reparse only if files are changed

Includes are now watched by a file watcher. Unsaved file changes are
watched too. If they are changed the translation units which depend on
them are set to a state which require a reparse. Later the diagnostics
of this units are collected and send back to creator.

Change-Id: I2fb5c7dd6644687f22399edd8d18edd6215c9505
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@theqtcompany.com>
This commit is contained in:
Marco Bubke
2015-08-31 12:40:14 +02:00
parent aa6aaee510
commit f2b7371af1
39 changed files with 800 additions and 242 deletions

View File

@@ -57,6 +57,7 @@ ConnectionServer::ConnectionServer(const QString &connectionName)
ConnectionServer::~ConnectionServer() ConnectionServer::~ConnectionServer()
{ {
killTimer(aliveTimerId);
removeServer(); removeServer();
} }

View File

@@ -38,11 +38,9 @@
namespace ClangBackEnd { namespace ClangBackEnd {
DiagnosticsChangedMessage::DiagnosticsChangedMessage(const FileContainer &file, DiagnosticsChangedMessage::DiagnosticsChangedMessage(const FileContainer &file,
const QVector<DiagnosticContainer> &diagnostics, const QVector<DiagnosticContainer> &diagnostics)
quint32 documentRevision)
: file_(file), : file_(file),
diagnostics_(diagnostics), diagnostics_(diagnostics)
documentRevision_(documentRevision)
{ {
} }
@@ -56,16 +54,10 @@ const QVector<DiagnosticContainer> &DiagnosticsChangedMessage::diagnostics() con
return diagnostics_; return diagnostics_;
} }
quint32 DiagnosticsChangedMessage::documentRevision() const
{
return documentRevision_;
}
QDataStream &operator<<(QDataStream &out, const DiagnosticsChangedMessage &message) QDataStream &operator<<(QDataStream &out, const DiagnosticsChangedMessage &message)
{ {
out << message.file_; out << message.file_;
out << message.diagnostics_; out << message.diagnostics_;
out << message.documentRevision_;
return out; return out;
} }
@@ -74,7 +66,6 @@ QDataStream &operator>>(QDataStream &in, DiagnosticsChangedMessage &message)
{ {
in >> message.file_; in >> message.file_;
in >> message.diagnostics_; in >> message.diagnostics_;
in >> message.documentRevision_;
return in; return in;
} }
@@ -94,8 +85,7 @@ bool operator<(const DiagnosticsChangedMessage &first, const DiagnosticsChangedM
QDebug operator<<(QDebug debug, const DiagnosticsChangedMessage &message) QDebug operator<<(QDebug debug, const DiagnosticsChangedMessage &message)
{ {
debug.nospace() << "DiagnosticsChangedMessage(" debug.nospace() << "DiagnosticsChangedMessage("
<< message.file_ << QStringLiteral(", ") << message.file_
<< message.documentRevision_
<< ")"; << ")";
return debug; return debug;

View File

@@ -51,17 +51,14 @@ class CMBIPC_EXPORT DiagnosticsChangedMessage
public: public:
DiagnosticsChangedMessage() = default; DiagnosticsChangedMessage() = default;
DiagnosticsChangedMessage(const FileContainer &file, DiagnosticsChangedMessage(const FileContainer &file,
const QVector<DiagnosticContainer> &diagnostics, const QVector<DiagnosticContainer> &diagnostics);
quint32 documentRevision);
const FileContainer &file() const; const FileContainer &file() const;
const QVector<DiagnosticContainer> &diagnostics() const; const QVector<DiagnosticContainer> &diagnostics() const;
quint32 documentRevision() const;
private: private:
FileContainer file_; FileContainer file_;
QVector<DiagnosticContainer> diagnostics_; QVector<DiagnosticContainer> diagnostics_;
quint32 documentRevision_;
}; };
CMBIPC_EXPORT QDataStream &operator<<(QDataStream &out, const DiagnosticsChangedMessage &message); CMBIPC_EXPORT QDataStream &operator<<(QDataStream &out, const DiagnosticsChangedMessage &message);

View File

@@ -39,17 +39,29 @@
namespace ClangBackEnd { namespace ClangBackEnd {
FileContainer::FileContainer(const Utf8String &fileName, FileContainer::FileContainer(const Utf8String &filePath,
const Utf8String &projectPartId, const Utf8String &projectPartId,
const Utf8String &unsavedFileContent, const Utf8String &unsavedFileContent,
bool hasUnsavedFileContent) bool hasUnsavedFileContent,
: filePath_(fileName), quint32 documentRevision)
: filePath_(filePath),
projectPartId_(projectPartId), projectPartId_(projectPartId),
unsavedFileContent_(unsavedFileContent), unsavedFileContent_(unsavedFileContent),
documentRevision_(documentRevision),
hasUnsavedFileContent_(hasUnsavedFileContent) hasUnsavedFileContent_(hasUnsavedFileContent)
{ {
} }
FileContainer::FileContainer(const Utf8String &filePath,
const Utf8String &projectPartId,
quint32 documentRevision)
: filePath_(filePath),
projectPartId_(projectPartId),
documentRevision_(documentRevision),
hasUnsavedFileContent_(false)
{
}
const Utf8String &FileContainer::filePath() const const Utf8String &FileContainer::filePath() const
{ {
return filePath_; return filePath_;
@@ -70,11 +82,17 @@ bool FileContainer::hasUnsavedFileContent() const
return hasUnsavedFileContent_; return hasUnsavedFileContent_;
} }
quint32 FileContainer::documentRevision() const
{
return documentRevision_;
}
QDataStream &operator<<(QDataStream &out, const FileContainer &container) QDataStream &operator<<(QDataStream &out, const FileContainer &container)
{ {
out << container.filePath_; out << container.filePath_;
out << container.projectPartId_; out << container.projectPartId_;
out << container.unsavedFileContent_; out << container.unsavedFileContent_;
out << container.documentRevision_;
out << container.hasUnsavedFileContent_; out << container.hasUnsavedFileContent_;
return out; return out;
@@ -85,6 +103,7 @@ QDataStream &operator>>(QDataStream &in, FileContainer &container)
in >> container.filePath_; in >> container.filePath_;
in >> container.projectPartId_; in >> container.projectPartId_;
in >> container.unsavedFileContent_; in >> container.unsavedFileContent_;
in >> container.documentRevision_;
in >> container.hasUnsavedFileContent_; in >> container.hasUnsavedFileContent_;
return in; return in;
@@ -106,9 +125,9 @@ bool operator<(const FileContainer &first, const FileContainer &second)
QDebug operator<<(QDebug debug, const FileContainer &container) QDebug operator<<(QDebug debug, const FileContainer &container)
{ {
debug.nospace() << "FileContainer(" debug.nospace() << "FileContainer("
<< container.filePath() << container.filePath() << ", "
<< ", " << container.projectPartId() << ", "
<< container.projectPartId(); << container.documentRevision();
if (container.hasUnsavedFileContent()) { if (container.hasUnsavedFileContent()) {
const Utf8String fileWithContent = debugWriteFileForInspection( const Utf8String fileWithContent = debugWriteFileForInspection(
@@ -126,9 +145,9 @@ QDebug operator<<(QDebug debug, const FileContainer &container)
void PrintTo(const FileContainer &container, ::std::ostream* os) void PrintTo(const FileContainer &container, ::std::ostream* os)
{ {
*os << "FileContainer(" *os << "FileContainer("
<< container.filePath().constData() << container.filePath().constData() << ", "
<< ", " << container.projectPartId().constData() << ", "
<< container.projectPartId().constData(); << container.documentRevision();
if (container.hasUnsavedFileContent()) if (container.hasUnsavedFileContent())
*os << ", " *os << ", "

View File

@@ -50,17 +50,23 @@ public:
FileContainer(const Utf8String &filePath, FileContainer(const Utf8String &filePath,
const Utf8String &projectPartId, const Utf8String &projectPartId,
const Utf8String &unsavedFileContent = Utf8String(), const Utf8String &unsavedFileContent = Utf8String(),
bool hasUnsavedFileContent = false); bool hasUnsavedFileContent = false,
quint32 documentRevision = 0);
FileContainer(const Utf8String &filePath,
const Utf8String &projectPartId,
quint32 documentRevision);
const Utf8String &filePath() const; const Utf8String &filePath() const;
const Utf8String &projectPartId() const; const Utf8String &projectPartId() const;
const Utf8String &unsavedFileContent() const; const Utf8String &unsavedFileContent() const;
bool hasUnsavedFileContent() const; bool hasUnsavedFileContent() const;
quint32 documentRevision() const;
private: private:
Utf8String filePath_; Utf8String filePath_;
Utf8String projectPartId_; Utf8String projectPartId_;
Utf8String unsavedFileContent_; Utf8String unsavedFileContent_;
quint32 documentRevision_;
bool hasUnsavedFileContent_ = false; bool hasUnsavedFileContent_ = false;
}; };

View File

@@ -35,10 +35,8 @@
namespace ClangBackEnd { namespace ClangBackEnd {
RequestDiagnosticsMessage::RequestDiagnosticsMessage(const FileContainer &file, RequestDiagnosticsMessage::RequestDiagnosticsMessage(const FileContainer &file)
quint32 documentRevision) : file_(file)
: file_(file),
documentRevision_(documentRevision)
{ {
} }
@@ -47,15 +45,9 @@ const FileContainer RequestDiagnosticsMessage::file() const
return file_; return file_;
} }
quint32 RequestDiagnosticsMessage::documentRevision() const
{
return documentRevision_;
}
QDataStream &operator<<(QDataStream &out, const RequestDiagnosticsMessage &message) QDataStream &operator<<(QDataStream &out, const RequestDiagnosticsMessage &message)
{ {
out << message.file_; out << message.file_;
out << message.documentRevision_;
return out; return out;
} }
@@ -63,14 +55,13 @@ QDataStream &operator<<(QDataStream &out, const RequestDiagnosticsMessage &messa
QDataStream &operator>>(QDataStream &in, RequestDiagnosticsMessage &message) QDataStream &operator>>(QDataStream &in, RequestDiagnosticsMessage &message)
{ {
in >> message.file_; in >> message.file_;
in >> message.documentRevision_;
return in; return in;
} }
bool operator==(const RequestDiagnosticsMessage &first, const RequestDiagnosticsMessage &second) bool operator==(const RequestDiagnosticsMessage &first, const RequestDiagnosticsMessage &second)
{ {
return first.file_ == second.file_ && first.documentRevision_ == second.documentRevision_; return first.file_ == second.file_;
} }
bool operator<(const RequestDiagnosticsMessage &first, const RequestDiagnosticsMessage &second) bool operator<(const RequestDiagnosticsMessage &first, const RequestDiagnosticsMessage &second)
@@ -81,8 +72,7 @@ bool operator<(const RequestDiagnosticsMessage &first, const RequestDiagnosticsM
QDebug operator<<(QDebug debug, const RequestDiagnosticsMessage &message) QDebug operator<<(QDebug debug, const RequestDiagnosticsMessage &message)
{ {
debug.nospace() << "RequestDiagnosticsMessage(" debug.nospace() << "RequestDiagnosticsMessage("
<< message.file() << ", " << message.file()
<< message.documentRevision()
<< ")"; << ")";
return debug; return debug;

View File

@@ -46,10 +46,9 @@ class CMBIPC_EXPORT RequestDiagnosticsMessage
public: public:
RequestDiagnosticsMessage() = default; RequestDiagnosticsMessage() = default;
RequestDiagnosticsMessage(const FileContainer &file, quint32 documentRevision); RequestDiagnosticsMessage(const FileContainer &file);
const FileContainer file() const; const FileContainer file() const;
quint32 documentRevision() const;
private: private:
FileContainer file_; FileContainer file_;

View File

@@ -263,3 +263,8 @@ void PrintTo(const Utf8String &text, ::std::ostream* os)
{ {
*os << "\"" << text.toByteArray().data() << "\""; *os << "\"" << text.toByteArray().data() << "\"";
} }
uint qHash(const Utf8String &utf8String)
{
return qHash(utf8String.byteArray);
}

View File

@@ -54,6 +54,8 @@ class SQLITE_EXPORT Utf8String
friend SQLITE_EXPORT QDataStream &operator<<(QDataStream &datastream, const Utf8String &text); friend SQLITE_EXPORT QDataStream &operator<<(QDataStream &datastream, const Utf8String &text);
friend SQLITE_EXPORT QDataStream &operator>>(QDataStream &datastream, Utf8String &text); friend SQLITE_EXPORT QDataStream &operator>>(QDataStream &datastream, Utf8String &text);
friend SQLITE_EXPORT uint qHash(const Utf8String &utf8String);
public: public:
Utf8String() = default; Utf8String() = default;
explicit Utf8String(const char *utf8Text, int size); explicit Utf8String(const char *utf8Text, int size);
@@ -118,6 +120,8 @@ SQLITE_EXPORT QDataStream &operator>>(QDataStream &datastream, Utf8String &text)
SQLITE_EXPORT QDebug operator<<(QDebug debug, const Utf8String &text); SQLITE_EXPORT QDebug operator<<(QDebug debug, const Utf8String &text);
SQLITE_EXPORT void PrintTo(const Utf8String &text, ::std::ostream* os); SQLITE_EXPORT void PrintTo(const Utf8String &text, ::std::ostream* os);
SQLITE_EXPORT uint qHash(const Utf8String &utf8String);
#define Utf8StringLiteral(str) Utf8String::fromByteArray(QByteArrayLiteral(str)) #define Utf8StringLiteral(str) Utf8String::fromByteArray(QByteArrayLiteral(str))
Q_DECLARE_METATYPE(Utf8String) Q_DECLARE_METATYPE(Utf8String)

View File

@@ -167,7 +167,7 @@ void IpcReceiver::diagnosticsChanged(const DiagnosticsChangedMessage &message)
const QString diagnosticsProjectPartId = message.file().projectPartId(); const QString diagnosticsProjectPartId = message.file().projectPartId();
const QString documentProjectPartId = processor->projectPart()->id(); const QString documentProjectPartId = processor->projectPart()->id();
if (diagnosticsProjectPartId == documentProjectPartId) if (diagnosticsProjectPartId == documentProjectPartId)
processor->updateCodeWarnings(message.diagnostics(), message.documentRevision()); processor->updateCodeWarnings(message.diagnostics(), message.file().documentRevision());
} }
} }
@@ -317,7 +317,7 @@ void IpcCommunicator::registerCurrrentCodeModelUiHeaders()
const auto editorSupports = CppModelManager::instance()->abstractEditorSupports(); const auto editorSupports = CppModelManager::instance()->abstractEditorSupports();
foreach (const AbstractEditorSupport *es, editorSupports) foreach (const AbstractEditorSupport *es, editorSupports)
updateUnsavedFile(es->fileName(), es->contents()); updateUnsavedFile(es->fileName(), es->contents(), es->revision());
} }
static QStringList projectPartMessageLine(const CppTools::ProjectPart::Ptr &projectPart) static QStringList projectPartMessageLine(const CppTools::ProjectPart::Ptr &projectPart)
@@ -355,12 +355,14 @@ void IpcCommunicator::registerProjectsParts(const QList<CppTools::ProjectPart::P
void IpcCommunicator::updateUnsavedFileFromCppEditorDocument(const QString &filePath) void IpcCommunicator::updateUnsavedFileFromCppEditorDocument(const QString &filePath)
{ {
const QByteArray unsavedContent = CppTools::CppModelManager::instance() const auto document = CppTools::CppModelManager::instance()->cppEditorDocument(filePath);
->cppEditorDocument(filePath)->contents();
updateUnsavedFile(filePath, unsavedContent); updateUnsavedFile(filePath, document->contents(), document->revision());
} }
void IpcCommunicator::updateUnsavedFile(const QString &filePath, const QByteArray &contents) void IpcCommunicator::updateUnsavedFile(const QString &filePath,
const QByteArray &contents,
uint documentRevision)
{ {
const QString projectPartId = Utils::projectPartIdForFile(filePath); const QString projectPartId = Utils::projectPartIdForFile(filePath);
const bool hasUnsavedContent = true; const bool hasUnsavedContent = true;
@@ -369,13 +371,14 @@ void IpcCommunicator::updateUnsavedFile(const QString &filePath, const QByteArra
registerFilesForCodeCompletion({{filePath, registerFilesForCodeCompletion({{filePath,
projectPartId, projectPartId,
Utf8String::fromByteArray(contents), Utf8String::fromByteArray(contents),
hasUnsavedContent}}); hasUnsavedContent,
documentRevision}});
} }
void IpcCommunicator::requestDiagnostics(const FileContainer &fileContainer, uint documentRevision) void IpcCommunicator::requestDiagnostics(const FileContainer &fileContainer)
{ {
registerFilesForCodeCompletion({fileContainer}); registerFilesForCodeCompletion({fileContainer});
m_ipcSender->requestDiagnostics({fileContainer, documentRevision}); m_ipcSender->requestDiagnostics({fileContainer});
} }
void IpcCommunicator::updateUnsavedFileIfNotCurrentDocument(Core::IDocument *document) void IpcCommunicator::updateUnsavedFileIfNotCurrentDocument(Core::IDocument *document)

View File

@@ -128,8 +128,8 @@ public:
void updateUnsavedFileIfNotCurrentDocument(Core::IDocument *document); void updateUnsavedFileIfNotCurrentDocument(Core::IDocument *document);
void updateUnsavedFileFromCppEditorDocument(const QString &filePath); void updateUnsavedFileFromCppEditorDocument(const QString &filePath);
void updateUnsavedFile(const QString &filePath, const QByteArray &contents); void updateUnsavedFile(const QString &filePath, const QByteArray &contents, uint documentRevision);
void requestDiagnostics(const ClangBackEnd::FileContainer &fileContainer, uint documentRevision); void requestDiagnostics(const ClangBackEnd::FileContainer &fileContainer);
public: // for tests public: // for tests
IpcSenderInterface *setIpcSender(IpcSenderInterface *ipcSender); IpcSenderInterface *setIpcSender(IpcSenderInterface *ipcSender);

View File

@@ -225,14 +225,20 @@ void ClangEditorDocumentProcessor::updateTranslationUnitForCompletion(CppTools::
if (m_projectPart) { if (m_projectPart) {
if (projectPart.id() != m_projectPart->id()) { if (projectPart.id() != m_projectPart->id()) {
auto container1 = ClangBackEnd::FileContainer(filePath(), m_projectPart->id()); auto container1 = ClangBackEnd::FileContainer(filePath(),
m_projectPart->id(),
revision());
ipcCommunicator.unregisterFilesForCodeCompletion({container1}); ipcCommunicator.unregisterFilesForCodeCompletion({container1});
auto container2 = ClangBackEnd::FileContainer(filePath(), projectPart.id()); auto container2 = ClangBackEnd::FileContainer(filePath(),
projectPart.id(),
revision());
ipcCommunicator.registerFilesForCodeCompletion({container2}); ipcCommunicator.registerFilesForCodeCompletion({container2});
} }
} else { } else {
auto container = ClangBackEnd::FileContainer(filePath(), projectPart.id()); auto container = ClangBackEnd::FileContainer(filePath(),
projectPart.id(),
revision());
ipcCommunicator.registerFilesForCodeCompletion({container}); ipcCommunicator.registerFilesForCodeCompletion({container});
} }
} }
@@ -458,8 +464,11 @@ void ClangEditorDocumentProcessor::requestDiagnostics(CppTools::ProjectPart &pro
if (!m_projectPart || projectPart.id() != m_projectPart->id()) { if (!m_projectPart || projectPart.id() != m_projectPart->id()) {
IpcCommunicator &ipcCommunicator = m_modelManagerSupport->ipcCommunicator(); IpcCommunicator &ipcCommunicator = m_modelManagerSupport->ipcCommunicator();
ipcCommunicator.requestDiagnostics({filePath(), projectPart.id()}, ipcCommunicator.requestDiagnostics({filePath(),
revision()); projectPart.id(),
Utf8String(),
false,
revision()});
} }
} }
@@ -469,10 +478,10 @@ void ClangEditorDocumentProcessor::requestDiagnostics()
if (m_projectPart) { if (m_projectPart) {
auto &ipcCommunicator = m_modelManagerSupport->ipcCommunicator(); auto &ipcCommunicator = m_modelManagerSupport->ipcCommunicator();
ipcCommunicator.requestDiagnostics({filePath(), ipcCommunicator.requestDiagnostics({filePath(),
m_projectPart->id(), m_projectPart->id(),
baseTextDocument()->plainText(), baseTextDocument()->plainText(),
true}, true,
revision()); revision()});
} }
} }

View File

@@ -152,7 +152,7 @@ void ModelManagerSupportClang::onAbstractEditorSupportContentsUpdated(const QStr
const QByteArray &content) const QByteArray &content)
{ {
QTC_ASSERT(!filePath.isEmpty(), return); QTC_ASSERT(!filePath.isEmpty(), return);
m_ipcCommunicator.updateUnsavedFile(filePath, content); m_ipcCommunicator.updateUnsavedFile(filePath, content, 0);
} }
void ModelManagerSupportClang::onAbstractEditorSupportRemoved(const QString &filePath) void ModelManagerSupportClang::onAbstractEditorSupportRemoved(const QString &filePath)

View File

@@ -22,7 +22,8 @@ HEADERS += $$PWD/clangipcserver.h \
$$PWD/sourcelocation.h \ $$PWD/sourcelocation.h \
$$PWD/sourcerange.h \ $$PWD/sourcerange.h \
$$PWD/fixit.h \ $$PWD/fixit.h \
$$PWD/diagnosticsetiterator.h $$PWD/diagnosticsetiterator.h \
$$PWD/clangfilesystemwatcher.h
SOURCES += $$PWD/clangipcserver.cpp \ SOURCES += $$PWD/clangipcserver.cpp \
$$PWD/codecompleter.cpp \ $$PWD/codecompleter.cpp \
@@ -45,4 +46,5 @@ SOURCES += $$PWD/clangipcserver.cpp \
$$PWD/diagnostic.cpp \ $$PWD/diagnostic.cpp \
$$PWD/sourcelocation.cpp \ $$PWD/sourcelocation.cpp \
$$PWD/sourcerange.cpp \ $$PWD/sourcerange.cpp \
$$PWD/fixit.cpp $$PWD/fixit.cpp \
$$PWD/clangfilesystemwatcher.cpp

View File

@@ -0,0 +1,89 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** 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 The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "clangfilesystemwatcher.h"
#include "translationunits.h"
#include <utf8stringvector.h>
#include <QStringList>
#include <algorithm>
#include <iterator>
namespace ClangBackEnd {
namespace {
QStringList toStringList(const QSet<Utf8String> &files)
{
QStringList resultList;
std::copy(files.cbegin(), files.cend(), std::back_inserter(resultList));
return resultList;
}
}
ClangFileSystemWatcher::ClangFileSystemWatcher(TranslationUnits &translationUnits)
: translationUnits(translationUnits)
{
connect(&watcher,
&QFileSystemWatcher::fileChanged,
this,
&ClangFileSystemWatcher::updateTranslationUnitsWithChangedDependencies);
connect(&changedDiagnosticsTimer,
&QTimer::timeout,
this,
&ClangFileSystemWatcher::sendChangedDiagnostics);
changedDiagnosticsTimer.setSingleShot(true);
changedDiagnosticsTimer.setInterval(100);
}
void ClangFileSystemWatcher::addFiles(const QSet<Utf8String> &filePaths)
{
watcher.addPaths(toStringList(filePaths));
}
void ClangFileSystemWatcher::updateTranslationUnitsWithChangedDependencies(const QString &filePath)
{
translationUnits.updateTranslationUnitsWithChangedDependencies(filePath);
changedDiagnosticsTimer.start();
watcher.addPath(filePath);
}
void ClangFileSystemWatcher::sendChangedDiagnostics()
{
translationUnits.sendChangedDiagnostics();
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,65 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** 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 The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CLANGFILESYSTEMWATCHER_H
#define CLANGFILESYSTEMWATCHER_H
#include <QFileSystemWatcher>
#include <QSet>
#include <QTimer>
class Utf8String;
namespace ClangBackEnd {
class TranslationUnits;
class ClangFileSystemWatcher : public QObject
{
Q_OBJECT
public:
ClangFileSystemWatcher(TranslationUnits &translationUnits);
void addFiles(const QSet<Utf8String> &filePaths);
private:
void updateTranslationUnitsWithChangedDependencies(const QString &filePath);
void sendChangedDiagnostics();
private:
QFileSystemWatcher watcher;
QTimer changedDiagnosticsTimer;
TranslationUnits &translationUnits;
};
} // namespace ClangBackEnd
#endif // CLANGFILESYSTEMWATCHER_H

View File

@@ -59,6 +59,10 @@ namespace ClangBackEnd {
ClangIpcServer::ClangIpcServer() ClangIpcServer::ClangIpcServer()
: translationUnits(projects, unsavedFiles) : translationUnits(projects, unsavedFiles)
{ {
translationUnits.setSendChangeDiagnosticsCallback([this] (const DiagnosticsChangedMessage &message)
{
client()->diagnosticsChanged(message);
});
} }
void ClangIpcServer::end() void ClangIpcServer::end()
@@ -71,8 +75,11 @@ void ClangIpcServer::registerTranslationUnitsForCodeCompletion(const ClangBackEn
TIME_SCOPE_DURATION("ClangIpcServer::registerTranslationUnitsForCodeCompletion"); TIME_SCOPE_DURATION("ClangIpcServer::registerTranslationUnitsForCodeCompletion");
try { try {
translationUnits.createOrUpdate(message.fileContainers()); const auto newerFileContainers = translationUnits.newerFileContainers(message.fileContainers());
unsavedFiles.createOrUpdate(message.fileContainers()); if (newerFileContainers.size() > 0) {
unsavedFiles.createOrUpdate(newerFileContainers);
translationUnits.createOrUpdate(newerFileContainers);
}
} catch (const ProjectPartDoNotExistException &exception) { } catch (const ProjectPartDoNotExistException &exception) {
client()->projectPartsDoNotExist(ProjectPartsDoNotExistMessage(exception.projectPartIds())); client()->projectPartsDoNotExist(ProjectPartsDoNotExistMessage(exception.projectPartIds()));
} catch (const std::exception &exception) { } catch (const std::exception &exception) {
@@ -85,6 +92,7 @@ void ClangIpcServer::unregisterTranslationUnitsForCodeCompletion(const ClangBack
TIME_SCOPE_DURATION("ClangIpcServer::unregisterTranslationUnitsForCodeCompletion"); TIME_SCOPE_DURATION("ClangIpcServer::unregisterTranslationUnitsForCodeCompletion");
try { try {
unsavedFiles.remove(message.fileContainers());
translationUnits.remove(message.fileContainers()); translationUnits.remove(message.fileContainers());
} catch (const TranslationUnitDoesNotExistException &exception) { } catch (const TranslationUnitDoesNotExistException &exception) {
client()->translationUnitDoesNotExist(TranslationUnitDoesNotExistMessage(exception.fileContainer())); client()->translationUnitDoesNotExist(TranslationUnitDoesNotExistMessage(exception.fileContainer()));
@@ -147,8 +155,7 @@ void ClangIpcServer::requestDiagnostics(const RequestDiagnosticsMessage &message
message.file().projectPartId()); message.file().projectPartId());
client()->diagnosticsChanged(DiagnosticsChangedMessage(translationUnit.fileContainer(), client()->diagnosticsChanged(DiagnosticsChangedMessage(translationUnit.fileContainer(),
translationUnit.diagnostics().toDiagnosticContainers(), translationUnit.diagnostics().toDiagnosticContainers()));
message.documentRevision()));
} catch (const TranslationUnitDoesNotExistException &exception) { } catch (const TranslationUnitDoesNotExistException &exception) {
client()->translationUnitDoesNotExist(TranslationUnitDoesNotExistMessage(exception.fileContainer())); client()->translationUnitDoesNotExist(TranslationUnitDoesNotExistMessage(exception.fileContainer()));
} catch (const ProjectPartDoNotExistException &exception) { } catch (const ProjectPartDoNotExistException &exception) {

View File

@@ -49,8 +49,6 @@ CodeCompleter::CodeCompleter(TranslationUnit translationUnit)
CodeCompletions CodeCompleter::complete(uint line, uint column) CodeCompletions CodeCompleter::complete(uint line, uint column)
{ {
translationUnit.reparse();
ClangCodeCompleteResults completeResults(clang_codeCompleteAt(translationUnit.cxTranslationUnit(), ClangCodeCompleteResults completeResults(clang_codeCompleteAt(translationUnit.cxTranslationUnit(),
translationUnit.filePath().constData(), translationUnit.filePath().constData(),
line, line,

View File

@@ -30,19 +30,24 @@
#include "translationunit.h" #include "translationunit.h"
#include "clangstring.h"
#include "codecompleter.h" #include "codecompleter.h"
#include "diagnosticset.h" #include "diagnosticset.h"
#include "projectpart.h" #include "projectpart.h"
#include "translationunitfilenotexitexception.h" #include "translationunitfilenotexitexception.h"
#include "translationunitisnullexception.h" #include "translationunitisnullexception.h"
#include "translationunitparseerrorexception.h" #include "translationunitparseerrorexception.h"
#include "translationunits.h"
#include "unsavedfiles.h" #include "unsavedfiles.h"
#include <utf8string.h> #include <utf8string.h>
#include <QDebug>
#include <QFileInfo> #include <QFileInfo>
#include <QLoggingCategory> #include <QLoggingCategory>
#include <ostream>
static Q_LOGGING_CATEGORY(verboseLibLog, "qtc.clangbackend.verboselib"); static Q_LOGGING_CATEGORY(verboseLibLog, "qtc.clangbackend.verboselib");
namespace ClangBackEnd { namespace ClangBackEnd {
@@ -51,27 +56,31 @@ class TranslationUnitData
{ {
public: public:
TranslationUnitData(const Utf8String &filePath, TranslationUnitData(const Utf8String &filePath,
const UnsavedFiles &unsavedFiles, const ProjectPart &projectPart,
const ProjectPart &projectPart); TranslationUnits &translationUnits);
~TranslationUnitData(); ~TranslationUnitData();
public: public:
time_point lastChangeTimePoint; TranslationUnits &translationUnits;
time_point lastProjectPartChangeTimePoint;
QSet<Utf8String> dependedFilePaths;
ProjectPart projectPart; ProjectPart projectPart;
Utf8String filePath; Utf8String filePath;
CXTranslationUnit translationUnit = nullptr; CXTranslationUnit translationUnit = nullptr;
CXIndex index = nullptr; CXIndex index = nullptr;
UnsavedFiles unsavedFiles; uint documentRevision = 0;
bool needsToBeReparsed = false;
}; };
TranslationUnitData::TranslationUnitData(const Utf8String &filePath, TranslationUnitData::TranslationUnitData(const Utf8String &filePath,
const UnsavedFiles &unsavedFiles, const ProjectPart &projectPart,
const ProjectPart &projectPart) TranslationUnits &translationUnits)
: lastChangeTimePoint(std::chrono::steady_clock::now()), : translationUnits(translationUnits),
lastProjectPartChangeTimePoint(std::chrono::steady_clock::now()),
projectPart(projectPart), projectPart(projectPart),
filePath(filePath), filePath(filePath)
unsavedFiles(unsavedFiles)
{ {
dependedFilePaths.insert(filePath);
} }
TranslationUnitData::~TranslationUnitData() TranslationUnitData::~TranslationUnitData()
@@ -81,10 +90,10 @@ TranslationUnitData::~TranslationUnitData()
} }
TranslationUnit::TranslationUnit(const Utf8String &filePath, TranslationUnit::TranslationUnit(const Utf8String &filePath,
const UnsavedFiles &unsavedFiles, const ProjectPart &projectPart,
const ProjectPart &project, TranslationUnits &translationUnits,
FileExistsCheck fileExistsCheck) FileExistsCheck fileExistsCheck)
: d(std::make_shared<TranslationUnitData>(filePath, unsavedFiles, project)) : d(std::make_shared<TranslationUnitData>(filePath, projectPart, translationUnits))
{ {
if (fileExistsCheck == CheckIfFileExists) if (fileExistsCheck == CheckIfFileExists)
checkIfFileExists(); checkIfFileExists();
@@ -122,10 +131,9 @@ CXIndex TranslationUnit::index() const
CXTranslationUnit TranslationUnit::cxTranslationUnit() const CXTranslationUnit TranslationUnit::cxTranslationUnit() const
{ {
checkIfNull(); checkIfNull();
removeTranslationUnitIfProjectPartWasChanged();
removeOutdatedTranslationUnit();
createTranslationUnitIfNeeded(); createTranslationUnitIfNeeded();
reparseTranslationUnitIfFilesAreChanged();
return d->translationUnit; return d->translationUnit;
} }
@@ -148,21 +156,60 @@ FileContainer TranslationUnit::fileContainer() const
{ {
checkIfNull(); checkIfNull();
return FileContainer(d->filePath, d->projectPart.projectPartId()); return FileContainer(d->filePath,
d->projectPart.projectPartId(),
Utf8String(),
false,
d->documentRevision);
} }
const time_point &TranslationUnit::lastChangeTimePoint() const const ProjectPart &TranslationUnit::projectPart() const
{ {
return d->lastChangeTimePoint; checkIfNull();
return d->projectPart;
}
void TranslationUnit::setDocumentRevision(uint revision)
{
d->documentRevision = revision;
}
uint TranslationUnit::documentRevision() const
{
return d->documentRevision;
}
const time_point &TranslationUnit::lastProjectPartChangeTimePoint() const
{
return d->lastProjectPartChangeTimePoint;
}
bool TranslationUnit::isNeedingReparse() const
{
return d->needsToBeReparsed;
} }
DiagnosticSet TranslationUnit::diagnostics() const DiagnosticSet TranslationUnit::diagnostics() const
{ {
reparse(); reparseTranslationUnitIfFilesAreChanged();
return DiagnosticSet(clang_getDiagnosticSetFromTU(cxTranslationUnit())); return DiagnosticSet(clang_getDiagnosticSetFromTU(cxTranslationUnit()));
} }
const QSet<Utf8String> &TranslationUnit::dependedFilePaths() const
{
createTranslationUnitIfNeeded();
return d->dependedFilePaths;
}
void TranslationUnit::updateIsNeedingReparseIfDependencyIsMet(const Utf8String &filePath)
{
if (d->dependedFilePaths.contains(filePath))
d->needsToBeReparsed = true;
}
void TranslationUnit::checkIfNull() const void TranslationUnit::checkIfNull() const
{ {
if (isNull()) if (isNull())
@@ -175,19 +222,24 @@ void TranslationUnit::checkIfFileExists() const
throw TranslationUnitFileNotExitsException(d->filePath); throw TranslationUnitFileNotExitsException(d->filePath);
} }
void TranslationUnit::updateLastChangeTimePoint() const void TranslationUnit::updateLastProjectPartChangeTimePoint() const
{ {
d->lastChangeTimePoint = std::chrono::steady_clock::now(); d->lastProjectPartChangeTimePoint = std::chrono::steady_clock::now();
} }
void TranslationUnit::removeOutdatedTranslationUnit() const void TranslationUnit::removeTranslationUnitIfProjectPartWasChanged() const
{ {
if (d->projectPart.lastChangeTimePoint() >= d->lastChangeTimePoint) { if (projectPartIsOutdated()) {
clang_disposeTranslationUnit(d->translationUnit); clang_disposeTranslationUnit(d->translationUnit);
d->translationUnit = nullptr; d->translationUnit = nullptr;
} }
} }
bool TranslationUnit::projectPartIsOutdated() const
{
return d->projectPart.lastChangeTimePoint() >= d->lastProjectPartChangeTimePoint;
}
void TranslationUnit::createTranslationUnitIfNeeded() const void TranslationUnit::createTranslationUnitIfNeeded() const
{ {
if (!d->translationUnit) { if (!d->translationUnit) {
@@ -196,18 +248,20 @@ void TranslationUnit::createTranslationUnitIfNeeded() const
d->filePath.constData(), d->filePath.constData(),
d->projectPart.cxArguments(), d->projectPart.cxArguments(),
d->projectPart.argumentCount(), d->projectPart.argumentCount(),
d->unsavedFiles.cxUnsavedFiles(), unsavedFiles().cxUnsavedFiles(),
d->unsavedFiles.count(), unsavedFiles().count(),
defaultOptions(), defaultOptions(),
&d->translationUnit); &d->translationUnit);
checkTranslationUnitErrorCode(errorCode); checkTranslationUnitErrorCode(errorCode);
updateIncludeFilePaths();
// We need to reparse to create the precompiled preamble, which will speed up further calls, // We need to reparse to create the precompiled preamble, which will speed up further calls,
// e.g. clang_codeCompleteAt() dramatically. // e.g. clang_codeCompleteAt() dramatically.
reparseTranslationUnit(); reparseTranslationUnit();
updateLastChangeTimePoint(); updateLastProjectPartChangeTimePoint();
} }
} }
@@ -222,9 +276,45 @@ void TranslationUnit::checkTranslationUnitErrorCode(CXErrorCode errorCode) const
void TranslationUnit::reparseTranslationUnit() const void TranslationUnit::reparseTranslationUnit() const
{ {
clang_reparseTranslationUnit(d->translationUnit, clang_reparseTranslationUnit(d->translationUnit,
d->unsavedFiles.count(), unsavedFiles().count(),
d->unsavedFiles.cxUnsavedFiles(), unsavedFiles().cxUnsavedFiles(),
clang_defaultReparseOptions(d->translationUnit)); clang_defaultReparseOptions(d->translationUnit));
d->needsToBeReparsed = false;
}
void TranslationUnit::reparseTranslationUnitIfFilesAreChanged() const
{
if (isNeedingReparse())
reparseTranslationUnit();
}
void TranslationUnit::includeCallback(CXFile included_file,
CXSourceLocation */*inclusion_stack*/,
unsigned /*include_len*/,
CXClientData clientData)
{
ClangString includeFilePath(clang_getFileName(included_file));
TranslationUnit *translationUnit = static_cast<TranslationUnit*>(clientData);
translationUnit->d->dependedFilePaths.insert(includeFilePath);
}
UnsavedFiles &TranslationUnit::unsavedFiles() const
{
return d->translationUnits.unsavedFiles();
}
void TranslationUnit::updateIncludeFilePaths() const
{
d->dependedFilePaths.clear();
d->dependedFilePaths.insert(filePath());
clang_getInclusions(d->translationUnit, includeCallback, const_cast<TranslationUnit*>(this));
d->translationUnits.addWatchedFiles(d->dependedFilePaths);
} }
int TranslationUnit::defaultOptions() int TranslationUnit::defaultOptions()
@@ -236,12 +326,12 @@ int TranslationUnit::defaultOptions()
uint TranslationUnit::unsavedFilesCount() const uint TranslationUnit::unsavedFilesCount() const
{ {
return d->unsavedFiles.count(); return unsavedFiles().count();
} }
CXUnsavedFile *TranslationUnit::cxUnsavedFiles() const CXUnsavedFile *TranslationUnit::cxUnsavedFiles() const
{ {
return d->unsavedFiles.cxUnsavedFiles(); return unsavedFiles().cxUnsavedFiles();
} }
TranslationUnit::~TranslationUnit() = default; TranslationUnit::~TranslationUnit() = default;
@@ -266,5 +356,13 @@ bool operator==(const TranslationUnit &first, const TranslationUnit &second)
return first.filePath() == second.filePath() && first.projectPartId() == second.projectPartId(); return first.filePath() == second.filePath() && first.projectPartId() == second.projectPartId();
} }
void PrintTo(const TranslationUnit &translationUnit, ::std::ostream *os)
{
*os << "TranslationUnit("
<< translationUnit.filePath().constData() << ", "
<< translationUnit.projectPartId().constData() << ", "
<< translationUnit.documentRevision() << ")";
}
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -31,12 +31,15 @@
#ifndef CLANGBACKEND_TRANSLATIONUNIT_H #ifndef CLANGBACKEND_TRANSLATIONUNIT_H
#define CLANGBACKEND_TRANSLATIONUNIT_H #define CLANGBACKEND_TRANSLATIONUNIT_H
#include <utf8stringvector.h>
#include <clang-c/Index.h> #include <clang-c/Index.h>
#include <QtGlobal> #include <QtGlobal>
#include <chrono> #include <chrono>
#include <memory> #include <memory>
#include <QSet>
class Utf8String; class Utf8String;
@@ -48,6 +51,7 @@ class UnsavedFiles;
class ProjectPart; class ProjectPart;
class DiagnosticSet; class DiagnosticSet;
class FileContainer; class FileContainer;
class TranslationUnits;
using time_point = std::chrono::steady_clock::time_point; using time_point = std::chrono::steady_clock::time_point;
@@ -61,8 +65,8 @@ public:
TranslationUnit() = default; TranslationUnit() = default;
TranslationUnit(const Utf8String &filePath, TranslationUnit(const Utf8String &filePath,
const UnsavedFiles &unsavedFiles,
const ProjectPart &projectPart, const ProjectPart &projectPart,
TranslationUnits &translationUnits,
FileExistsCheck fileExistsCheck = CheckIfFileExists); FileExistsCheck fileExistsCheck = CheckIfFileExists);
~TranslationUnit(); ~TranslationUnit();
@@ -85,27 +89,45 @@ public:
const Utf8String &filePath() const; const Utf8String &filePath() const;
const Utf8String &projectPartId() const; const Utf8String &projectPartId() const;
FileContainer fileContainer() const; FileContainer fileContainer() const;
const ProjectPart &projectPart() const;
const time_point &lastChangeTimePoint() const; void setDocumentRevision(uint revision);
uint documentRevision() const;
const time_point &lastProjectPartChangeTimePoint() const;
bool isNeedingReparse() const;
DiagnosticSet diagnostics() const; DiagnosticSet diagnostics() const;
const QSet<Utf8String> &dependedFilePaths() const;
void updateIsNeedingReparseIfDependencyIsMet(const Utf8String &filePath);
private: private:
void checkIfNull() const; void checkIfNull() const;
void checkIfFileExists() const; void checkIfFileExists() const;
void updateLastChangeTimePoint() const; void updateLastProjectPartChangeTimePoint() const;
void removeOutdatedTranslationUnit() const; void removeTranslationUnitIfProjectPartWasChanged() const;
bool projectPartIsOutdated() const;
void createTranslationUnitIfNeeded() const; void createTranslationUnitIfNeeded() const;
void checkTranslationUnitErrorCode(CXErrorCode errorCode) const; void checkTranslationUnitErrorCode(CXErrorCode errorCode) const;
void reparseTranslationUnit() const; void reparseTranslationUnit() const;
void reparseTranslationUnitIfFilesAreChanged() const;
void updateIncludeFilePaths() const;
static int defaultOptions(); static int defaultOptions();
static void includeCallback(CXFile included_file,
CXSourceLocation */*inclusion_stack*/,
unsigned /*include_len*/,
CXClientData clientData);
UnsavedFiles &unsavedFiles() const;
private: private:
mutable std::shared_ptr<TranslationUnitData> d; mutable std::shared_ptr<TranslationUnitData> d;
}; };
bool operator==(const TranslationUnit &first, const TranslationUnit &second); bool operator==(const TranslationUnit &first, const TranslationUnit &second);
void PrintTo(const TranslationUnit &translationUnit, ::std::ostream *os);
} // namespace ClangBackEnd } // namespace ClangBackEnd
#endif // CLANGBACKEND_TRANSLATIONUNIT_H #endif // CLANGBACKEND_TRANSLATIONUNIT_H

View File

@@ -30,10 +30,14 @@
#include "translationunits.h" #include "translationunits.h"
#include <diagnosticschangedmessage.h>
#include <diagnosticset.h>
#include <projectpartsdonotexistexception.h> #include <projectpartsdonotexistexception.h>
#include <projects.h> #include <projects.h>
#include <translationunitdoesnotexistexception.h> #include <translationunitdoesnotexistexception.h>
#include <QDebug>
namespace ClangBackEnd { namespace ClangBackEnd {
bool operator==(const FileContainer &fileContainer, const TranslationUnit &translationUnit) bool operator==(const FileContainer &fileContainer, const TranslationUnit &translationUnit)
@@ -48,15 +52,20 @@ bool operator==(const TranslationUnit &translationUnit, const FileContainer &fil
TranslationUnits::TranslationUnits(ProjectParts &projects, UnsavedFiles &unsavedFiles) TranslationUnits::TranslationUnits(ProjectParts &projects, UnsavedFiles &unsavedFiles)
: projects(projects), : fileSystemWatcher(*this),
unsavedFiles(unsavedFiles) projectParts(projects),
unsavedFiles_(unsavedFiles)
{ {
} }
void TranslationUnits::createOrUpdate(const QVector<FileContainer> &fileContainers) void TranslationUnits::createOrUpdate(const QVector<FileContainer> &fileContainers)
{ {
for (const FileContainer &fileContainer : fileContainers) for (const FileContainer &fileContainer : fileContainers) {
createOrUpdateTranslationUnit(fileContainer); createOrUpdateTranslationUnit(fileContainer);
updateTranslationUnitsWithChangedDependencies(fileContainer.filePath());
}
sendChangedDiagnostics();
} }
static bool removeFromFileContainer(QVector<FileContainer> &fileContainers, const TranslationUnit &translationUnit) static bool removeFromFileContainer(QVector<FileContainer> &fileContainers, const TranslationUnit &translationUnit)
@@ -100,20 +109,78 @@ const TranslationUnit &TranslationUnits::translationUnit(const Utf8String &fileP
return *findIterator; return *findIterator;
} }
const TranslationUnit &TranslationUnits::translationUnit(const FileContainer &fileContainer) const
{
return translationUnit(fileContainer.filePath(), fileContainer.projectPartId());
}
const std::vector<TranslationUnit> &TranslationUnits::translationUnits() const const std::vector<TranslationUnit> &TranslationUnits::translationUnits() const
{ {
return translationUnits_; return translationUnits_;
} }
UnsavedFiles &TranslationUnits::unsavedFiles() const
{
return unsavedFiles_;
}
void TranslationUnits::addWatchedFiles(QSet<Utf8String> &filePaths)
{
fileSystemWatcher.addFiles(filePaths);
}
void TranslationUnits::updateTranslationUnitsWithChangedDependencies(const Utf8String &filePath)
{
for (auto &translationUnit : translationUnits_)
translationUnit.updateIsNeedingReparseIfDependencyIsMet(filePath);
}
void TranslationUnits::sendChangedDiagnostics()
{
for (const auto &translationUnit : translationUnits_) {
if (translationUnit.isNeedingReparse())
sendDiagnosticChangedMessage(translationUnit);
}
}
void TranslationUnits::setSendChangeDiagnosticsCallback(std::function<void(const DiagnosticsChangedMessage &)> &&callback)
{
sendDiagnosticsChangedCallback = std::move(callback);
}
QVector<FileContainer> TranslationUnits::newerFileContainers(const QVector<FileContainer> &fileContainers) const
{
QVector<FileContainer> newerContainers;
auto translationUnitIsNewer = [this] (const FileContainer &fileContainer) {
try {
return translationUnit(fileContainer).documentRevision() != fileContainer.documentRevision();
} catch (const TranslationUnitDoesNotExistException &) {
return true;
}
};
std::copy_if(fileContainers.cbegin(),
fileContainers.cend(),
std::back_inserter(newerContainers),
translationUnitIsNewer);
return newerContainers;
}
void TranslationUnits::createOrUpdateTranslationUnit(const FileContainer &fileContainer) void TranslationUnits::createOrUpdateTranslationUnit(const FileContainer &fileContainer)
{ {
TranslationUnit::FileExistsCheck checkIfFileExists = fileContainer.hasUnsavedFileContent() ? TranslationUnit::DoNotCheckIfFileExists : TranslationUnit::CheckIfFileExists; TranslationUnit::FileExistsCheck checkIfFileExists = fileContainer.hasUnsavedFileContent() ? TranslationUnit::DoNotCheckIfFileExists : TranslationUnit::CheckIfFileExists;
auto findIterator = findTranslationUnit(fileContainer); auto findIterator = findTranslationUnit(fileContainer);
if (findIterator == translationUnits_.end()) if (findIterator == translationUnits_.end()) {
translationUnits_.push_back(TranslationUnit(fileContainer.filePath(), translationUnits_.push_back(TranslationUnit(fileContainer.filePath(),
unsavedFiles, projectParts.project(fileContainer.projectPartId()),
projects.project(fileContainer.projectPartId()), *this,
checkIfFileExists)); checkIfFileExists));
translationUnits_.back().setDocumentRevision(fileContainer.documentRevision());
} else {
findIterator->setDocumentRevision(fileContainer.documentRevision());
}
} }
std::vector<TranslationUnit>::iterator TranslationUnits::findTranslationUnit(const FileContainer &fileContainer) std::vector<TranslationUnit>::iterator TranslationUnits::findTranslationUnit(const FileContainer &fileContainer)
@@ -129,7 +196,7 @@ std::vector<TranslationUnit>::const_iterator TranslationUnits::findTranslationUn
void TranslationUnits::checkIfProjectPartExists(const Utf8String &projectFileName) const void TranslationUnits::checkIfProjectPartExists(const Utf8String &projectFileName) const
{ {
projects.project(projectFileName); projectParts.project(projectFileName);
} }
void TranslationUnits::checkIfProjectPartsExists(const QVector<FileContainer> &fileContainers) const void TranslationUnits::checkIfProjectPartsExists(const QVector<FileContainer> &fileContainers) const
@@ -137,7 +204,7 @@ void TranslationUnits::checkIfProjectPartsExists(const QVector<FileContainer> &f
Utf8StringVector notExistingProjectParts; Utf8StringVector notExistingProjectParts;
for (const FileContainer &fileContainer : fileContainers) { for (const FileContainer &fileContainer : fileContainers) {
if (!projects.hasProjectPart(fileContainer.projectPartId())) if (!projectParts.hasProjectPart(fileContainer.projectPartId()))
notExistingProjectParts.push_back(fileContainer.projectPartId()); notExistingProjectParts.push_back(fileContainer.projectPartId());
} }
@@ -146,5 +213,15 @@ void TranslationUnits::checkIfProjectPartsExists(const QVector<FileContainer> &f
} }
void TranslationUnits::sendDiagnosticChangedMessage(const TranslationUnit &translationUnit)
{
if (sendDiagnosticsChangedCallback) {
DiagnosticsChangedMessage message(translationUnit.fileContainer(),
translationUnit.diagnostics().toDiagnosticContainers());
sendDiagnosticsChangedCallback(std::move(message));
}
}
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -31,6 +31,7 @@
#ifndef CLANGBACKEND_TRANSLATIONUNITS_H #ifndef CLANGBACKEND_TRANSLATIONUNITS_H
#define CLANGBACKEND_TRANSLATIONUNITS_H #define CLANGBACKEND_TRANSLATIONUNITS_H
#include "clangfilesystemwatcher.h"
#include "translationunit.h" #include "translationunit.h"
#include <filecontainer.h> #include <filecontainer.h>
@@ -43,31 +44,47 @@ namespace ClangBackEnd {
class ProjectParts; class ProjectParts;
class UnsavedFiles; class UnsavedFiles;
class DiagnosticsChangedMessage;
class TranslationUnits class TranslationUnits
{ {
public: public:
TranslationUnits(ProjectParts &projects, UnsavedFiles &unsavedFiles); TranslationUnits(ProjectParts &projectParts, UnsavedFiles &unsavedFiles);
void createOrUpdate(const QVector<FileContainer> &fileContainers); void createOrUpdate(const QVector<FileContainer> &fileContainers);
void remove(const QVector<FileContainer> &fileContainers); void remove(const QVector<FileContainer> &fileContainers);
const TranslationUnit &translationUnit(const Utf8String &filePath, const Utf8String &projectPartId) const; const TranslationUnit &translationUnit(const Utf8String &filePath, const Utf8String &projectPartId) const;
const TranslationUnit &translationUnit(const FileContainer &fileContainer) const;
const std::vector<TranslationUnit> &translationUnits() const; const std::vector<TranslationUnit> &translationUnits() const;
UnsavedFiles &unsavedFiles() const;
void addWatchedFiles(QSet<Utf8String> &filePaths);
void updateTranslationUnitsWithChangedDependencies(const Utf8String &filePath);
void sendChangedDiagnostics();
void setSendChangeDiagnosticsCallback(std::function<void(const DiagnosticsChangedMessage&)> &&callback);
QVector<FileContainer> newerFileContainers(const QVector<FileContainer> &fileContainers) const;
private: private:
void createOrUpdateTranslationUnit(const FileContainer &fileContainer); void createOrUpdateTranslationUnit(const FileContainer &fileContainer);
std::vector<TranslationUnit>::iterator findTranslationUnit(const FileContainer &fileContainer); std::vector<TranslationUnit>::iterator findTranslationUnit(const FileContainer &fileContainer);
std::vector<TranslationUnit>::const_iterator findTranslationUnit(const Utf8String &filePath, const Utf8String &projectPartId) const; std::vector<TranslationUnit>::const_iterator findTranslationUnit(const Utf8String &filePath, const Utf8String &projectPartId) const;
void checkIfProjectPartExists(const Utf8String &projectFileName) const; void checkIfProjectPartExists(const Utf8String &projectFileName) const;
void checkIfProjectPartsExists(const QVector<FileContainer> &fileContainers) const; void checkIfProjectPartsExists(const QVector<FileContainer> &fileContainers) const;
void sendDiagnosticChangedMessage(const TranslationUnit &translationUnit);
private: private:
ClangFileSystemWatcher fileSystemWatcher;
std::function<void(const DiagnosticsChangedMessage&)> sendDiagnosticsChangedCallback;
std::vector<TranslationUnit> translationUnits_; std::vector<TranslationUnit> translationUnits_;
ProjectParts &projects; ProjectParts &projectParts;
UnsavedFiles &unsavedFiles; UnsavedFiles &unsavedFiles_;
}; };
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -30,7 +30,9 @@
#include <clangcodecompleteresults.h> #include <clangcodecompleteresults.h>
#include <projectpart.h> #include <projectpart.h>
#include <projects.h>
#include <translationunit.h> #include <translationunit.h>
#include <translationunits.h>
#include <unsavedfiles.h> #include <unsavedfiles.h>
#include <utf8string.h> #include <utf8string.h>
@@ -51,8 +53,12 @@ using ClangBackEnd::ProjectPart;
TEST(ClangCodeCompleteResults, GetData) TEST(ClangCodeCompleteResults, GetData)
{ {
ProjectPart projectPart(Utf8StringLiteral("projectPartId")); ProjectPart projectPart(Utf8StringLiteral("projectPartId"));
UnsavedFiles unsavedFiles; ClangBackEnd::ProjectParts projects;
TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), unsavedFiles, projectPart); ClangBackEnd::UnsavedFiles unsavedFiles;
ClangBackEnd::TranslationUnits translationUnits{projects, unsavedFiles};
TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"),
projectPart,
translationUnits);
CXCodeCompleteResults *cxCodeCompleteResults = clang_codeCompleteAt(translationUnit.cxTranslationUnit(), translationUnit.filePath().constData(), 49, 1, 0, 0, 0); CXCodeCompleteResults *cxCodeCompleteResults = clang_codeCompleteAt(translationUnit.cxTranslationUnit(), translationUnit.filePath().constData(), 49, 1, 0, 0, 0);
ClangCodeCompleteResults codeCompleteResults(cxCodeCompleteResults); ClangCodeCompleteResults codeCompleteResults(cxCodeCompleteResults);
@@ -72,8 +78,12 @@ TEST(ClangCodeCompleteResults, GetInvalidData)
TEST(ClangCodeCompleteResults, MoveClangCodeCompleteResults) TEST(ClangCodeCompleteResults, MoveClangCodeCompleteResults)
{ {
ProjectPart projectPart(Utf8StringLiteral("projectPartId")); ProjectPart projectPart(Utf8StringLiteral("projectPartId"));
UnsavedFiles unsavedFiles; ClangBackEnd::ProjectParts projects;
TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), unsavedFiles, projectPart); ClangBackEnd::UnsavedFiles unsavedFiles;
ClangBackEnd::TranslationUnits translationUnits{projects, unsavedFiles};
TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"),
projectPart,
translationUnits);
CXCodeCompleteResults *cxCodeCompleteResults = clang_codeCompleteAt(translationUnit.cxTranslationUnit(), translationUnit.filePath().constData(), 49, 1, 0, 0, 0); CXCodeCompleteResults *cxCodeCompleteResults = clang_codeCompleteAt(translationUnit.cxTranslationUnit(), translationUnit.filePath().constData(), 49, 1, 0, 0, 0);
ClangCodeCompleteResults codeCompleteResults(cxCodeCompleteResults); ClangCodeCompleteResults codeCompleteResults(cxCodeCompleteResults);

View File

@@ -222,7 +222,7 @@ TEST_F(ClangIpcServer, GetCodeCompletionForUnsavedFile)
TEST_F(ClangIpcServer, GetNoCodeCompletionAfterRemovingUnsavedFile) TEST_F(ClangIpcServer, GetNoCodeCompletionAfterRemovingUnsavedFile)
{ {
clangServer.registerTranslationUnitsForCodeCompletion(RegisterTranslationUnitForCodeCompletionMessage({FileContainer(functionTestFilePath, projectPartId)})); clangServer.registerTranslationUnitsForCodeCompletion(RegisterTranslationUnitForCodeCompletionMessage({FileContainer(functionTestFilePath, projectPartId, 74)}));
CompleteCodeMessage completeCodeMessage(functionTestFilePath, CompleteCodeMessage completeCodeMessage(functionTestFilePath,
20, 20,
1, 1,
@@ -242,7 +242,8 @@ TEST_F(ClangIpcServer, GetNewCodeCompletionAfterUpdatingUnsavedFile)
clangServer.registerTranslationUnitsForCodeCompletion(RegisterTranslationUnitForCodeCompletionMessage({FileContainer(functionTestFilePath, clangServer.registerTranslationUnitsForCodeCompletion(RegisterTranslationUnitForCodeCompletionMessage({FileContainer(functionTestFilePath,
projectPartId, projectPartId,
unsavedContent(updatedUnsavedTestFilePath), unsavedContent(updatedUnsavedTestFilePath),
true)})); true,
74)}));
CompleteCodeMessage completeCodeMessage(functionTestFilePath, CompleteCodeMessage completeCodeMessage(functionTestFilePath,
20, 20,
1, 1,

View File

@@ -148,8 +148,7 @@ TEST_F(ClientServerInProcess, SendCompleteCodeMessage)
TEST_F(ClientServerInProcess, SendRequestDiagnosticsMessage) TEST_F(ClientServerInProcess, SendRequestDiagnosticsMessage)
{ {
ClangBackEnd::RequestDiagnosticsMessage message({Utf8StringLiteral("foo.cpp"), ClangBackEnd::RequestDiagnosticsMessage message({Utf8StringLiteral("foo.cpp"),
Utf8StringLiteral("projectId")}, Utf8StringLiteral("projectId")});
1);
EXPECT_CALL(mockIpcServer, requestDiagnostics(message)) EXPECT_CALL(mockIpcServer, requestDiagnostics(message))
.Times(1); .Times(1);
@@ -232,8 +231,7 @@ TEST_F(ClientServerInProcess, SendDiagnosticsChangedMessage)
{}, {},
{}); {});
ClangBackEnd::DiagnosticsChangedMessage message(fileContainer, ClangBackEnd::DiagnosticsChangedMessage message(fileContainer,
{container}, {container});
1);
EXPECT_CALL(mockIpcClient, diagnosticsChanged(message)) EXPECT_CALL(mockIpcClient, diagnosticsChanged(message))
.Times(1); .Times(1);

View File

@@ -32,7 +32,9 @@
#include <codecompletionsextractor.h> #include <codecompletionsextractor.h>
#include <filecontainer.h> #include <filecontainer.h>
#include <projectpart.h> #include <projectpart.h>
#include <projects.h>
#include <translationunit.h> #include <translationunit.h>
#include <translationunits.h>
#include <unsavedfiles.h> #include <unsavedfiles.h>
#include <utf8stringvector.h> #include <utf8stringvector.h>
@@ -155,14 +157,16 @@ class CodeCompletionsExtractor : public ::testing::Test
{ {
protected: protected:
ClangBackEnd::ProjectPart project{Utf8StringLiteral("/path/to/projectfile")}; ClangBackEnd::ProjectPart project{Utf8StringLiteral("/path/to/projectfile")};
ClangBackEnd::ProjectParts projects;
ClangBackEnd::UnsavedFiles unsavedFiles; ClangBackEnd::UnsavedFiles unsavedFiles;
TranslationUnit functionTranslationUnit{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_function.cpp"), unsavedFiles, project}; ClangBackEnd::TranslationUnits translationUnits{projects, unsavedFiles};
TranslationUnit variableTranslationUnit{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_variable.cpp"), unsavedFiles, project}; TranslationUnit functionTranslationUnit{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_function.cpp"), project, translationUnits};
TranslationUnit classTranslationUnit{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_class.cpp"), unsavedFiles, project}; TranslationUnit variableTranslationUnit{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_variable.cpp"), project, translationUnits};
TranslationUnit namespaceTranslationUnit{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_namespace.cpp"), unsavedFiles, project}; TranslationUnit classTranslationUnit{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_class.cpp"), project, translationUnits};
TranslationUnit enumerationTranslationUnit{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_enumeration.cpp"), unsavedFiles, project}; TranslationUnit namespaceTranslationUnit{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_namespace.cpp"), project, translationUnits};
TranslationUnit constructorTranslationUnit{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_constructor.cpp"), unsavedFiles, project}; TranslationUnit enumerationTranslationUnit{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_enumeration.cpp"), project, translationUnits};
TranslationUnit briefCommentTranslationUnit{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_brief_comment.cpp"), unsavedFiles, project}; TranslationUnit constructorTranslationUnit{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_constructor.cpp"), project, translationUnits};
TranslationUnit briefCommentTranslationUnit{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_brief_comment.cpp"), project, translationUnits};
}; };
TEST_F(CodeCompletionsExtractor, Function) TEST_F(CodeCompletionsExtractor, Function)
@@ -523,12 +527,11 @@ TEST_F(CodeCompletionsExtractor, NotAvailableFunction)
TEST_F(CodeCompletionsExtractor, UnsavedFile) TEST_F(CodeCompletionsExtractor, UnsavedFile)
{ {
ClangBackEnd::UnsavedFiles unsavedFiles; TranslationUnit translationUnit(Utf8String::fromUtf8(TESTDATA_DIR"/complete_extractor_function.cpp"), project, translationUnits);
ClangBackEnd::ProjectPart project(Utf8StringLiteral("/path/to/projectfile"));
TranslationUnit translationUnit(Utf8String::fromUtf8(TESTDATA_DIR"/complete_extractor_function.cpp"), unsavedFiles, project);
unsavedFiles.createOrUpdate({unsavedDataFileContainer(TESTDATA_DIR"/complete_extractor_function.cpp", unsavedFiles.createOrUpdate({unsavedDataFileContainer(TESTDATA_DIR"/complete_extractor_function.cpp",
TESTDATA_DIR"/complete_extractor_function_unsaved.cpp")}); TESTDATA_DIR"/complete_extractor_function_unsaved.cpp")});
ClangCodeCompleteResults completeResults(getResults(translationUnit, 20)); ClangCodeCompleteResults completeResults(getResults(translationUnit, 20));
unsavedFiles.clear();
::CodeCompletionsExtractor extractor(completeResults.data()); ::CodeCompletionsExtractor extractor(completeResults.data());
@@ -539,15 +542,14 @@ TEST_F(CodeCompletionsExtractor, UnsavedFile)
TEST_F(CodeCompletionsExtractor, ChangeUnsavedFile) TEST_F(CodeCompletionsExtractor, ChangeUnsavedFile)
{ {
ClangBackEnd::UnsavedFiles unsavedFiles; TranslationUnit translationUnit(Utf8String::fromUtf8(TESTDATA_DIR"/complete_extractor_function.cpp"), project, translationUnits);
ClangBackEnd::ProjectPart project(Utf8StringLiteral("/path/to/projectfile"));
TranslationUnit translationUnit(Utf8String::fromUtf8(TESTDATA_DIR"/complete_extractor_function.cpp"), unsavedFiles, project);
unsavedFiles.createOrUpdate({unsavedDataFileContainer(TESTDATA_DIR"/complete_extractor_function.cpp", unsavedFiles.createOrUpdate({unsavedDataFileContainer(TESTDATA_DIR"/complete_extractor_function.cpp",
TESTDATA_DIR"/complete_extractor_function_unsaved.cpp")}); TESTDATA_DIR"/complete_extractor_function_unsaved.cpp")});
ClangCodeCompleteResults completeResults(getResults(translationUnit, 20)); ClangCodeCompleteResults completeResults(getResults(translationUnit, 20));
unsavedFiles.createOrUpdate({unsavedDataFileContainer(TESTDATA_DIR"/complete_extractor_function.cpp", unsavedFiles.createOrUpdate({unsavedDataFileContainer(TESTDATA_DIR"/complete_extractor_function.cpp",
TESTDATA_DIR"/complete_extractor_function_unsaved_2.cpp")}); TESTDATA_DIR"/complete_extractor_function_unsaved_2.cpp")});
completeResults = getResults(translationUnit, 20); completeResults = getResults(translationUnit, 20);
unsavedFiles.clear();
::CodeCompletionsExtractor extractor(completeResults.data()); ::CodeCompletionsExtractor extractor(completeResults.data());
@@ -559,7 +561,7 @@ TEST_F(CodeCompletionsExtractor, ChangeUnsavedFile)
TEST_F(CodeCompletionsExtractor, ArgumentDefinition) TEST_F(CodeCompletionsExtractor, ArgumentDefinition)
{ {
variableTranslationUnit.cxTranslationUnit(); variableTranslationUnit.cxTranslationUnit();
project.setArguments({Utf8StringLiteral("-DArgumentDefinition")}); project.setArguments({Utf8StringLiteral("-DArgumentDefinition"), Utf8StringLiteral("-std=gnu++14")});
ClangCodeCompleteResults completeResults(getResults(variableTranslationUnit, 35)); ClangCodeCompleteResults completeResults(getResults(variableTranslationUnit, 35));
::CodeCompletionsExtractor extractor(completeResults.data()); ::CodeCompletionsExtractor extractor(completeResults.data());
@@ -572,7 +574,7 @@ TEST_F(CodeCompletionsExtractor, ArgumentDefinition)
TEST_F(CodeCompletionsExtractor, NoArgumentDefinition) TEST_F(CodeCompletionsExtractor, NoArgumentDefinition)
{ {
variableTranslationUnit.cxTranslationUnit(); variableTranslationUnit.cxTranslationUnit();
project.setArguments(Utf8StringVector()); project.setArguments({Utf8StringLiteral("-std=gnu++14")});
ClangCodeCompleteResults completeResults(getResults(variableTranslationUnit, 35)); ClangCodeCompleteResults completeResults(getResults(variableTranslationUnit, 35));
::CodeCompletionsExtractor extractor(completeResults.data()); ::CodeCompletionsExtractor extractor(completeResults.data());

View File

@@ -31,10 +31,13 @@
#include <codecompleter.h> #include <codecompleter.h>
#include <filecontainer.h> #include <filecontainer.h>
#include <projectpart.h> #include <projectpart.h>
#include <projects.h>
#include <translationunit.h> #include <translationunit.h>
#include <translationunits.h>
#include <unsavedfiles.h> #include <unsavedfiles.h>
#include <utf8stringvector.h> #include <utf8stringvector.h>
#include <QCoreApplication>
#include <QFile> #include <QFile>
#include <QTemporaryDir> #include <QTemporaryDir>
@@ -82,14 +85,17 @@ protected:
protected: protected:
QTemporaryDir includeDirectory; QTemporaryDir includeDirectory;
Utf8String includePath{QStringLiteral("-I") + includeDirectory.path()};
QString targetHeaderPath{includeDirectory.path() + QStringLiteral("/complete_target_header.h")}; QString targetHeaderPath{includeDirectory.path() + QStringLiteral("/complete_target_header.h")};
ClangBackEnd::ProjectPart projectPart{Utf8StringLiteral("projectPartId")}; ClangBackEnd::ProjectPartContainer projectPart{Utf8StringLiteral("projectPartId"), {includePath}};
ClangBackEnd::FileContainer mainFileContainer{Utf8StringLiteral(TESTDATA_DIR"/complete_completer_main.cpp"),
projectPart.projectPartId()};
ClangBackEnd::ProjectParts projects;
ClangBackEnd::UnsavedFiles unsavedFiles; ClangBackEnd::UnsavedFiles unsavedFiles;
ClangBackEnd::TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/complete_completer_main.cpp"), ClangBackEnd::TranslationUnits translationUnits{projects, unsavedFiles};
unsavedFiles, ClangBackEnd::TranslationUnit translationUnit;
projectPart}; ClangBackEnd::CodeCompleter completer;
ClangBackEnd::CodeCompleter completer{translationUnit}; ClangBackEnd::FileContainer unsavedMainFileContainer{mainFileContainer.filePath(),
ClangBackEnd::FileContainer unsavedMainFileContainer{translationUnit.filePath(),
projectPart.projectPartId(), projectPart.projectPartId(),
readFileContent(QStringLiteral("/complete_completer_main_unsaved.cpp")), readFileContent(QStringLiteral("/complete_completer_main_unsaved.cpp")),
true}; true};
@@ -128,9 +134,10 @@ void CodeCompleter::copyChangedTargetHeaderToTemporaryIncludeDirecory()
void CodeCompleter::SetUp() void CodeCompleter::SetUp()
{ {
EXPECT_TRUE(includeDirectory.isValid()); EXPECT_TRUE(includeDirectory.isValid());
projects.createOrUpdate({projectPart});
Utf8String includePath(QStringLiteral("-I") + includeDirectory.path()); translationUnits.createOrUpdate({mainFileContainer});
projectPart.setArguments({includePath}); translationUnit = translationUnits.translationUnit(mainFileContainer);
completer = ClangBackEnd::CodeCompleter(translationUnit);
copyTargetHeaderToTemporaryIncludeDirecory(); copyTargetHeaderToTemporaryIncludeDirecory();
@@ -140,6 +147,7 @@ void CodeCompleter::SetUp()
TEST_F(CodeCompleter, FunctionInUnsavedFile) TEST_F(CodeCompleter, FunctionInUnsavedFile)
{ {
unsavedFiles.createOrUpdate({unsavedMainFileContainer}); unsavedFiles.createOrUpdate({unsavedMainFileContainer});
translationUnits.createOrUpdate({unsavedMainFileContainer});
ASSERT_THAT(completer.complete(27, 1), ASSERT_THAT(completer.complete(27, 1),
AllOf(Contains(IsCodeCompletion(Utf8StringLiteral("FunctionWithArguments"), AllOf(Contains(IsCodeCompletion(Utf8StringLiteral("FunctionWithArguments"),
@@ -157,6 +165,7 @@ TEST_F(CodeCompleter, FunctionInUnsavedFile)
TEST_F(CodeCompleter, VariableInUnsavedFile) TEST_F(CodeCompleter, VariableInUnsavedFile)
{ {
unsavedFiles.createOrUpdate({unsavedMainFileContainer}); unsavedFiles.createOrUpdate({unsavedMainFileContainer});
translationUnits.createOrUpdate({unsavedMainFileContainer});
ASSERT_THAT(completer.complete(27, 1), ASSERT_THAT(completer.complete(27, 1),
Contains(IsCodeCompletion(Utf8StringLiteral("VariableInUnsavedFile"), Contains(IsCodeCompletion(Utf8StringLiteral("VariableInUnsavedFile"),
@@ -166,6 +175,7 @@ TEST_F(CodeCompleter, VariableInUnsavedFile)
TEST_F(CodeCompleter, GlobalVariableInUnsavedFile) TEST_F(CodeCompleter, GlobalVariableInUnsavedFile)
{ {
unsavedFiles.createOrUpdate({unsavedMainFileContainer}); unsavedFiles.createOrUpdate({unsavedMainFileContainer});
translationUnits.createOrUpdate({unsavedMainFileContainer});
ASSERT_THAT(completer.complete(27, 1), ASSERT_THAT(completer.complete(27, 1),
Contains(IsCodeCompletion(Utf8StringLiteral("GlobalVariableInUnsavedFile"), Contains(IsCodeCompletion(Utf8StringLiteral("GlobalVariableInUnsavedFile"),
@@ -175,6 +185,7 @@ TEST_F(CodeCompleter, GlobalVariableInUnsavedFile)
TEST_F(CodeCompleter, Macro) TEST_F(CodeCompleter, Macro)
{ {
unsavedFiles.createOrUpdate({unsavedMainFileContainer}); unsavedFiles.createOrUpdate({unsavedMainFileContainer});
translationUnits.createOrUpdate({unsavedMainFileContainer});
ASSERT_THAT(completer.complete(27, 1), ASSERT_THAT(completer.complete(27, 1),
Contains(IsCodeCompletion(Utf8StringLiteral("Macro"), Contains(IsCodeCompletion(Utf8StringLiteral("Macro"),
@@ -198,13 +209,14 @@ TEST_F(CodeCompleter, FunctionInIncludedHeader)
TEST_F(CodeCompleter, FunctionInUnsavedIncludedHeader) TEST_F(CodeCompleter, FunctionInUnsavedIncludedHeader)
{ {
unsavedFiles.createOrUpdate({unsavedTargetHeaderFileContainer}); unsavedFiles.createOrUpdate({unsavedTargetHeaderFileContainer});
translationUnits.createOrUpdate({unsavedTargetHeaderFileContainer});
ASSERT_THAT(completer.complete(27, 1), ASSERT_THAT(completer.complete(27, 1),
Contains(IsCodeCompletion(Utf8StringLiteral("FunctionInIncludedHeaderUnsaved"), Contains(IsCodeCompletion(Utf8StringLiteral("FunctionInIncludedHeaderUnsaved"),
CodeCompletion::FunctionCompletionKind))); CodeCompletion::FunctionCompletionKind)));
} }
TEST_F(CodeCompleter, FunctionInChangedIncludedHeader) TEST_F(CodeCompleter, DISABLED_FunctionInChangedIncludedHeader)
{ {
copyChangedTargetHeaderToTemporaryIncludeDirecory(); copyChangedTargetHeaderToTemporaryIncludeDirecory();
@@ -216,6 +228,7 @@ TEST_F(CodeCompleter, FunctionInChangedIncludedHeader)
TEST_F(CodeCompleter, FunctionInChangedIncludedHeaderWithUnsavedContentInMainFile) TEST_F(CodeCompleter, FunctionInChangedIncludedHeaderWithUnsavedContentInMainFile)
{ {
unsavedFiles.createOrUpdate({unsavedMainFileContainer}); unsavedFiles.createOrUpdate({unsavedMainFileContainer});
translationUnits.createOrUpdate({unsavedMainFileContainer});
copyChangedTargetHeaderToTemporaryIncludeDirecory(); copyChangedTargetHeaderToTemporaryIncludeDirecory();

View File

@@ -0,0 +1,32 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** 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 The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include <vector>

View File

@@ -0,0 +1,7 @@
#include "translationunits.h"
void function()
{
}

View File

@@ -0,0 +1,7 @@
#ifndef TRANSLATIONUNITS_H
#define TRANSLATIONUNITS_H
void FunctionInIncludedHeader();
#endif // TRANSLATIONUNITS_H

View File

@@ -30,7 +30,9 @@
#include <diagnosticset.h> #include <diagnosticset.h>
#include <projectpart.h> #include <projectpart.h>
#include <projects.h>
#include <translationunit.h> #include <translationunit.h>
#include <translationunits.h>
#include <unsavedfiles.h> #include <unsavedfiles.h>
#include <clang-c/Index.h> #include <clang-c/Index.h>
@@ -51,10 +53,12 @@ class DiagnosticSet : public ::testing::Test
{ {
protected: protected:
ProjectPart projectPart{Utf8StringLiteral("projectPartId"), {Utf8StringLiteral("-pedantic")}}; ProjectPart projectPart{Utf8StringLiteral("projectPartId"), {Utf8StringLiteral("-pedantic")}};
UnsavedFiles unsavedFiles; ClangBackEnd::ProjectParts projects;
ClangBackEnd::UnsavedFiles unsavedFiles;
ClangBackEnd::TranslationUnits translationUnits{projects, unsavedFiles};
TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/diagnostic_diagnosticset.cpp"), TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/diagnostic_diagnosticset.cpp"),
unsavedFiles, projectPart,
projectPart}; translationUnits};
}; };
TEST_F(DiagnosticSet, SetHasContent) TEST_F(DiagnosticSet, SetHasContent)

View File

@@ -32,6 +32,8 @@
#include <diagnosticset.h> #include <diagnosticset.h>
#include <projectpart.h> #include <projectpart.h>
#include <translationunit.h> #include <translationunit.h>
#include <translationunits.h>
#include <projects.h>
#include <unsavedfiles.h> #include <unsavedfiles.h>
#include <sourcelocation.h> #include <sourcelocation.h>
#include <sourcerange.h> #include <sourcerange.h>
@@ -50,6 +52,7 @@ using ClangBackEnd::UnsavedFiles;
using ClangBackEnd::Diagnostic; using ClangBackEnd::Diagnostic;
using ClangBackEnd::SourceLocation; using ClangBackEnd::SourceLocation;
using ClangBackEnd::DiagnosticSeverity; using ClangBackEnd::DiagnosticSeverity;
using ClangBackEnd::TranslationUnits;
using testing::PrintToString; using testing::PrintToString;
namespace { namespace {
@@ -75,10 +78,12 @@ class Diagnostic : public ::testing::Test
{ {
protected: protected:
ProjectPart projectPart{Utf8StringLiteral("projectPartId"), {Utf8StringLiteral("-std=c++11")}}; ProjectPart projectPart{Utf8StringLiteral("projectPartId"), {Utf8StringLiteral("-std=c++11")}};
UnsavedFiles unsavedFiles; ClangBackEnd::ProjectParts projects;
ClangBackEnd::UnsavedFiles unsavedFiles;
ClangBackEnd::TranslationUnits translationUnits{projects, unsavedFiles};
TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/diagnostic_diagnostic.cpp"), TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/diagnostic_diagnostic.cpp"),
unsavedFiles, projectPart,
projectPart}; translationUnits};
DiagnosticSet diagnosticSet{translationUnit.diagnostics()}; DiagnosticSet diagnosticSet{translationUnit.diagnostics()};
::Diagnostic diagnostic{diagnosticSet.back()}; ::Diagnostic diagnostic{diagnosticSet.back()};
}; };

View File

@@ -31,7 +31,9 @@
#include <diagnostic.h> #include <diagnostic.h>
#include <diagnosticset.h> #include <diagnosticset.h>
#include <projectpart.h> #include <projectpart.h>
#include <projects.h>
#include <translationunit.h> #include <translationunit.h>
#include <translationunits.h>
#include <unsavedfiles.h> #include <unsavedfiles.h>
#include <sourcelocation.h> #include <sourcelocation.h>
#include <sourcerange.h> #include <sourcerange.h>
@@ -75,10 +77,12 @@ class FixIt : public ::testing::Test
{ {
protected: protected:
ProjectPart projectPart{Utf8StringLiteral("projectPartId")}; ProjectPart projectPart{Utf8StringLiteral("projectPartId")};
UnsavedFiles unsavedFiles; ClangBackEnd::ProjectParts projects;
ClangBackEnd::UnsavedFiles unsavedFiles;
ClangBackEnd::TranslationUnits translationUnits{projects, unsavedFiles};
TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/diagnostic_fixit.cpp"), TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/diagnostic_fixit.cpp"),
unsavedFiles, projectPart,
projectPart}; translationUnits};
DiagnosticSet diagnosticSet{translationUnit.diagnostics()}; DiagnosticSet diagnosticSet{translationUnit.diagnostics()};
Diagnostic diagnostic{diagnosticSet.front()}; Diagnostic diagnostic{diagnosticSet.front()};
::FixIt fixIt{diagnostic.fixIts().front()}; ::FixIt fixIt{diagnostic.fixIts().front()};

View File

@@ -180,15 +180,14 @@ TEST_F(ReadAndWriteMessageBlock, CompareDiagnosticsChangedMessage)
{}); {});
CompareMessage(ClangBackEnd::DiagnosticsChangedMessage(fileContainer, CompareMessage(ClangBackEnd::DiagnosticsChangedMessage(fileContainer,
{container}, {container}));
1));
} }
TEST_F(ReadAndWriteMessageBlock, RequestDiagnosticsMessage) TEST_F(ReadAndWriteMessageBlock, RequestDiagnosticsMessage)
{ {
ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), Utf8StringLiteral("pathToProject.pro")); ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), Utf8StringLiteral("pathToProject.pro"));
CompareMessage(ClangBackEnd::RequestDiagnosticsMessage(fileContainer, 1)); CompareMessage(ClangBackEnd::RequestDiagnosticsMessage(fileContainer));
} }
TEST_F(ReadAndWriteMessageBlock, GetInvalidMessageForAPartialBuffer) TEST_F(ReadAndWriteMessageBlock, GetInvalidMessageForAPartialBuffer)

View File

@@ -31,7 +31,9 @@
#include <diagnostic.h> #include <diagnostic.h>
#include <diagnosticset.h> #include <diagnosticset.h>
#include <projectpart.h> #include <projectpart.h>
#include <projects.h>
#include <translationunit.h> #include <translationunit.h>
#include <translationunits.h>
#include <unsavedfiles.h> #include <unsavedfiles.h>
#include <sourcelocation.h> #include <sourcelocation.h>
@@ -56,10 +58,12 @@ class SourceLocation : public ::testing::Test
{ {
protected: protected:
ProjectPart projectPart{Utf8StringLiteral("projectPartId")}; ProjectPart projectPart{Utf8StringLiteral("projectPartId")};
UnsavedFiles unsavedFiles; ClangBackEnd::ProjectParts projects;
ClangBackEnd::UnsavedFiles unsavedFiles;
ClangBackEnd::TranslationUnits translationUnits{projects, unsavedFiles};
TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/diagnostic_source_location.cpp"), TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/diagnostic_source_location.cpp"),
unsavedFiles, projectPart,
projectPart}; translationUnits};
DiagnosticSet diagnosticSet{translationUnit.diagnostics()}; DiagnosticSet diagnosticSet{translationUnit.diagnostics()};
Diagnostic diagnostic{diagnosticSet.front()}; Diagnostic diagnostic{diagnosticSet.front()};
::SourceLocation sourceLocation{diagnostic.location()}; ::SourceLocation sourceLocation{diagnostic.location()};

View File

@@ -32,6 +32,8 @@
#include <diagnosticset.h> #include <diagnosticset.h>
#include <projectpart.h> #include <projectpart.h>
#include <translationunit.h> #include <translationunit.h>
#include <translationunits.h>
#include <projects.h>
#include <unsavedfiles.h> #include <unsavedfiles.h>
#include <sourcerange.h> #include <sourcerange.h>
@@ -48,6 +50,7 @@ using ClangBackEnd::ProjectPart;
using ClangBackEnd::UnsavedFiles; using ClangBackEnd::UnsavedFiles;
using ClangBackEnd::Diagnostic; using ClangBackEnd::Diagnostic;
using ClangBackEnd::SourceRange; using ClangBackEnd::SourceRange;
using ClangBackEnd::TranslationUnits;
using testing::PrintToString; using testing::PrintToString;
namespace { namespace {
@@ -74,10 +77,12 @@ class SourceRange : public ::testing::Test
{ {
protected: protected:
ProjectPart projectPart{Utf8StringLiteral("projectPartId"), {Utf8StringLiteral("-pedantic")}}; ProjectPart projectPart{Utf8StringLiteral("projectPartId"), {Utf8StringLiteral("-pedantic")}};
UnsavedFiles unsavedFiles; ClangBackEnd::ProjectParts projects;
ClangBackEnd::UnsavedFiles unsavedFiles;
ClangBackEnd::TranslationUnits translationUnits{projects, unsavedFiles};
TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/diagnostic_source_range.cpp"), TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/diagnostic_source_range.cpp"),
unsavedFiles, projectPart,
projectPart}; translationUnits};
DiagnosticSet diagnosticSet{translationUnit.diagnostics()}; DiagnosticSet diagnosticSet{translationUnit.diagnostics()};
Diagnostic diagnostic{diagnosticSet.front()}; Diagnostic diagnostic{diagnosticSet.front()};
::SourceRange sourceRange{diagnostic.ranges().front()}; ::SourceRange sourceRange{diagnostic.ranges().front()};

View File

@@ -63,22 +63,16 @@ namespace {
using ::testing::PrintToString; using ::testing::PrintToString;
MATCHER_P2(IsTranslationUnit, filePath, projectPartId, MATCHER_P3(IsTranslationUnit, filePath, projectPartId, documentRevision,
std::string(negation ? "isn't" : "is") + " translation unit with file path " std::string(negation ? "isn't" : "is")
+ PrintToString(filePath) + " and project " + PrintToString(projectPartId) + " translation unit with file path "+ PrintToString(filePath)
+ " and project " + PrintToString(projectPartId)
+ " and document revision " + PrintToString(documentRevision)
) )
{ {
if (arg.filePath() != filePath) { return arg.filePath() == filePath
*result_listener << "file path is " + PrintToString(arg.filePath()) + " and not " + PrintToString(filePath); && arg.projectPartId() == projectPartId
return false; && arg.documentRevision() == documentRevision;
}
if (arg.projectPartId() != projectPartId) {
*result_listener << "file path is " + PrintToString(arg.projectPartId()) + " and not " + PrintToString(projectPartId);
return false;
}
return true;
} }
class TranslationUnits : public ::testing::Test class TranslationUnits : public ::testing::Test
@@ -88,10 +82,12 @@ protected:
ClangBackEnd::ProjectParts projects; ClangBackEnd::ProjectParts projects;
ClangBackEnd::UnsavedFiles unsavedFiles; ClangBackEnd::UnsavedFiles unsavedFiles;
ClangBackEnd::TranslationUnits translationUnits = ClangBackEnd::TranslationUnits(projects, unsavedFiles); ClangBackEnd::TranslationUnits translationUnits{projects, unsavedFiles};
const Utf8String filePath = Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"); const Utf8String filePath = Utf8StringLiteral(TESTDATA_DIR"/translationunits.cpp");
const Utf8String projectPartId = Utf8StringLiteral("/path/to/projectfile"); const Utf8String headerPath = Utf8StringLiteral(TESTDATA_DIR"/translationunits.h");
const Utf8String nonExistingFilePath = Utf8StringLiteral("foo.cpp");
const Utf8String projectPartId = Utf8StringLiteral("projectPartId");
const Utf8String nonExistingProjectPartId = Utf8StringLiteral("nonExistingProjectPartId");
}; };
void TranslationUnits::SetUp() void TranslationUnits::SetUp()
@@ -102,21 +98,21 @@ void TranslationUnits::SetUp()
TEST_F(TranslationUnits, ThrowForGettingWithWrongFilePath) TEST_F(TranslationUnits, ThrowForGettingWithWrongFilePath)
{ {
ASSERT_THROW(translationUnits.translationUnit(Utf8StringLiteral("foo.cpp"), projectPartId), ASSERT_THROW(translationUnits.translationUnit(nonExistingFilePath, projectPartId),
ClangBackEnd::TranslationUnitDoesNotExistException); ClangBackEnd::TranslationUnitDoesNotExistException);
} }
TEST_F(TranslationUnits, ThrowForGettingWithWrongProjectPartFilePath) TEST_F(TranslationUnits, ThrowForGettingWithWrongProjectPartFilePath)
{ {
ASSERT_THROW(translationUnits.translationUnit(filePath, Utf8StringLiteral("foo.pro")), ASSERT_THROW(translationUnits.translationUnit(filePath, nonExistingProjectPartId),
ClangBackEnd::ProjectPartDoNotExistException); ClangBackEnd::ProjectPartDoNotExistException);
} }
TEST_F(TranslationUnits, ThrowForAddingNonExistingFile) TEST_F(TranslationUnits, ThrowForAddingNonExistingFile)
{ {
ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), projectPartId); ClangBackEnd::FileContainer fileContainer(nonExistingFilePath, projectPartId);
ASSERT_THROW(translationUnits.createOrUpdate({fileContainer}), ASSERT_THROW(translationUnits.createOrUpdate({fileContainer}),
ClangBackEnd::TranslationUnitFileNotExitsException); ClangBackEnd::TranslationUnitFileNotExitsException);
@@ -124,24 +120,59 @@ TEST_F(TranslationUnits, ThrowForAddingNonExistingFile)
TEST_F(TranslationUnits, DoNotThrowForAddingNonExistingFileWithUnsavedContent) TEST_F(TranslationUnits, DoNotThrowForAddingNonExistingFileWithUnsavedContent)
{ {
ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), projectPartId, Utf8String(), true); ClangBackEnd::FileContainer fileContainer(nonExistingFilePath, projectPartId, Utf8String(), true);
ASSERT_NO_THROW(translationUnits.createOrUpdate({fileContainer})); ASSERT_NO_THROW(translationUnits.createOrUpdate({fileContainer}));
} }
TEST_F(TranslationUnits, Add) TEST_F(TranslationUnits, Add)
{ {
ClangBackEnd::FileContainer fileContainer(filePath, projectPartId); ClangBackEnd::FileContainer fileContainer(filePath, projectPartId, 74u);
translationUnits.createOrUpdate({fileContainer}); translationUnits.createOrUpdate({fileContainer});
ASSERT_THAT(translationUnits.translationUnit(filePath, projectPartId), ASSERT_THAT(translationUnits.translationUnit(filePath, projectPartId),
IsTranslationUnit(filePath, projectPartId)); IsTranslationUnit(filePath, projectPartId, 74u));
}
TEST_F(TranslationUnits, UpdateUnsavedFileAndCheckForReparse)
{
ClangBackEnd::FileContainer fileContainer(filePath, projectPartId, 74u);
ClangBackEnd::FileContainer headerContainer(headerPath, projectPartId, 74u);
ClangBackEnd::FileContainer headerContainerWithUnsavedContent(headerPath, projectPartId, Utf8String(), true, 75u);
translationUnits.createOrUpdate({fileContainer, headerContainer});
translationUnits.translationUnit(filePath, projectPartId).cxTranslationUnit();
translationUnits.createOrUpdate({headerContainerWithUnsavedContent});
ASSERT_TRUE(translationUnits.translationUnit(filePath, projectPartId).isNeedingReparse());
}
TEST_F(TranslationUnits, DontGetNewerFileContainerIfRevisionIsTheSame)
{
ClangBackEnd::FileContainer fileContainer(filePath, projectPartId, 74u);
translationUnits.createOrUpdate({fileContainer});
auto newerFileContainers = translationUnits.newerFileContainers({fileContainer});
ASSERT_THAT(newerFileContainers.size(), 0);
}
TEST_F(TranslationUnits, GetNewerFileContainerIfRevisionIsDifferent)
{
ClangBackEnd::FileContainer fileContainer(filePath, projectPartId, 74u);
ClangBackEnd::FileContainer newerContainer(filePath, projectPartId, 75u);
translationUnits.createOrUpdate({fileContainer});
auto newerFileContainers = translationUnits.newerFileContainers({newerContainer});
ASSERT_THAT(newerFileContainers.size(), 1);
} }
TEST_F(TranslationUnits, ThrowForRemovingWithWrongFilePath) TEST_F(TranslationUnits, ThrowForRemovingWithWrongFilePath)
{ {
ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), projectPartId); ClangBackEnd::FileContainer fileContainer(nonExistingFilePath, projectPartId);
ASSERT_THROW(translationUnits.remove({fileContainer}), ASSERT_THROW(translationUnits.remove({fileContainer}),
ClangBackEnd::TranslationUnitDoesNotExistException); ClangBackEnd::TranslationUnitDoesNotExistException);
@@ -149,7 +180,7 @@ TEST_F(TranslationUnits, ThrowForRemovingWithWrongFilePath)
TEST_F(TranslationUnits, ThrowForRemovingWithWrongProjectPartFilePath) TEST_F(TranslationUnits, ThrowForRemovingWithWrongProjectPartFilePath)
{ {
ClangBackEnd::FileContainer fileContainer(filePath, Utf8StringLiteral("foo.pro")); ClangBackEnd::FileContainer fileContainer(filePath, nonExistingProjectPartId);
ASSERT_THROW(translationUnits.remove({fileContainer}), ASSERT_THROW(translationUnits.remove({fileContainer}),
ClangBackEnd::ProjectPartDoNotExistException); ClangBackEnd::ProjectPartDoNotExistException);
@@ -175,7 +206,9 @@ TEST_F(TranslationUnits, RemoveAllValidIfExceptionIsThrown)
ClangBackEnd::TranslationUnitDoesNotExistException); ClangBackEnd::TranslationUnitDoesNotExistException);
ASSERT_THAT(translationUnits.translationUnits(), ASSERT_THAT(translationUnits.translationUnits(),
Not(Contains(TranslationUnit(filePath, unsavedFiles, projects.project(projectPartId))))); Not(Contains(TranslationUnit(filePath,
projects.project(projectPartId),
translationUnits))));
} }
} }

View File

@@ -54,101 +54,132 @@
using ClangBackEnd::TranslationUnit; using ClangBackEnd::TranslationUnit;
using ClangBackEnd::UnsavedFiles; using ClangBackEnd::UnsavedFiles;
using ClangBackEnd::ProjectPart; using ClangBackEnd::ProjectPart;
using ClangBackEnd::TranslationUnits;
using testing::IsNull; using testing::IsNull;
using testing::NotNull; using testing::NotNull;
using testing::Gt; using testing::Gt;
using testing::Contains;
using testing::EndsWith;
using testing::AllOf;
namespace { namespace {
TEST(TranslationUnit, DefaultTranslationUnitIsInvalid) class TranslationUnit : public ::testing::Test
{ {
TranslationUnit translationUnit; protected:
ClangBackEnd::ProjectParts projects;
ClangBackEnd::UnsavedFiles unsavedFiles;
ClangBackEnd::TranslationUnits translationUnits{projects, unsavedFiles};
::TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/translationunits.cpp"),
ProjectPart(Utf8StringLiteral("/path/to/projectfile")),
translationUnits};
};
TEST_F(TranslationUnit, DefaultTranslationUnitIsInvalid)
{
::TranslationUnit translationUnit;
ASSERT_TRUE(translationUnit.isNull()); ASSERT_TRUE(translationUnit.isNull());
} }
TEST(TranslationUnit, ThrowExceptionForNonExistingFilePath) TEST_F(TranslationUnit, ThrowExceptionForNonExistingFilePath)
{ {
ASSERT_THROW(TranslationUnit(Utf8StringLiteral("file.cpp"), UnsavedFiles(), ProjectPart(Utf8StringLiteral("/path/to/projectfile"))), ASSERT_THROW(::TranslationUnit(Utf8StringLiteral("file.cpp"), ProjectPart(Utf8StringLiteral("/path/to/projectfile")), translationUnits),
ClangBackEnd::TranslationUnitFileNotExitsException); ClangBackEnd::TranslationUnitFileNotExitsException);
} }
TEST(TranslationUnit, ThrowNoExceptionForNonExistingFilePathIfDoNotCheckIfFileExistsIsSet) TEST_F(TranslationUnit, ThrowNoExceptionForNonExistingFilePathIfDoNotCheckIfFileExistsIsSet)
{ {
ASSERT_NO_THROW(TranslationUnit(Utf8StringLiteral("file.cpp"), UnsavedFiles(), ProjectPart(Utf8StringLiteral("/path/to/projectfile")), TranslationUnit::DoNotCheckIfFileExists)); ASSERT_NO_THROW(::TranslationUnit(Utf8StringLiteral("file.cpp"), ProjectPart(Utf8StringLiteral("/path/to/projectfile")), translationUnits, ::TranslationUnit::DoNotCheckIfFileExists));
} }
TEST(TranslationUnit, TranslationUnitIsValid) TEST_F(TranslationUnit, TranslationUnitIsValid)
{ {
TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), UnsavedFiles(), ProjectPart(Utf8StringLiteral("/path/to/projectfile")));
ASSERT_FALSE(translationUnit.isNull()); ASSERT_FALSE(translationUnit.isNull());
} }
TEST(TranslationUnit, ThrowExceptionForGettingIndexForInvalidUnit) TEST_F(TranslationUnit, ThrowExceptionForGettingIndexForInvalidUnit)
{ {
TranslationUnit translationUnit; ::TranslationUnit translationUnit;
ASSERT_THROW(translationUnit.index(), ClangBackEnd::TranslationUnitIsNullException); ASSERT_THROW(translationUnit.index(), ClangBackEnd::TranslationUnitIsNullException);
} }
TEST(TranslationUnit, IndexGetterIsNonNullForValidUnit) TEST_F(TranslationUnit, IndexGetterIsNonNullForValidUnit)
{ {
TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), UnsavedFiles(), ProjectPart(Utf8StringLiteral("/path/to/projectfile")));
ASSERT_THAT(translationUnit.index(), NotNull()); ASSERT_THAT(translationUnit.index(), NotNull());
} }
TEST(TranslationUnit, ThrowExceptionForGettingCxTranslationUnitForInvalidUnit) TEST_F(TranslationUnit, ThrowExceptionForGettingCxTranslationUnitForInvalidUnit)
{ {
TranslationUnit translationUnit; ::TranslationUnit translationUnit;
ASSERT_THROW(translationUnit.cxTranslationUnit(), ClangBackEnd::TranslationUnitIsNullException); ASSERT_THROW(translationUnit.cxTranslationUnit(), ClangBackEnd::TranslationUnitIsNullException);
} }
TEST(TranslationUnit, CxTranslationUnitGetterIsNonNullForValidUnit) TEST_F(TranslationUnit, CxTranslationUnitGetterIsNonNullForValidUnit)
{ {
UnsavedFiles unsavedFiles;
TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), unsavedFiles, ProjectPart(Utf8StringLiteral("/path/to/projectfile")));
ASSERT_THAT(translationUnit.cxTranslationUnit(), NotNull()); ASSERT_THAT(translationUnit.cxTranslationUnit(), NotNull());
} }
TEST(TranslationUnit, ThrowExceptionIfGettingFilePathForNullUnit) TEST_F(TranslationUnit, ThrowExceptionIfGettingFilePathForNullUnit)
{ {
TranslationUnit translationUnit; ::TranslationUnit translationUnit;
ASSERT_THROW(translationUnit.filePath(), ClangBackEnd::TranslationUnitIsNullException); ASSERT_THROW(translationUnit.filePath(), ClangBackEnd::TranslationUnitIsNullException);
} }
TEST(TranslationUnit, ResetedTranslationUnitIsNull) TEST_F(TranslationUnit, ResetedTranslationUnitIsNull)
{ {
TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), UnsavedFiles(), ProjectPart(Utf8StringLiteral("/path/to/projectfile")));
translationUnit.reset(); translationUnit.reset();
ASSERT_TRUE(translationUnit.isNull()); ASSERT_TRUE(translationUnit.isNull());
} }
TEST(TranslationUnit, TimeStampIsUpdatedAsNewCxTranslationUnitIsGenerated) TEST_F(TranslationUnit, TimeStampForProjectPartChangeIsUpdatedAsNewCxTranslationUnitIsGenerated)
{ {
TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), UnsavedFiles(), ProjectPart(Utf8StringLiteral("/path/to/projectfile"))); auto lastChangeTimePoint = translationUnit.lastProjectPartChangeTimePoint();
auto lastChangeTimePoint = translationUnit.lastChangeTimePoint();
std::this_thread::sleep_for(std::chrono::steady_clock::duration(1)); std::this_thread::sleep_for(std::chrono::steady_clock::duration(1));
translationUnit.cxTranslationUnit(); translationUnit.cxTranslationUnit();
ASSERT_THAT(translationUnit.lastChangeTimePoint(), Gt(lastChangeTimePoint)); ASSERT_THAT(translationUnit.lastProjectPartChangeTimePoint(), Gt(lastChangeTimePoint));
} }
TEST_F(TranslationUnit, TimeStampForProjectPartChangeIsUpdatedAsProjectPartIsCleared)
{
ProjectPart projectPart = translationUnit.projectPart();
translationUnit.cxTranslationUnit();
auto lastChangeTimePoint = translationUnit.lastProjectPartChangeTimePoint();
std::this_thread::sleep_for(std::chrono::steady_clock::duration(1));
//TEST(TranslationUnit, ThrowParseErrorForWrongArguments) projectPart.clear();
translationUnit.cxTranslationUnit();
ASSERT_THAT(translationUnit.lastProjectPartChangeTimePoint(), Gt(lastChangeTimePoint));
}
TEST_F(TranslationUnit, DocumentRevisionInFileContainerGetter)
{
translationUnit.setDocumentRevision(74);
ASSERT_THAT(translationUnit.fileContainer().documentRevision(), 74);
}
TEST_F(TranslationUnit, DependedFilePaths)
{
ASSERT_THAT(translationUnit.dependedFilePaths(),
AllOf(Contains(Utf8StringLiteral(TESTDATA_DIR"/translationunits.cpp")),
Contains(Utf8StringLiteral(TESTDATA_DIR"/translationunits.h"))));
}
//TEST_F(TranslationUnit, ThrowParseErrorForWrongArguments)
//{ //{
// ProjectPart project(Utf8StringLiteral("/path/to/projectfile")); // ProjectPart project(Utf8StringLiteral("/path/to/projectfile"));
// project.setArguments({Utf8StringLiteral("-fblah")}); // project.setArguments({Utf8StringLiteral("-fblah")});
// TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), UnsavedFiles(), project); // TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), unsavedFiles, project);
// ASSERT_THROW(translationUnit.cxTranslationUnit(), ClangBackEnd::TranslationUnitParseErrorException); // ASSERT_THROW(translationUnit.cxTranslationUnit(), ClangBackEnd::TranslationUnitParseErrorException);
//} //}

View File

@@ -85,6 +85,11 @@ protected:
protected: protected:
::UnsavedFiles unsavedFiles; ::UnsavedFiles unsavedFiles;
Utf8String filePath{Utf8StringLiteral("file.cpp")};
Utf8String projectPartId{Utf8StringLiteral("projectPartId")};
Utf8String unsavedContent1{Utf8StringLiteral("foo")};
Utf8String unsavedContent2{Utf8StringLiteral("bar")};
}; };
void UnsavedFiles::TearDown() void UnsavedFiles::TearDown()
@@ -94,7 +99,7 @@ void UnsavedFiles::TearDown()
TEST_F(UnsavedFiles, DoNothingForUpdateIfFileHasNoUnsavedContent) TEST_F(UnsavedFiles, DoNothingForUpdateIfFileHasNoUnsavedContent)
{ {
QVector<FileContainer> fileContainers({FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"))}); QVector<FileContainer> fileContainers({FileContainer(filePath, projectPartId)});
unsavedFiles.createOrUpdate(fileContainers); unsavedFiles.createOrUpdate(fileContainers);
@@ -103,17 +108,17 @@ TEST_F(UnsavedFiles, DoNothingForUpdateIfFileHasNoUnsavedContent)
TEST_F(UnsavedFiles, AddUnsavedFileForUpdateWithUnsavedContent) TEST_F(UnsavedFiles, AddUnsavedFileForUpdateWithUnsavedContent)
{ {
QVector<FileContainer> fileContainers({FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro")), QVector<FileContainer> fileContainers({FileContainer(filePath, projectPartId),
FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"), Utf8StringLiteral("foo"), true)}); FileContainer(filePath, projectPartId, unsavedContent1, true)});
unsavedFiles.createOrUpdate(fileContainers); unsavedFiles.createOrUpdate(fileContainers);
ASSERT_THAT(unsavedFiles, HasUnsavedFiles(QVector<FileContainer>({FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"), Utf8StringLiteral("foo"), true)}))); ASSERT_THAT(unsavedFiles, HasUnsavedFiles(QVector<FileContainer>({FileContainer(filePath, projectPartId, unsavedContent1, true)})));
} }
TEST_F(UnsavedFiles, RemoveUnsavedFileForUpdateWithUnsavedContent) TEST_F(UnsavedFiles, RemoveUnsavedFileForUpdateWithUnsavedContent)
{ {
QVector<FileContainer> fileContainers({FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"), Utf8StringLiteral("foo"), true), QVector<FileContainer> fileContainers({FileContainer(filePath, projectPartId, unsavedContent1, true),
FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"))}); FileContainer(filePath, projectPartId)});
unsavedFiles.createOrUpdate(fileContainers); unsavedFiles.createOrUpdate(fileContainers);
@@ -122,17 +127,17 @@ TEST_F(UnsavedFiles, RemoveUnsavedFileForUpdateWithUnsavedContent)
TEST_F(UnsavedFiles, ExchangeUnsavedFileForUpdateWithUnsavedContent) TEST_F(UnsavedFiles, ExchangeUnsavedFileForUpdateWithUnsavedContent)
{ {
QVector<FileContainer> fileContainers({FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"), Utf8StringLiteral("foo"), true), QVector<FileContainer> fileContainers({FileContainer(filePath, projectPartId, unsavedContent1, true),
FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"), Utf8StringLiteral("foo2"), true)}); FileContainer(filePath, projectPartId, unsavedContent2, true)});
unsavedFiles.createOrUpdate(fileContainers); unsavedFiles.createOrUpdate(fileContainers);
ASSERT_THAT(unsavedFiles, HasUnsavedFiles(QVector<FileContainer>({FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"), Utf8StringLiteral("foo2"), true)}))); ASSERT_THAT(unsavedFiles, HasUnsavedFiles(QVector<FileContainer>({FileContainer(filePath, projectPartId, unsavedContent2, true)})));
} }
TEST_F(UnsavedFiles, TimeStampIsUpdatedAsUnsavedFilesChanged) TEST_F(UnsavedFiles, TimeStampIsUpdatedAsUnsavedFilesChanged)
{ {
QVector<FileContainer> fileContainers({FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"), Utf8StringLiteral("foo"), true), QVector<FileContainer> fileContainers({FileContainer(filePath, projectPartId, unsavedContent1, true),
FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"), Utf8StringLiteral("foo2"), true)}); FileContainer(filePath, projectPartId, unsavedContent2, true)});
auto lastChangeTimePoint = unsavedFiles.lastChangeTimePoint(); auto lastChangeTimePoint = unsavedFiles.lastChangeTimePoint();
unsavedFiles.createOrUpdate(fileContainers); unsavedFiles.createOrUpdate(fileContainers);
@@ -142,7 +147,7 @@ TEST_F(UnsavedFiles, TimeStampIsUpdatedAsUnsavedFilesChanged)
TEST_F(UnsavedFiles, RemoveUnsavedFiles) TEST_F(UnsavedFiles, RemoveUnsavedFiles)
{ {
QVector<FileContainer> fileContainers({FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"), Utf8StringLiteral("foo"), true)}); QVector<FileContainer> fileContainers({FileContainer(filePath, projectPartId, unsavedContent1, true)});
unsavedFiles.createOrUpdate(fileContainers); unsavedFiles.createOrUpdate(fileContainers);
unsavedFiles.remove(fileContainers); unsavedFiles.remove(fileContainers);