Clang: Extract TranslationUnitUpdater

...in preparation for concurrent processing of documents.

Parsing and reparsing is handled by TranslationUnit. Since we will do
this in a different thread, extract the core logic into the new class
TranslationUnitUpdater, so that we can prepare the necessary data for
the run and then later incorporate the results of the parse/reparse.

Change-Id: Ic9d936d193ee6795a755f0cfc38c0b2a7bd402cc
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
Nikolai Kosjar
2016-07-15 12:30:25 +02:00
parent 606d41187c
commit dc734f45fd
10 changed files with 541 additions and 157 deletions

View File

@@ -30,6 +30,7 @@ HEADERS += $$PWD/clangcodemodelserver.h \
$$PWD/cursor.h \ $$PWD/cursor.h \
$$PWD/skippedsourceranges.h \ $$PWD/skippedsourceranges.h \
$$PWD/clangtranslationunit.h \ $$PWD/clangtranslationunit.h \
$$PWD/clangtranslationunitupdater.h \
$$PWD/clangtype.h \ $$PWD/clangtype.h \
$$PWD/highlightingmark.h \ $$PWD/highlightingmark.h \
$$PWD/highlightingmarks.h \ $$PWD/highlightingmarks.h \
@@ -67,6 +68,7 @@ SOURCES += $$PWD/clangcodemodelserver.cpp \
$$PWD/cursor.cpp \ $$PWD/cursor.cpp \
$$PWD/skippedsourceranges.cpp \ $$PWD/skippedsourceranges.cpp \
$$PWD/clangtranslationunit.cpp \ $$PWD/clangtranslationunit.cpp \
$$PWD/clangtranslationunitupdater.cpp \
$$PWD/clangtype.cpp \ $$PWD/clangtype.cpp \
$$PWD/highlightingmark.cpp \ $$PWD/highlightingmark.cpp \
$$PWD/highlightingmarks.cpp \ $$PWD/highlightingmarks.cpp \

View File

@@ -42,6 +42,7 @@
#include "translationunitisnullexception.h" #include "translationunitisnullexception.h"
#include "translationunitparseerrorexception.h" #include "translationunitparseerrorexception.h"
#include "translationunitreparseerrorexception.h" #include "translationunitreparseerrorexception.h"
#include "clangtranslationunitupdater.h"
#include "translationunits.h" #include "translationunits.h"
#include "unsavedfiles.h" #include "unsavedfiles.h"
#include "unsavedfile.h" #include "unsavedfile.h"
@@ -54,13 +55,6 @@
#include <ostream> #include <ostream>
static Q_LOGGING_CATEGORY(verboseLibLog, "qtc.clangbackend.verboselib");
static bool isVerboseModeEnabled()
{
return verboseLibLog().isDebugEnabled();
}
namespace ClangBackEnd { namespace ClangBackEnd {
class TranslationUnitData class TranslationUnitData
@@ -158,7 +152,7 @@ void TranslationUnit::reparse() const
{ {
cxTranslationUnit(); cxTranslationUnit();
reparseTranslationUnit(); updateSynchronously(TranslationUnitUpdater::UpdateMode::ForceReparse);
} }
bool TranslationUnit::parseWasSuccessful() const bool TranslationUnit::parseWasSuccessful() const
@@ -171,22 +165,19 @@ bool TranslationUnit::reparseWasSuccessful() const
return d->reparseErrorCode == 0; return d->reparseErrorCode == 0;
} }
CXIndex TranslationUnit::index() const CXIndex &TranslationUnit::index() const
{ {
checkIfNull(); checkIfNull();
if (!d->index) {
const bool displayDiagnostics = isVerboseModeEnabled();
d->index = clang_createIndex(1, displayDiagnostics);
}
return d->index; return d->index;
} }
CXTranslationUnit TranslationUnit::cxTranslationUnit() const CXTranslationUnit TranslationUnit::cxTranslationUnit() const
{ {
cxTranslationUnitWithoutReparsing(); checkIfNull();
reparseTranslationUnitIfFilesAreChanged(); checkIfFileExists();
updateSynchronously(TranslationUnitUpdater::UpdateMode::AsNeeded);
return d->translationUnit; return d->translationUnit;
} }
@@ -195,8 +186,8 @@ CXTranslationUnit TranslationUnit::cxTranslationUnitWithoutReparsing() const
{ {
checkIfNull(); checkIfNull();
checkIfFileExists(); checkIfFileExists();
removeTranslationUnitIfProjectPartWasChanged();
createTranslationUnitIfNeeded(); updateSynchronously(TranslationUnitUpdater::UpdateMode::ParseIfNeeded);
return d->translationUnit; return d->translationUnit;
} }
@@ -294,7 +285,7 @@ QVector<ClangBackEnd::DiagnosticContainer> TranslationUnit::mainFileDiagnostics(
const QSet<Utf8String> &TranslationUnit::dependedFilePaths() const const QSet<Utf8String> &TranslationUnit::dependedFilePaths() const
{ {
createTranslationUnitIfNeeded(); cxTranslationUnit();
return d->dependedFilePaths; return d->dependedFilePaths;
} }
@@ -377,19 +368,6 @@ void TranslationUnit::checkIfFileExists() const
throw TranslationUnitFileNotExitsException(d->filePath); throw TranslationUnitFileNotExitsException(d->filePath);
} }
void TranslationUnit::updateLastProjectPartChangeTimePoint() const
{
d->lastProjectPartChangeTimePoint = std::chrono::steady_clock::now();
}
void TranslationUnit::removeTranslationUnitIfProjectPartWasChanged() const
{
if (projectPartIsOutdated()) {
clang_disposeTranslationUnit(d->translationUnit);
d->translationUnit = nullptr;
}
}
bool TranslationUnit::projectPartIsOutdated() const bool TranslationUnit::projectPartIsOutdated() const
{ {
return d->projectPart.lastChangeTimePoint() >= d->lastProjectPartChangeTimePoint; return d->projectPart.lastChangeTimePoint() >= d->lastProjectPartChangeTimePoint;
@@ -410,34 +388,6 @@ bool TranslationUnit::isMainFileAndExistsOrIsOtherFile(const Utf8String &filePat
return true; return true;
} }
void TranslationUnit::createTranslationUnitIfNeeded() const
{
if (!d->translationUnit) {
d->translationUnit = CXTranslationUnit();
const auto args = commandLineArguments();
if (isVerboseModeEnabled())
args.print();
UnsavedFilesShallowArguments unsaved = unsavedFiles().shallowArguments();
d->parseErrorCode = clang_parseTranslationUnit2(index(),
NULL,
args.data(),
args.count(),
unsaved.data(),
unsaved.count(),
defaultOptions(),
&d->translationUnit);
checkParseErrorCode();
updateIncludeFilePaths();
updateLastProjectPartChangeTimePoint();
}
}
void TranslationUnit::checkParseErrorCode() const void TranslationUnit::checkParseErrorCode() const
{ {
if (!parseWasSuccessful()) { if (!parseWasSuccessful()) {
@@ -447,77 +397,48 @@ void TranslationUnit::checkParseErrorCode() const
} }
} }
void TranslationUnit::checkReparseErrorCode() const
{
if (!reparseWasSuccessful()) {
throw TranslationUnitReparseErrorException(d->filePath,
d->projectPart.projectPartId(),
d->reparseErrorCode);
}
}
void TranslationUnit::reparseTranslationUnit() const
{
UnsavedFilesShallowArguments unsaved = unsavedFiles().shallowArguments();
d->reparseErrorCode = clang_reparseTranslationUnit(
d->translationUnit,
unsaved.count(),
unsaved.data(),
clang_defaultReparseOptions(d->translationUnit));
checkReparseErrorCode();
updateIncludeFilePaths();
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);
const Utf8String normalizedFilePath = FilePath::fromNativeSeparators(includeFilePath);
translationUnit->d->dependedFilePaths.insert(normalizedFilePath);
}
UnsavedFiles TranslationUnit::unsavedFiles() const
{
return d->translationUnits.unsavedFiles();
}
void TranslationUnit::updateIncludeFilePaths() const
{
auto oldDependedFilePaths = d->dependedFilePaths;
d->dependedFilePaths.clear();
d->dependedFilePaths.insert(filePath());
clang_getInclusions(d->translationUnit, includeCallback, const_cast<TranslationUnit*>(this));
if (d->dependedFilePaths.size() == 1)
d->dependedFilePaths = oldDependedFilePaths;
d->translationUnits.addWatchedFiles(d->dependedFilePaths);
}
bool TranslationUnit::fileExists() const bool TranslationUnit::fileExists() const
{ {
return QFileInfo::exists(d->filePath.toString()); return QFileInfo::exists(d->filePath.toString());
} }
void TranslationUnit::updateSynchronously(TranslationUnitUpdater::UpdateMode updateMode) const
{
TranslationUnitUpdater updater = createUpdater();
const TranslationUnitUpdateResult updateResult = updater.update(updateMode);
incorporateUpdaterResult(updateResult);
}
TranslationUnitUpdater TranslationUnit::createUpdater() const
{
TranslationUnitUpdateInput updateInput;
updateInput.reparseNeeded = isNeedingReparse();
updateInput.parseNeeded = projectPartIsOutdated();
updateInput.filePath = filePath();
updateInput.fileArguments = fileArguments();
updateInput.unsavedFiles = unsavedFiles();
updateInput.projectId = projectPart().projectPartId();
updateInput.projectArguments = projectPart().arguments();
TranslationUnitUpdater updater(index(), d->translationUnit, updateInput);
return updater;
}
void TranslationUnit::incorporateUpdaterResult(const TranslationUnitUpdateResult &result) const
{
if (result.parseTimePointIsSet)
d->lastProjectPartChangeTimePoint = result.parseTimePoint;
if (!result.dependedOnFilePaths.isEmpty()) // TODO: Remove me
d->dependedFilePaths = result.dependedOnFilePaths;
d->translationUnits.addWatchedFiles(d->dependedFilePaths);
if (result.reparsed)
d->needsToBeReparsed = false;
}
bool TranslationUnit::isIntact() const bool TranslationUnit::isIntact() const
{ {
return !isNull() return !isNull()
@@ -528,10 +449,7 @@ bool TranslationUnit::isIntact() const
CommandLineArguments TranslationUnit::commandLineArguments() const CommandLineArguments TranslationUnit::commandLineArguments() const
{ {
return CommandLineArguments(d->filePath.constData(), return createUpdater().commandLineArguments();
d->projectPart.arguments(),
d->fileArguments,
isVerboseModeEnabled());
} }
SourceLocation TranslationUnit::sourceLocationAtWithoutReparsing(uint line, uint column) const SourceLocation TranslationUnit::sourceLocationAtWithoutReparsing(uint line, uint column) const
@@ -539,12 +457,9 @@ SourceLocation TranslationUnit::sourceLocationAtWithoutReparsing(uint line, uint
return SourceLocation(cxTranslationUnitWithoutReparsing(), filePath(), line, column); return SourceLocation(cxTranslationUnitWithoutReparsing(), filePath(), line, column);
} }
uint TranslationUnit::defaultOptions() uint TranslationUnit::defaultParseOptions()
{ {
return CXTranslationUnit_CacheCompletionResults return TranslationUnitUpdater::defaultParseOptions();
| CXTranslationUnit_PrecompiledPreamble
| CXTranslationUnit_IncludeBriefCommentsInCodeCompletion
| CXTranslationUnit_DetailedPreprocessingRecord;
} }
uint TranslationUnit::unsavedFilesCount() const uint TranslationUnit::unsavedFilesCount() const
@@ -552,6 +467,11 @@ uint TranslationUnit::unsavedFilesCount() const
return unsavedFiles().count(); return unsavedFiles().count();
} }
UnsavedFiles TranslationUnit::unsavedFiles() const
{
return d->translationUnits.unsavedFiles();
}
TranslationUnit::~TranslationUnit() = default; TranslationUnit::~TranslationUnit() = default;
TranslationUnit::TranslationUnit(const TranslationUnit &) = default; TranslationUnit::TranslationUnit(const TranslationUnit &) = default;

View File

@@ -25,6 +25,8 @@
#pragma once #pragma once
#include "clangtranslationunitupdater.h"
#include <utf8stringvector.h> #include <utf8stringvector.h>
#include <clang-c/Index.h> #include <clang-c/Index.h>
@@ -40,6 +42,7 @@ class Utf8String;
namespace ClangBackEnd { namespace ClangBackEnd {
class TranslationUnitData; class TranslationUnitData;
class TranslationUnitUpdateResult;
class CodeCompleter; class CodeCompleter;
class UnsavedFile; class UnsavedFile;
class UnsavedFiles; class UnsavedFiles;
@@ -92,13 +95,13 @@ public:
bool isIntact() const; bool isIntact() const;
CXIndex index() const; CXIndex &index() const;
CXTranslationUnit cxTranslationUnit() const; CXTranslationUnit cxTranslationUnit() const;
CXTranslationUnit cxTranslationUnitWithoutReparsing() const; CXTranslationUnit cxTranslationUnitWithoutReparsing() const;
UnsavedFile unsavedFile() const; UnsavedFile unsavedFile() const;
UnsavedFiles unsavedFiles() const; UnsavedFiles unsavedFiles() const;
uint unsavedFilesCount() const; uint unsavedFilesCount() const;
Utf8String filePath() const; Utf8String filePath() const;
@@ -141,29 +144,22 @@ public:
SkippedSourceRanges skippedSourceRanges() const; SkippedSourceRanges skippedSourceRanges() const;
static uint defaultOptions(); bool projectPartIsOutdated() const;
static uint defaultParseOptions();
private: private:
void setDirty(); void setDirty();
void checkIfNull() const; void checkIfNull() const;
void checkIfFileExists() const; void checkIfFileExists() const;
void updateLastProjectPartChangeTimePoint() const;
void removeTranslationUnitIfProjectPartWasChanged() const;
bool projectPartIsOutdated() const;
bool isMainFileAndExistsOrIsOtherFile(const Utf8String &filePath) const; bool isMainFileAndExistsOrIsOtherFile(const Utf8String &filePath) const;
void createTranslationUnitIfNeeded() const;
void checkParseErrorCode() const; void checkParseErrorCode() const;
void checkReparseErrorCode() const;
void reparseTranslationUnit() const;
void reparseTranslationUnitIfFilesAreChanged() const;
bool parseWasSuccessful() const; bool parseWasSuccessful() const;
bool reparseWasSuccessful() const; bool reparseWasSuccessful() const;
void updateIncludeFilePaths() const;
bool fileExists() const; bool fileExists() const;
static void includeCallback(CXFile included_file,
CXSourceLocation * /*inclusion_stack*/, void updateSynchronously(TranslationUnitUpdater::UpdateMode updateMode) const;
unsigned /*include_len*/, TranslationUnitUpdater createUpdater() const;
CXClientData clientData); void incorporateUpdaterResult(const TranslationUnitUpdateResult &result) const;
private: private:
mutable std::shared_ptr<TranslationUnitData> d; mutable std::shared_ptr<TranslationUnitData> d;

View File

@@ -0,0 +1,218 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangtranslationunitupdater.h"
#include "clangfilepath.h"
#include "clangstring.h"
#include "clangunsavedfilesshallowarguments.h"
#include "translationunitparseerrorexception.h"
#include "translationunitreparseerrorexception.h"
#include <QLoggingCategory>
static Q_LOGGING_CATEGORY(verboseLibLog, "qtc.clangbackend.verboselib");
static bool isVerboseModeEnabled()
{
return verboseLibLog().isDebugEnabled();
}
namespace ClangBackEnd {
TranslationUnitUpdater::TranslationUnitUpdater(CXIndex &index,
CXTranslationUnit &cxTranslationUnit,
const TranslationUnitUpdateInput &updateData)
: m_cxIndex(index)
, m_cxTranslationUnit(cxTranslationUnit)
, m_in(updateData)
{
}
TranslationUnitUpdateResult TranslationUnitUpdater::update(UpdateMode mode)
{
createIndexIfNeeded();
switch (mode) {
case UpdateMode::AsNeeded:
recreateAndParseIfNeeded();
reparseIfNeeded();
break;
case UpdateMode::ParseIfNeeded:
recreateAndParseIfNeeded();
break;
case UpdateMode::ForceReparse:
reparse();
break;
}
return m_out;
}
void TranslationUnitUpdater::recreateAndParseIfNeeded()
{
removeTranslationUnitIfProjectPartWasChanged();
createTranslationUnitIfNeeded();
}
void TranslationUnitUpdater::removeTranslationUnitIfProjectPartWasChanged()
{
if (m_in.parseNeeded) {
clang_disposeTranslationUnit(m_cxTranslationUnit);
m_cxTranslationUnit = nullptr;
}
}
void TranslationUnitUpdater::createTranslationUnitIfNeeded()
{
if (!m_cxTranslationUnit) {
m_cxTranslationUnit = CXTranslationUnit();
const auto args = commandLineArguments();
if (isVerboseModeEnabled())
args.print();
UnsavedFilesShallowArguments unsaved = m_in.unsavedFiles.shallowArguments();
m_parseErrorCode = clang_parseTranslationUnit2(m_cxIndex,
NULL,
args.data(),
args.count(),
unsaved.data(),
unsaved.count(),
defaultParseOptions(),
&m_cxTranslationUnit);
checkParseErrorCode();
updateIncludeFilePaths();
updateLastProjectPartChangeTimePoint();
}
}
void TranslationUnitUpdater::reparseIfNeeded()
{
if (m_in.reparseNeeded)
reparse();
}
void TranslationUnitUpdater::reparse()
{
UnsavedFilesShallowArguments unsaved = m_in.unsavedFiles.shallowArguments();
m_reparseErrorCode = clang_reparseTranslationUnit(
m_cxTranslationUnit,
unsaved.count(),
unsaved.data(),
clang_defaultReparseOptions(m_cxTranslationUnit));
checkReparseErrorCode();
updateIncludeFilePaths();
m_out.reparsed = true;
}
void TranslationUnitUpdater::updateIncludeFilePaths()
{
m_out.dependedOnFilePaths.clear();
m_out.dependedOnFilePaths.insert(m_in.filePath);
clang_getInclusions(m_cxTranslationUnit,
includeCallback,
const_cast<TranslationUnitUpdater *>(this));
}
void TranslationUnitUpdater::checkParseErrorCode() const
{
if (!parseWasSuccessful()) {
throw TranslationUnitParseErrorException(m_in.filePath,
m_in.projectId,
m_parseErrorCode);
}
}
void TranslationUnitUpdater::checkReparseErrorCode() const
{
if (!reparseWasSuccessful()) {
throw TranslationUnitReparseErrorException(m_in.filePath,
m_in.projectId,
m_reparseErrorCode);
}
}
uint TranslationUnitUpdater::defaultParseOptions()
{
return CXTranslationUnit_CacheCompletionResults
| CXTranslationUnit_PrecompiledPreamble
| CXTranslationUnit_IncludeBriefCommentsInCodeCompletion
| CXTranslationUnit_DetailedPreprocessingRecord;
}
void TranslationUnitUpdater::createIndexIfNeeded()
{
if (!m_cxIndex) {
const bool displayDiagnostics = isVerboseModeEnabled();
m_cxIndex = clang_createIndex(1, displayDiagnostics);
}
}
void TranslationUnitUpdater::updateLastProjectPartChangeTimePoint()
{
m_out.parseTimePointIsSet = true;
m_out.parseTimePoint = std::chrono::steady_clock::now();
}
void TranslationUnitUpdater::includeCallback(CXFile included_file,
CXSourceLocation *,
unsigned, CXClientData clientData)
{
ClangString includeFilePath(clang_getFileName(included_file));
TranslationUnitUpdater *updater = static_cast<TranslationUnitUpdater *>(clientData);
updater->m_out.dependedOnFilePaths.insert(FilePath::fromNativeSeparators(includeFilePath));
}
bool TranslationUnitUpdater::parseWasSuccessful() const
{
return m_parseErrorCode == CXError_Success;
}
bool TranslationUnitUpdater::reparseWasSuccessful() const
{
return m_reparseErrorCode == 0;
}
CommandLineArguments TranslationUnitUpdater::commandLineArguments() const
{
return CommandLineArguments(m_in.filePath.constData(),
m_in.projectArguments,
m_in.fileArguments,
isVerboseModeEnabled());
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,117 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "commandlinearguments.h"
#include "unsavedfiles.h"
#include "utf8stringvector.h"
#include <clang-c/Index.h>
#include <QSet>
#include <chrono>
namespace ClangBackEnd {
using time_point = std::chrono::steady_clock::time_point;
class TranslationUnitUpdateInput {
public:
bool reparseNeeded = false;
bool parseNeeded = false;
Utf8String filePath;
Utf8StringVector fileArguments;
UnsavedFiles unsavedFiles;
Utf8String projectId;
Utf8StringVector projectArguments;
};
class TranslationUnitUpdateResult {
public:
bool parseTimePointIsSet = false;
time_point parseTimePoint;
bool reparsed = false;
QSet<Utf8String> dependedOnFilePaths;
};
class TranslationUnitUpdater {
public:
enum class UpdateMode {
AsNeeded,
ParseIfNeeded,
ForceReparse,
};
public:
TranslationUnitUpdater(CXIndex &index,
CXTranslationUnit &cxTranslationUnit,
const TranslationUnitUpdateInput &in);
TranslationUnitUpdateResult update(UpdateMode mode);
CommandLineArguments commandLineArguments() const;
static uint defaultParseOptions();
private:
void createIndexIfNeeded();
void createTranslationUnitIfNeeded();
void removeTranslationUnitIfProjectPartWasChanged();
void reparseIfNeeded();
void recreateAndParseIfNeeded();
void reparse();
void updateLastProjectPartChangeTimePoint();
void updateIncludeFilePaths();
static void includeCallback(CXFile included_file,
CXSourceLocation *,
unsigned,
CXClientData clientData);
bool parseWasSuccessful() const;
bool reparseWasSuccessful() const;
void checkReparseErrorCode() const;
void checkParseErrorCode() const;
private:
CXIndex &m_cxIndex;
CXTranslationUnit &m_cxTranslationUnit;
CXErrorCode m_parseErrorCode = CXError_Success;
int m_reparseErrorCode = 0;
const TranslationUnitUpdateInput m_in;
TranslationUnitUpdateResult m_out;
};
} // namespace ClangBackEnd

View File

@@ -36,6 +36,7 @@ class UnsavedFiles;
class UnsavedFilesShallowArguments { class UnsavedFilesShallowArguments {
public: public:
UnsavedFilesShallowArguments() = default;
UnsavedFilesShallowArguments(const UnsavedFiles &unsavedFiles); UnsavedFilesShallowArguments(const UnsavedFiles &unsavedFiles);
uint count() const; uint count() const;

View File

@@ -99,8 +99,10 @@ uint CodeCompleter::defaultOptions() const
uint options = CXCodeComplete_IncludeMacros uint options = CXCodeComplete_IncludeMacros
| CXCodeComplete_IncludeCodePatterns; | CXCodeComplete_IncludeCodePatterns;
if (translationUnit.defaultOptions() & CXTranslationUnit_IncludeBriefCommentsInCodeCompletion) if (translationUnit.defaultParseOptions()
& CXTranslationUnit_IncludeBriefCommentsInCodeCompletion) {
options |= CXCodeComplete_IncludeBriefComments; options |= CXCodeComplete_IncludeBriefComments;
}
return options; return options;
} }

View File

@@ -125,11 +125,6 @@ TEST_F(TranslationUnit, ThrowExceptionForGettingIndexForInvalidUnit)
ASSERT_THROW(translationUnit.index(), ClangBackEnd::TranslationUnitIsNullException); ASSERT_THROW(translationUnit.index(), ClangBackEnd::TranslationUnitIsNullException);
} }
TEST_F(TranslationUnit, IndexGetterIsNonNullForValidUnit)
{
ASSERT_THAT(translationUnit.index(), NotNull());
}
TEST_F(TranslationUnit, ThrowExceptionForGettingCxTranslationUnitForInvalidUnit) TEST_F(TranslationUnit, ThrowExceptionForGettingCxTranslationUnitForInvalidUnit)
{ {
::TranslationUnit translationUnit; ::TranslationUnit translationUnit;

View File

@@ -0,0 +1,132 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include <clangtranslationunitupdater.h>
#include <clang-c/Index.h>
#include <gmock/gmock.h>
#include <gmock/gmock-matchers.h>
#include <gtest/gtest.h>
#include "gtest-qt-printing.h"
using ClangBackEnd::TranslationUnitUpdater;
using ClangBackEnd::TranslationUnitUpdateInput;
using ClangBackEnd::TranslationUnitUpdateResult;
using testing::Gt;
namespace {
class TranslationUnitUpdater : public ::testing::Test
{
protected:
void TearDown() override;
::TranslationUnitUpdater createUpdater(const TranslationUnitUpdateInput &input);
enum ReparseMode { SetReparseNeeded, DoNotSetReparseNeeded };
TranslationUnitUpdateInput createInput(ReparseMode reparseMode = DoNotSetReparseNeeded);
protected:
CXIndex cxIndex = nullptr;
CXTranslationUnit cxTranslationUnit = nullptr;
Utf8String filePath = Utf8StringLiteral(TESTDATA_DIR"/translationunits.cpp");
};
TEST_F(TranslationUnitUpdater, ParsesIfNeeded)
{
::TranslationUnitUpdater updater = createUpdater(createInput());
TranslationUnitUpdateResult result = updater.update(::TranslationUnitUpdater::UpdateMode::AsNeeded);
ASSERT_TRUE(cxTranslationUnit);
ASSERT_FALSE(result.reparsed);
}
TEST_F(TranslationUnitUpdater, ReparsesIfNeeded)
{
::TranslationUnitUpdater updater = createUpdater(createInput(SetReparseNeeded));
TranslationUnitUpdateResult result = updater.update(::TranslationUnitUpdater::UpdateMode::AsNeeded);
ASSERT_TRUE(result.reparsed);
}
TEST_F(TranslationUnitUpdater, UpdatesParseTimePoint)
{
::TranslationUnitUpdater updater = createUpdater(createInput());
const std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
TranslationUnitUpdateResult result = updater.update(::TranslationUnitUpdater::UpdateMode::AsNeeded);
ASSERT_TRUE(result.parseTimePointIsSet);
ASSERT_THAT(result.parseTimePoint, Gt(now));
}
TEST_F(TranslationUnitUpdater, NotUpdatingParseTimePointForReparseOnly)
{
::TranslationUnitUpdater updater = createUpdater(createInput());
TranslationUnitUpdateResult result = updater.update(::TranslationUnitUpdater::UpdateMode::AsNeeded);
::TranslationUnitUpdater reparseUpdater = createUpdater(createInput(SetReparseNeeded));
result = reparseUpdater.update(::TranslationUnitUpdater::UpdateMode::AsNeeded);
ASSERT_TRUE(result.reparsed);
ASSERT_FALSE(result.parseTimePointIsSet);
}
TEST_F(TranslationUnitUpdater, UpdatesDependendOnFilesOnParse)
{
::TranslationUnitUpdater updater = createUpdater(createInput());
TranslationUnitUpdateResult result = updater.update(::TranslationUnitUpdater::UpdateMode::AsNeeded);
ASSERT_FALSE(result.dependedOnFilePaths.isEmpty());
}
void TranslationUnitUpdater::TearDown()
{
clang_disposeIndex(cxIndex);
}
::TranslationUnitUpdater
TranslationUnitUpdater::createUpdater(const TranslationUnitUpdateInput &input)
{
return ::TranslationUnitUpdater(cxIndex, cxTranslationUnit, input);
}
TranslationUnitUpdateInput
TranslationUnitUpdater::createInput(ReparseMode reparseMode)
{
TranslationUnitUpdateInput updateInput;
updateInput.filePath = filePath;
updateInput.reparseNeeded = reparseMode == SetReparseNeeded;
return updateInput;
}
} // anonymous

View File

@@ -69,7 +69,8 @@ SOURCES += \
# smallstringtest.cpp \ # smallstringtest.cpp \
highlightingmarkstest.cpp \ highlightingmarkstest.cpp \
sizedarraytest.cpp \ sizedarraytest.cpp \
utf8positionfromlinecolumntest.cpp utf8positionfromlinecolumntest.cpp \
translationunitupdatertest.cpp
exists($$GOOGLEBENCHMARK_DIR) { exists($$GOOGLEBENCHMARK_DIR) {
SOURCES += \ SOURCES += \