Clang: Reparse the translation unit for unsaved file changes

Change-Id: I49711ce040a995f193d36961e010decc27c34c4c
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@theqtcompany.com>
This commit is contained in:
Marco Bubke
2015-07-16 19:57:52 +02:00
committed by Nikolai Kosjar
parent efada54950
commit 2443f18b85
3 changed files with 114 additions and 18 deletions

View File

@@ -52,7 +52,8 @@ public:
~TranslationUnitData(); ~TranslationUnitData();
public: public:
time_point lastChangeTimePoint; time_point lastProjectPartChangeTimePoint;
time_point lastUnsavedFilesChangeTimePoint;
ProjectPart projectPart; ProjectPart projectPart;
Utf8String filePath; Utf8String filePath;
CXTranslationUnit translationUnit = nullptr; CXTranslationUnit translationUnit = nullptr;
@@ -63,7 +64,8 @@ public:
TranslationUnitData::TranslationUnitData(const Utf8String &filePath, TranslationUnitData::TranslationUnitData(const Utf8String &filePath,
const UnsavedFiles &unsavedFiles, const UnsavedFiles &unsavedFiles,
const ProjectPart &projectPart) const ProjectPart &projectPart)
: lastChangeTimePoint(std::chrono::steady_clock::now()), : lastProjectPartChangeTimePoint(std::chrono::steady_clock::now()),
lastUnsavedFilesChangeTimePoint(lastProjectPartChangeTimePoint),
projectPart(projectPart), projectPart(projectPart),
filePath(filePath), filePath(filePath),
unsavedFiles(unsavedFiles) unsavedFiles(unsavedFiles)
@@ -109,10 +111,9 @@ CXIndex TranslationUnit::index() const
CXTranslationUnit TranslationUnit::cxTranslationUnit() const CXTranslationUnit TranslationUnit::cxTranslationUnit() const
{ {
checkIfNull(); checkIfNull();
removeTranslationUnitIfProjectPartWasChanged();
removeOutdatedTranslationUnit();
createTranslationUnitIfNeeded(); createTranslationUnitIfNeeded();
reparseTranslationUnitIfUnsavedFilesAreChanged();
return d->translationUnit; return d->translationUnit;
} }
@@ -131,9 +132,19 @@ const Utf8String &TranslationUnit::projectPartId() const
return d->projectPart.projectPartId(); 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 void TranslationUnit::checkIfNull() const
@@ -148,19 +159,29 @@ void TranslationUnit::checkIfFileExists() const
throw TranslationUnitFileNotExitsException(d->filePath); throw TranslationUnitFileNotExitsException(d->filePath);
} }
void TranslationUnit::updateLastChangeTimePoint() const void TranslationUnit::updateLastProjectPartChangeTimePoint() const
{ {
d->lastChangeTimePoint = std::chrono::steady_clock::now(); d->lastProjectPartChangeTimePoint = std::chrono::steady_clock::now();
} }
void TranslationUnit::removeOutdatedTranslationUnit() const void TranslationUnit::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); clang_disposeTranslationUnit(d->translationUnit);
d->translationUnit = nullptr; d->translationUnit = nullptr;
} }
} }
bool TranslationUnit::projectPartIsOutdated() const
{
return d->projectPart.lastChangeTimePoint() >= d->lastProjectPartChangeTimePoint;
}
void TranslationUnit::createTranslationUnitIfNeeded() const void TranslationUnit::createTranslationUnitIfNeeded() const
{ {
if (!d->translationUnit) { if (!d->translationUnit) {
@@ -180,7 +201,7 @@ void TranslationUnit::createTranslationUnitIfNeeded() const
// e.g. clang_codeCompleteAt() dramatically. // e.g. clang_codeCompleteAt() dramatically.
reparseTranslationUnit(); reparseTranslationUnit();
updateLastChangeTimePoint(); updateLastProjectPartChangeTimePoint();
} }
} }
@@ -198,6 +219,14 @@ void TranslationUnit::reparseTranslationUnit() const
d->unsavedFiles.count(), d->unsavedFiles.count(),
d->unsavedFiles.cxUnsavedFiles(), d->unsavedFiles.cxUnsavedFiles(),
clang_defaultReparseOptions(d->translationUnit)); clang_defaultReparseOptions(d->translationUnit));
updateLastUnsavedFilesChangeTimePoint();
}
void TranslationUnit::reparseTranslationUnitIfUnsavedFilesAreChanged() const
{
if (isNeedingReparse())
reparseTranslationUnit();
} }
int TranslationUnit::defaultOptions() int TranslationUnit::defaultOptions()

View File

@@ -82,16 +82,23 @@ public:
const Utf8String &filePath() const; const Utf8String &filePath() const;
const Utf8String &projectPartId() const; const Utf8String &projectPartId() const;
const time_point &lastChangeTimePoint() const; const time_point &lastProjectPartChangeTimePoint() const;
const time_point &lastUnsavedFilesChangeTimePoint() const;
bool isNeedingReparse() const;
private: private:
void checkIfNull() const; void checkIfNull() const;
void checkIfFileExists() const; void checkIfFileExists() const;
void updateLastChangeTimePoint() const; void updateLastProjectPartChangeTimePoint() const;
void removeOutdatedTranslationUnit() const; void updateLastUnsavedFilesChangeTimePoint() const;
void removeTranslationUnitIfProjectPartWasChanged() const;
bool projectPartIsOutdated() const;
void createTranslationUnitIfNeeded() const; void createTranslationUnitIfNeeded() const;
void checkTranslationUnitErrorCode(CXErrorCode errorCode) const; void checkTranslationUnitErrorCode(CXErrorCode errorCode) const;
void reparseTranslationUnit() const; void reparseTranslationUnit() const;
void reparseTranslationUnitIfUnsavedFilesAreChanged() const;
void printIncludes() const;
static int defaultOptions(); static int defaultOptions();
private: private:

View File

@@ -132,15 +132,75 @@ TEST(TranslationUnit, ResetedTranslationUnitIsNull)
ASSERT_TRUE(translationUnit.isNull()); 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"))); 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)); std::this_thread::sleep_for(std::chrono::steady_clock::duration(1));
translationUnit.cxTranslationUnit(); translationUnit.cxTranslationUnit();
ASSERT_THAT(translationUnit.lastChangeTimePoint(), Gt(lastChangeTimePoint)); ASSERT_THAT(translationUnit.lastProjectPartChangeTimePoint(), Gt(lastChangeTimePoint));
}
TEST(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));
} }