[clang-tools-extra] r325522 - [clangd] Do not reuse preamble if compile args changed

Ilya Biryukov via cfe-commits cfe-commits at lists.llvm.org
Mon Feb 19 10:18:49 PST 2018


Author: ibiryukov
Date: Mon Feb 19 10:18:49 2018
New Revision: 325522

URL: http://llvm.org/viewvc/llvm-project?rev=325522&view=rev
Log:
[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

Modified:
    clang-tools-extra/trunk/clangd/ClangdUnit.cpp
    clang-tools-extra/trunk/clangd/ClangdUnit.h
    clang-tools-extra/trunk/unittests/clangd/ClangdTests.cpp

Modified: clang-tools-extra/trunk/clangd/ClangdUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdUnit.cpp?rev=325522&r1=325521&r2=325522&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdUnit.cpp (original)
+++ clang-tools-extra/trunk/clangd/ClangdUnit.cpp Mon Feb 19 10:18:49 2018
@@ -34,6 +34,13 @@ using namespace clang;
 
 namespace {
 
+bool compileCommandsAreEqual(const tooling::CompileCommand &LHS,
+                             const tooling::CompileCommand &RHS) {
+  // We don't check for Output, it should not matter to clangd.
+  return LHS.Directory == RHS.Directory && LHS.Filename == RHS.Filename &&
+         llvm::makeArrayRef(LHS.CommandLine).equals(RHS.CommandLine);
+}
+
 template <class T> std::size_t getUsedBytes(const std::vector<T> &Vec) {
   return Vec.capacity() * sizeof(T);
 }
@@ -417,7 +424,7 @@ CppFile::rebuild(ParseInputs &&Inputs) {
 
   // Compute updated Preamble.
   std::shared_ptr<const PreambleData> NewPreamble =
-      rebuildPreamble(*CI, Inputs.FS, *ContentsBuffer);
+      rebuildPreamble(*CI, Inputs.CompileCommand, Inputs.FS, *ContentsBuffer);
 
   // Remove current AST to avoid wasting memory.
   AST = llvm::None;
@@ -445,6 +452,7 @@ CppFile::rebuild(ParseInputs &&Inputs) {
   }
 
   // Write the results of rebuild into class fields.
+  Command = std::move(Inputs.CompileCommand);
   Preamble = std::move(NewPreamble);
   AST = std::move(NewAST);
   return Diagnostics;
@@ -471,11 +479,12 @@ std::size_t CppFile::getUsedBytes() cons
 
 std::shared_ptr<const PreambleData>
 CppFile::rebuildPreamble(CompilerInvocation &CI,
+                         const tooling::CompileCommand &Command,
                          IntrusiveRefCntPtr<vfs::FileSystem> FS,
                          llvm::MemoryBuffer &ContentsBuffer) const {
   const auto &OldPreamble = this->Preamble;
   auto Bounds = ComputePreambleBounds(*CI.getLangOpts(), &ContentsBuffer, 0);
-  if (OldPreamble &&
+  if (OldPreamble && compileCommandsAreEqual(this->Command, Command) &&
       OldPreamble->Preamble.CanReuse(CI, &ContentsBuffer, Bounds, FS.get())) {
     log("Reusing preamble for file " + Twine(FileName));
     return OldPreamble;

Modified: clang-tools-extra/trunk/clangd/ClangdUnit.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdUnit.h?rev=325522&r1=325521&r2=325522&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdUnit.h (original)
+++ clang-tools-extra/trunk/clangd/ClangdUnit.h Mon Feb 19 10:18:49 2018
@@ -152,12 +152,15 @@ private:
   /// This method is const to ensure we don't incidentally modify any fields.
   std::shared_ptr<const PreambleData>
   rebuildPreamble(CompilerInvocation &CI,
+                  const tooling::CompileCommand &Command,
                   IntrusiveRefCntPtr<vfs::FileSystem> FS,
                   llvm::MemoryBuffer &ContentsBuffer) const;
 
   const Path FileName;
   const bool StorePreamblesInMemory;
 
+  /// The last CompileCommand used to build AST and Preamble.
+  tooling::CompileCommand Command;
   /// The last parsed AST.
   llvm::Optional<ParsedAST> AST;
   /// The last built Preamble.

Modified: clang-tools-extra/trunk/unittests/clangd/ClangdTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/ClangdTests.cpp?rev=325522&r1=325521&r2=325522&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/ClangdTests.cpp (original)
+++ clang-tools-extra/trunk/unittests/clangd/ClangdTests.cpp Mon Feb 19 10:18:49 2018
@@ -373,6 +373,46 @@ struct bar { T x; };
   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
 }
 
+TEST_F(ClangdVFSTest, ForceReparseCompileCommandDefines) {
+  MockFSProvider FS;
+  ErrorCheckingDiagConsumer DiagConsumer;
+  MockCompilationDatabase CDB;
+  ClangdServer Server(CDB, DiagConsumer, FS,
+                      /*AsyncThreadsCount=*/0,
+                      /*StorePreamblesInMemory=*/true);
+
+  // No need to sync reparses, because reparses are performed on the calling
+  // thread.
+  auto FooCpp = testPath("foo.cpp");
+  const auto SourceContents = R"cpp(
+#ifdef WITH_ERROR
+this
+#endif
+
+int main() { return 0; }
+)cpp";
+  FS.Files[FooCpp] = "";
+  FS.ExpectedFile = FooCpp;
+
+  // Parse with define, we expect to see the errors.
+  CDB.ExtraClangFlags = {"-DWITH_ERROR"};
+  Server.addDocument(FooCpp, SourceContents);
+  EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
+
+  // Parse without the define, no errors should be produced.
+  CDB.ExtraClangFlags = {};
+  // Currently, addDocument never checks if CompileCommand has changed, so we
+  // expect to see the errors.
+  Server.addDocument(FooCpp, SourceContents);
+  EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
+  // But forceReparse should reparse the file with proper flags.
+  Server.forceReparse(FooCpp);
+  EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
+  // Subsequent addDocument call should finish without errors too.
+  Server.addDocument(FooCpp, SourceContents);
+  EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
+}
+
 TEST_F(ClangdVFSTest, MemoryUsage) {
   MockFSProvider FS;
   ErrorCheckingDiagConsumer DiagConsumer;




More information about the cfe-commits mailing list