Skip to content

Commit 7fac6e9

Browse files
committedFeb 19, 2018
[clangd] Do not reuse preamble if compile args changed
Reviewers: hokein, ioeric, sammccall, simark Reviewed By: simark Subscribers: klimek, jkorous-apple, cfe-commits, simark Differential Revision: https://reviews.llvm.org/D43454 llvm-svn: 325522
1 parent 70eb508 commit 7fac6e9

File tree

3 files changed

+54
-2
lines changed

3 files changed

+54
-2
lines changed
 

‎clang-tools-extra/clangd/ClangdUnit.cpp

+11-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ using namespace clang;
3434

3535
namespace {
3636

37+
bool compileCommandsAreEqual(const tooling::CompileCommand &LHS,
38+
const tooling::CompileCommand &RHS) {
39+
// We don't check for Output, it should not matter to clangd.
40+
return LHS.Directory == RHS.Directory && LHS.Filename == RHS.Filename &&
41+
llvm::makeArrayRef(LHS.CommandLine).equals(RHS.CommandLine);
42+
}
43+
3744
template <class T> std::size_t getUsedBytes(const std::vector<T> &Vec) {
3845
return Vec.capacity() * sizeof(T);
3946
}
@@ -417,7 +424,7 @@ CppFile::rebuild(ParseInputs &&Inputs) {
417424

418425
// Compute updated Preamble.
419426
std::shared_ptr<const PreambleData> NewPreamble =
420-
rebuildPreamble(*CI, Inputs.FS, *ContentsBuffer);
427+
rebuildPreamble(*CI, Inputs.CompileCommand, Inputs.FS, *ContentsBuffer);
421428

422429
// Remove current AST to avoid wasting memory.
423430
AST = llvm::None;
@@ -445,6 +452,7 @@ CppFile::rebuild(ParseInputs &&Inputs) {
445452
}
446453

447454
// Write the results of rebuild into class fields.
455+
Command = std::move(Inputs.CompileCommand);
448456
Preamble = std::move(NewPreamble);
449457
AST = std::move(NewAST);
450458
return Diagnostics;
@@ -471,11 +479,12 @@ std::size_t CppFile::getUsedBytes() const {
471479

472480
std::shared_ptr<const PreambleData>
473481
CppFile::rebuildPreamble(CompilerInvocation &CI,
482+
const tooling::CompileCommand &Command,
474483
IntrusiveRefCntPtr<vfs::FileSystem> FS,
475484
llvm::MemoryBuffer &ContentsBuffer) const {
476485
const auto &OldPreamble = this->Preamble;
477486
auto Bounds = ComputePreambleBounds(*CI.getLangOpts(), &ContentsBuffer, 0);
478-
if (OldPreamble &&
487+
if (OldPreamble && compileCommandsAreEqual(this->Command, Command) &&
479488
OldPreamble->Preamble.CanReuse(CI, &ContentsBuffer, Bounds, FS.get())) {
480489
log("Reusing preamble for file " + Twine(FileName));
481490
return OldPreamble;

‎clang-tools-extra/clangd/ClangdUnit.h

+3
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,15 @@ class CppFile {
152152
/// This method is const to ensure we don't incidentally modify any fields.
153153
std::shared_ptr<const PreambleData>
154154
rebuildPreamble(CompilerInvocation &CI,
155+
const tooling::CompileCommand &Command,
155156
IntrusiveRefCntPtr<vfs::FileSystem> FS,
156157
llvm::MemoryBuffer &ContentsBuffer) const;
157158

158159
const Path FileName;
159160
const bool StorePreamblesInMemory;
160161

162+
/// The last CompileCommand used to build AST and Preamble.
163+
tooling::CompileCommand Command;
161164
/// The last parsed AST.
162165
llvm::Optional<ParsedAST> AST;
163166
/// The last built Preamble.

‎clang-tools-extra/unittests/clangd/ClangdTests.cpp

+40
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,46 @@ struct bar { T x; };
373373
EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
374374
}
375375

376+
TEST_F(ClangdVFSTest, ForceReparseCompileCommandDefines) {
377+
MockFSProvider FS;
378+
ErrorCheckingDiagConsumer DiagConsumer;
379+
MockCompilationDatabase CDB;
380+
ClangdServer Server(CDB, DiagConsumer, FS,
381+
/*AsyncThreadsCount=*/0,
382+
/*StorePreamblesInMemory=*/true);
383+
384+
// No need to sync reparses, because reparses are performed on the calling
385+
// thread.
386+
auto FooCpp = testPath("foo.cpp");
387+
const auto SourceContents = R"cpp(
388+
#ifdef WITH_ERROR
389+
this
390+
#endif
391+
392+
int main() { return 0; }
393+
)cpp";
394+
FS.Files[FooCpp] = "";
395+
FS.ExpectedFile = FooCpp;
396+
397+
// Parse with define, we expect to see the errors.
398+
CDB.ExtraClangFlags = {"-DWITH_ERROR"};
399+
Server.addDocument(FooCpp, SourceContents);
400+
EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
401+
402+
// Parse without the define, no errors should be produced.
403+
CDB.ExtraClangFlags = {};
404+
// Currently, addDocument never checks if CompileCommand has changed, so we
405+
// expect to see the errors.
406+
Server.addDocument(FooCpp, SourceContents);
407+
EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
408+
// But forceReparse should reparse the file with proper flags.
409+
Server.forceReparse(FooCpp);
410+
EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
411+
// Subsequent addDocument call should finish without errors too.
412+
Server.addDocument(FooCpp, SourceContents);
413+
EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
414+
}
415+
376416
TEST_F(ClangdVFSTest, MemoryUsage) {
377417
MockFSProvider FS;
378418
ErrorCheckingDiagConsumer DiagConsumer;

0 commit comments

Comments
 (0)
Please sign in to comment.