diff --git a/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri b/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri index 244bd43b686..f528d1c58de 100644 --- a/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri +++ b/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri @@ -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 \ diff --git a/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp b/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp index de16732dee5..2d7784b63b4 100644 --- a/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp +++ b/src/tools/clangbackend/ipcsource/clangtranslationunit.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 -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 TranslationUnit::mainFileDiagnostics( const QSet &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(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(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; diff --git a/src/tools/clangbackend/ipcsource/clangtranslationunit.h b/src/tools/clangbackend/ipcsource/clangtranslationunit.h index f0f7be8fd0d..6d353852bc7 100644 --- a/src/tools/clangbackend/ipcsource/clangtranslationunit.h +++ b/src/tools/clangbackend/ipcsource/clangtranslationunit.h @@ -25,6 +25,8 @@ #pragma once +#include "clangtranslationunitupdater.h" + #include #include @@ -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 d; diff --git a/src/tools/clangbackend/ipcsource/clangtranslationunitupdater.cpp b/src/tools/clangbackend/ipcsource/clangtranslationunitupdater.cpp new file mode 100644 index 00000000000..9a09170c43c --- /dev/null +++ b/src/tools/clangbackend/ipcsource/clangtranslationunitupdater.cpp @@ -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 + +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(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(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 diff --git a/src/tools/clangbackend/ipcsource/clangtranslationunitupdater.h b/src/tools/clangbackend/ipcsource/clangtranslationunitupdater.h new file mode 100644 index 00000000000..a7a9d88f23f --- /dev/null +++ b/src/tools/clangbackend/ipcsource/clangtranslationunitupdater.h @@ -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 + +#include + +#include + +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 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 diff --git a/src/tools/clangbackend/ipcsource/clangunsavedfilesshallowarguments.h b/src/tools/clangbackend/ipcsource/clangunsavedfilesshallowarguments.h index 6fa670a4aec..20c8981ef26 100644 --- a/src/tools/clangbackend/ipcsource/clangunsavedfilesshallowarguments.h +++ b/src/tools/clangbackend/ipcsource/clangunsavedfilesshallowarguments.h @@ -36,6 +36,7 @@ class UnsavedFiles; class UnsavedFilesShallowArguments { public: + UnsavedFilesShallowArguments() = default; UnsavedFilesShallowArguments(const UnsavedFiles &unsavedFiles); uint count() const; diff --git a/src/tools/clangbackend/ipcsource/codecompleter.cpp b/src/tools/clangbackend/ipcsource/codecompleter.cpp index 29da5af22bb..9cab1493c61 100644 --- a/src/tools/clangbackend/ipcsource/codecompleter.cpp +++ b/src/tools/clangbackend/ipcsource/codecompleter.cpp @@ -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; } diff --git a/tests/unit/unittest/translationunittest.cpp b/tests/unit/unittest/translationunittest.cpp index 2d4486021ac..714ed595753 100644 --- a/tests/unit/unittest/translationunittest.cpp +++ b/tests/unit/unittest/translationunittest.cpp @@ -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; diff --git a/tests/unit/unittest/translationunitupdatertest.cpp b/tests/unit/unittest/translationunitupdatertest.cpp new file mode 100644 index 00000000000..0a78bdd3f38 --- /dev/null +++ b/tests/unit/unittest/translationunitupdatertest.cpp @@ -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 + +#include + +#include +#include +#include +#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 diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 7d9684fdea8..9a9752369c7 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -69,7 +69,8 @@ SOURCES += \ # smallstringtest.cpp \ highlightingmarkstest.cpp \ sizedarraytest.cpp \ - utf8positionfromlinecolumntest.cpp + utf8positionfromlinecolumntest.cpp \ + translationunitupdatertest.cpp exists($$GOOGLEBENCHMARK_DIR) { SOURCES += \