diff --git a/src/tools/clangbackend/ipcsource/translationunit.cpp b/src/tools/clangbackend/ipcsource/translationunit.cpp index f74b555f383..17871176fae 100644 --- a/src/tools/clangbackend/ipcsource/translationunit.cpp +++ b/src/tools/clangbackend/ipcsource/translationunit.cpp @@ -52,7 +52,8 @@ public: ~TranslationUnitData(); public: - time_point lastChangeTimePoint; + time_point lastProjectPartChangeTimePoint; + time_point lastUnsavedFilesChangeTimePoint; ProjectPart projectPart; Utf8String filePath; CXTranslationUnit translationUnit = nullptr; @@ -63,7 +64,8 @@ public: TranslationUnitData::TranslationUnitData(const Utf8String &filePath, const UnsavedFiles &unsavedFiles, const ProjectPart &projectPart) - : lastChangeTimePoint(std::chrono::steady_clock::now()), + : lastProjectPartChangeTimePoint(std::chrono::steady_clock::now()), + lastUnsavedFilesChangeTimePoint(lastProjectPartChangeTimePoint), projectPart(projectPart), filePath(filePath), unsavedFiles(unsavedFiles) @@ -109,10 +111,9 @@ CXIndex TranslationUnit::index() const CXTranslationUnit TranslationUnit::cxTranslationUnit() const { checkIfNull(); - - removeOutdatedTranslationUnit(); - + removeTranslationUnitIfProjectPartWasChanged(); createTranslationUnitIfNeeded(); + reparseTranslationUnitIfUnsavedFilesAreChanged(); return d->translationUnit; } @@ -131,9 +132,19 @@ const Utf8String &TranslationUnit::projectPartId() const return d->projectPart.projectPartId(); } -const time_point &TranslationUnit::lastChangeTimePoint() const +const time_point &TranslationUnit::lastProjectPartChangeTimePoint() const { - return d->lastChangeTimePoint; + return d->lastProjectPartChangeTimePoint; +} + +const time_point &TranslationUnit::lastUnsavedFilesChangeTimePoint() const +{ + return d->lastUnsavedFilesChangeTimePoint; +} + +bool TranslationUnit::isNeedingReparse() const +{ + return d->lastUnsavedFilesChangeTimePoint < d->unsavedFiles.lastChangeTimePoint(); } void TranslationUnit::checkIfNull() const @@ -148,19 +159,29 @@ void TranslationUnit::checkIfFileExists() const 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::updateLastUnsavedFilesChangeTimePoint() const { - if (d->projectPart.lastChangeTimePoint() >= d->lastChangeTimePoint) { + d->lastUnsavedFilesChangeTimePoint = 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; +} + void TranslationUnit::createTranslationUnitIfNeeded() const { if (!d->translationUnit) { @@ -180,7 +201,7 @@ void TranslationUnit::createTranslationUnitIfNeeded() const // e.g. clang_codeCompleteAt() dramatically. reparseTranslationUnit(); - updateLastChangeTimePoint(); + updateLastProjectPartChangeTimePoint(); } } @@ -198,6 +219,14 @@ void TranslationUnit::reparseTranslationUnit() const d->unsavedFiles.count(), d->unsavedFiles.cxUnsavedFiles(), clang_defaultReparseOptions(d->translationUnit)); + + updateLastUnsavedFilesChangeTimePoint(); +} + +void TranslationUnit::reparseTranslationUnitIfUnsavedFilesAreChanged() const +{ + if (isNeedingReparse()) + reparseTranslationUnit(); } int TranslationUnit::defaultOptions() diff --git a/src/tools/clangbackend/ipcsource/translationunit.h b/src/tools/clangbackend/ipcsource/translationunit.h index 75dd39e8614..5491f0acec8 100644 --- a/src/tools/clangbackend/ipcsource/translationunit.h +++ b/src/tools/clangbackend/ipcsource/translationunit.h @@ -82,16 +82,23 @@ public: const Utf8String &filePath() const; const Utf8String &projectPartId() const; - const time_point &lastChangeTimePoint() const; + const time_point &lastProjectPartChangeTimePoint() const; + const time_point &lastUnsavedFilesChangeTimePoint() const; + + bool isNeedingReparse() const; private: void checkIfNull() const; void checkIfFileExists() const; - void updateLastChangeTimePoint() const; - void removeOutdatedTranslationUnit() const; + void updateLastProjectPartChangeTimePoint() const; + void updateLastUnsavedFilesChangeTimePoint() const; + void removeTranslationUnitIfProjectPartWasChanged() const; + bool projectPartIsOutdated() const; void createTranslationUnitIfNeeded() const; void checkTranslationUnitErrorCode(CXErrorCode errorCode) const; void reparseTranslationUnit() const; + void reparseTranslationUnitIfUnsavedFilesAreChanged() const; + void printIncludes() const; static int defaultOptions(); private: diff --git a/tests/unit/unittest/translationunittest.cpp b/tests/unit/unittest/translationunittest.cpp index 25235940bf0..29ae9cd4686 100644 --- a/tests/unit/unittest/translationunittest.cpp +++ b/tests/unit/unittest/translationunittest.cpp @@ -132,15 +132,75 @@ TEST(TranslationUnit, ResetedTranslationUnitIsNull) ASSERT_TRUE(translationUnit.isNull()); } -TEST(TranslationUnit, TimeStampIsUpdatedAsNewCxTranslationUnitIsGenerated) +TEST(TranslationUnit, TimeStampForProjectPartChangeIsUpdatedAsNewCxTranslationUnitIsGenerated) { TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), UnsavedFiles(), ProjectPart(Utf8StringLiteral("/path/to/projectfile"))); - auto lastChangeTimePoint = translationUnit.lastChangeTimePoint(); + auto lastChangeTimePoint = translationUnit.lastProjectPartChangeTimePoint(); std::this_thread::sleep_for(std::chrono::steady_clock::duration(1)); translationUnit.cxTranslationUnit(); - ASSERT_THAT(translationUnit.lastChangeTimePoint(), Gt(lastChangeTimePoint)); + ASSERT_THAT(translationUnit.lastProjectPartChangeTimePoint(), Gt(lastChangeTimePoint)); +} + +TEST(TranslationUnit, TimeStampForProjectPartChangeIsUpdatedAsProjectPartIsCleared) +{ + ProjectPart projectPart(Utf8StringLiteral("/path/to/projectfile")); + TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), UnsavedFiles(), projectPart); + translationUnit.cxTranslationUnit(); + auto lastChangeTimePoint = translationUnit.lastProjectPartChangeTimePoint(); + std::this_thread::sleep_for(std::chrono::steady_clock::duration(1)); + + projectPart.clear(); + translationUnit.cxTranslationUnit(); + + ASSERT_THAT(translationUnit.lastProjectPartChangeTimePoint(), Gt(lastChangeTimePoint)); +} + +TEST(TranslationUnit, ReparseIsNeededAfterUnsavedFilesAreChanged) +{ + UnsavedFiles unsavedFiles; + TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), + unsavedFiles, + ProjectPart(Utf8StringLiteral("/path/to/projectfile"))); + translationUnit.cxTranslationUnit(); + unsavedFiles.clear(); + translationUnit.cxTranslationUnit(); + + unsavedFiles.clear(); + + ASSERT_TRUE(translationUnit.isNeedingReparse()); +} + +TEST(TranslationUnit, NeedsNoReparseAfterUnsavedFilesAreNotChanged) +{ + UnsavedFiles unsavedFiles; + TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), + unsavedFiles, + ProjectPart(Utf8StringLiteral("/path/to/projectfile"))); + translationUnit.cxTranslationUnit(); + unsavedFiles.clear(); + translationUnit.cxTranslationUnit(); + + ASSERT_FALSE(translationUnit.isNeedingReparse()); +} + +TEST(TranslationUnit, TimeStampForUnsavedFilesChange) +{ + UnsavedFiles unsavedFiles; + TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), + unsavedFiles, + ProjectPart(Utf8StringLiteral("/path/to/projectfile"))); + translationUnit.cxTranslationUnit(); + unsavedFiles.clear(); + translationUnit.cxTranslationUnit(); + auto lastChangeTimePoint = translationUnit.lastUnsavedFilesChangeTimePoint(); + std::this_thread::sleep_for(std::chrono::steady_clock::duration(1)); + + unsavedFiles.clear(); + translationUnit.cxTranslationUnit(); + + ASSERT_THAT(translationUnit.lastUnsavedFilesChangeTimePoint(), Gt(lastChangeTimePoint)); }