forked from qt-creator/qt-creator
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:
@@ -30,6 +30,7 @@ HEADERS += $$PWD/clangcodemodelserver.h \
|
||||
$$PWD/cursor.h \
|
||||
$$PWD/skippedsourceranges.h \
|
||||
$$PWD/clangtranslationunit.h \
|
||||
$$PWD/clangtranslationunitupdater.h \
|
||||
$$PWD/clangtype.h \
|
||||
$$PWD/highlightingmark.h \
|
||||
$$PWD/highlightingmarks.h \
|
||||
@@ -67,6 +68,7 @@ SOURCES += $$PWD/clangcodemodelserver.cpp \
|
||||
$$PWD/cursor.cpp \
|
||||
$$PWD/skippedsourceranges.cpp \
|
||||
$$PWD/clangtranslationunit.cpp \
|
||||
$$PWD/clangtranslationunitupdater.cpp \
|
||||
$$PWD/clangtype.cpp \
|
||||
$$PWD/highlightingmark.cpp \
|
||||
$$PWD/highlightingmarks.cpp \
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "translationunitisnullexception.h"
|
||||
#include "translationunitparseerrorexception.h"
|
||||
#include "translationunitreparseerrorexception.h"
|
||||
#include "clangtranslationunitupdater.h"
|
||||
#include "translationunits.h"
|
||||
#include "unsavedfiles.h"
|
||||
#include "unsavedfile.h"
|
||||
@@ -54,13 +55,6 @@
|
||||
|
||||
#include <ostream>
|
||||
|
||||
static Q_LOGGING_CATEGORY(verboseLibLog, "qtc.clangbackend.verboselib");
|
||||
|
||||
static bool isVerboseModeEnabled()
|
||||
{
|
||||
return verboseLibLog().isDebugEnabled();
|
||||
}
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
class TranslationUnitData
|
||||
@@ -158,7 +152,7 @@ void TranslationUnit::reparse() const
|
||||
{
|
||||
cxTranslationUnit();
|
||||
|
||||
reparseTranslationUnit();
|
||||
updateSynchronously(TranslationUnitUpdater::UpdateMode::ForceReparse);
|
||||
}
|
||||
|
||||
bool TranslationUnit::parseWasSuccessful() const
|
||||
@@ -171,22 +165,19 @@ bool TranslationUnit::reparseWasSuccessful() const
|
||||
return d->reparseErrorCode == 0;
|
||||
}
|
||||
|
||||
CXIndex TranslationUnit::index() const
|
||||
CXIndex &TranslationUnit::index() const
|
||||
{
|
||||
checkIfNull();
|
||||
|
||||
if (!d->index) {
|
||||
const bool displayDiagnostics = isVerboseModeEnabled();
|
||||
d->index = clang_createIndex(1, displayDiagnostics);
|
||||
}
|
||||
|
||||
return d->index;
|
||||
}
|
||||
|
||||
CXTranslationUnit TranslationUnit::cxTranslationUnit() const
|
||||
{
|
||||
cxTranslationUnitWithoutReparsing();
|
||||
reparseTranslationUnitIfFilesAreChanged();
|
||||
checkIfNull();
|
||||
checkIfFileExists();
|
||||
|
||||
updateSynchronously(TranslationUnitUpdater::UpdateMode::AsNeeded);
|
||||
|
||||
return d->translationUnit;
|
||||
}
|
||||
@@ -195,8 +186,8 @@ CXTranslationUnit TranslationUnit::cxTranslationUnitWithoutReparsing() const
|
||||
{
|
||||
checkIfNull();
|
||||
checkIfFileExists();
|
||||
removeTranslationUnitIfProjectPartWasChanged();
|
||||
createTranslationUnitIfNeeded();
|
||||
|
||||
updateSynchronously(TranslationUnitUpdater::UpdateMode::ParseIfNeeded);
|
||||
|
||||
return d->translationUnit;
|
||||
}
|
||||
@@ -294,7 +285,7 @@ QVector<ClangBackEnd::DiagnosticContainer> TranslationUnit::mainFileDiagnostics(
|
||||
|
||||
const QSet<Utf8String> &TranslationUnit::dependedFilePaths() const
|
||||
{
|
||||
createTranslationUnitIfNeeded();
|
||||
cxTranslationUnit();
|
||||
|
||||
return d->dependedFilePaths;
|
||||
}
|
||||
@@ -377,19 +368,6 @@ void TranslationUnit::checkIfFileExists() const
|
||||
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
|
||||
{
|
||||
return d->projectPart.lastChangeTimePoint() >= d->lastProjectPartChangeTimePoint;
|
||||
@@ -410,34 +388,6 @@ bool TranslationUnit::isMainFileAndExistsOrIsOtherFile(const Utf8String &filePat
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
return !isNull()
|
||||
@@ -528,10 +449,7 @@ bool TranslationUnit::isIntact() const
|
||||
|
||||
CommandLineArguments TranslationUnit::commandLineArguments() const
|
||||
{
|
||||
return CommandLineArguments(d->filePath.constData(),
|
||||
d->projectPart.arguments(),
|
||||
d->fileArguments,
|
||||
isVerboseModeEnabled());
|
||||
return createUpdater().commandLineArguments();
|
||||
}
|
||||
|
||||
SourceLocation TranslationUnit::sourceLocationAtWithoutReparsing(uint line, uint column) const
|
||||
@@ -539,12 +457,9 @@ SourceLocation TranslationUnit::sourceLocationAtWithoutReparsing(uint line, uint
|
||||
return SourceLocation(cxTranslationUnitWithoutReparsing(), filePath(), line, column);
|
||||
}
|
||||
|
||||
uint TranslationUnit::defaultOptions()
|
||||
uint TranslationUnit::defaultParseOptions()
|
||||
{
|
||||
return CXTranslationUnit_CacheCompletionResults
|
||||
| CXTranslationUnit_PrecompiledPreamble
|
||||
| CXTranslationUnit_IncludeBriefCommentsInCodeCompletion
|
||||
| CXTranslationUnit_DetailedPreprocessingRecord;
|
||||
return TranslationUnitUpdater::defaultParseOptions();
|
||||
}
|
||||
|
||||
uint TranslationUnit::unsavedFilesCount() const
|
||||
@@ -552,6 +467,11 @@ uint TranslationUnit::unsavedFilesCount() const
|
||||
return unsavedFiles().count();
|
||||
}
|
||||
|
||||
UnsavedFiles TranslationUnit::unsavedFiles() const
|
||||
{
|
||||
return d->translationUnits.unsavedFiles();
|
||||
}
|
||||
|
||||
TranslationUnit::~TranslationUnit() = default;
|
||||
|
||||
TranslationUnit::TranslationUnit(const TranslationUnit &) = default;
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "clangtranslationunitupdater.h"
|
||||
|
||||
#include <utf8stringvector.h>
|
||||
|
||||
#include <clang-c/Index.h>
|
||||
@@ -40,6 +42,7 @@ class Utf8String;
|
||||
namespace ClangBackEnd {
|
||||
|
||||
class TranslationUnitData;
|
||||
class TranslationUnitUpdateResult;
|
||||
class CodeCompleter;
|
||||
class UnsavedFile;
|
||||
class UnsavedFiles;
|
||||
@@ -92,13 +95,13 @@ public:
|
||||
|
||||
bool isIntact() const;
|
||||
|
||||
CXIndex index() const;
|
||||
CXIndex &index() const;
|
||||
|
||||
CXTranslationUnit cxTranslationUnit() const;
|
||||
CXTranslationUnit cxTranslationUnitWithoutReparsing() const;
|
||||
|
||||
UnsavedFile unsavedFile() const;
|
||||
UnsavedFiles unsavedFiles() const;
|
||||
|
||||
uint unsavedFilesCount() const;
|
||||
|
||||
Utf8String filePath() const;
|
||||
@@ -141,29 +144,22 @@ public:
|
||||
|
||||
SkippedSourceRanges skippedSourceRanges() const;
|
||||
|
||||
static uint defaultOptions();
|
||||
bool projectPartIsOutdated() const;
|
||||
static uint defaultParseOptions();
|
||||
|
||||
private:
|
||||
void setDirty();
|
||||
void checkIfNull() const;
|
||||
void checkIfFileExists() const;
|
||||
void updateLastProjectPartChangeTimePoint() const;
|
||||
void removeTranslationUnitIfProjectPartWasChanged() const;
|
||||
bool projectPartIsOutdated() const;
|
||||
bool isMainFileAndExistsOrIsOtherFile(const Utf8String &filePath) const;
|
||||
void createTranslationUnitIfNeeded() const;
|
||||
void checkParseErrorCode() const;
|
||||
void checkReparseErrorCode() const;
|
||||
void reparseTranslationUnit() const;
|
||||
void reparseTranslationUnitIfFilesAreChanged() const;
|
||||
bool parseWasSuccessful() const;
|
||||
bool reparseWasSuccessful() const;
|
||||
void updateIncludeFilePaths() const;
|
||||
bool fileExists() const;
|
||||
static void includeCallback(CXFile included_file,
|
||||
CXSourceLocation * /*inclusion_stack*/,
|
||||
unsigned /*include_len*/,
|
||||
CXClientData clientData);
|
||||
|
||||
void updateSynchronously(TranslationUnitUpdater::UpdateMode updateMode) const;
|
||||
TranslationUnitUpdater createUpdater() const;
|
||||
void incorporateUpdaterResult(const TranslationUnitUpdateResult &result) const;
|
||||
|
||||
private:
|
||||
mutable std::shared_ptr<TranslationUnitData> d;
|
||||
|
||||
218
src/tools/clangbackend/ipcsource/clangtranslationunitupdater.cpp
Normal file
218
src/tools/clangbackend/ipcsource/clangtranslationunitupdater.cpp
Normal 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
|
||||
117
src/tools/clangbackend/ipcsource/clangtranslationunitupdater.h
Normal file
117
src/tools/clangbackend/ipcsource/clangtranslationunitupdater.h
Normal 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
|
||||
@@ -36,6 +36,7 @@ class UnsavedFiles;
|
||||
|
||||
class UnsavedFilesShallowArguments {
|
||||
public:
|
||||
UnsavedFilesShallowArguments() = default;
|
||||
UnsavedFilesShallowArguments(const UnsavedFiles &unsavedFiles);
|
||||
|
||||
uint count() const;
|
||||
|
||||
@@ -99,8 +99,10 @@ uint CodeCompleter::defaultOptions() const
|
||||
uint options = CXCodeComplete_IncludeMacros
|
||||
| CXCodeComplete_IncludeCodePatterns;
|
||||
|
||||
if (translationUnit.defaultOptions() & CXTranslationUnit_IncludeBriefCommentsInCodeCompletion)
|
||||
if (translationUnit.defaultParseOptions()
|
||||
& CXTranslationUnit_IncludeBriefCommentsInCodeCompletion) {
|
||||
options |= CXCodeComplete_IncludeBriefComments;
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
@@ -125,11 +125,6 @@ TEST_F(TranslationUnit, ThrowExceptionForGettingIndexForInvalidUnit)
|
||||
ASSERT_THROW(translationUnit.index(), ClangBackEnd::TranslationUnitIsNullException);
|
||||
}
|
||||
|
||||
TEST_F(TranslationUnit, IndexGetterIsNonNullForValidUnit)
|
||||
{
|
||||
ASSERT_THAT(translationUnit.index(), NotNull());
|
||||
}
|
||||
|
||||
TEST_F(TranslationUnit, ThrowExceptionForGettingCxTranslationUnitForInvalidUnit)
|
||||
{
|
||||
::TranslationUnit translationUnit;
|
||||
|
||||
132
tests/unit/unittest/translationunitupdatertest.cpp
Normal file
132
tests/unit/unittest/translationunitupdatertest.cpp
Normal 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
|
||||
@@ -69,7 +69,8 @@ SOURCES += \
|
||||
# smallstringtest.cpp \
|
||||
highlightingmarkstest.cpp \
|
||||
sizedarraytest.cpp \
|
||||
utf8positionfromlinecolumntest.cpp
|
||||
utf8positionfromlinecolumntest.cpp \
|
||||
translationunitupdatertest.cpp
|
||||
|
||||
exists($$GOOGLEBENCHMARK_DIR) {
|
||||
SOURCES += \
|
||||
|
||||
Reference in New Issue
Block a user