This revision was automatically updated to reflect the committed changes.
Closed by commit rL324732: [clangd] Fix crash when CompilerInvocation 
can't be created. (authored by ibiryukov, committed by ).
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

https://reviews.llvm.org/D43122

Files:
  clang-tools-extra/trunk/clangd/ClangdUnit.cpp
  clang-tools-extra/trunk/clangd/CodeComplete.cpp
  clang-tools-extra/trunk/unittests/clangd/ClangdTests.cpp
  clang-tools-extra/trunk/unittests/clangd/Matchers.h

Index: clang-tools-extra/trunk/clangd/ClangdUnit.cpp
===================================================================
--- clang-tools-extra/trunk/clangd/ClangdUnit.cpp
+++ clang-tools-extra/trunk/clangd/ClangdUnit.cpp
@@ -405,10 +405,15 @@
                                             &IgnoreDiagnostics, false);
     CI = createInvocationFromCommandLine(ArgStrs, CommandLineDiagsEngine,
                                          Inputs.FS);
+    if (!CI) {
+      log("Could not build CompilerInvocation for file " + FileName);
+      AST = llvm::None;
+      Preamble = nullptr;
+      return llvm::None;
+    }
     // createInvocationFromCommandLine sets DisableFree.
     CI->getFrontendOpts().DisableFree = false;
   }
-  assert(CI && "Couldn't create CompilerInvocation");
 
   std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer =
       llvm::MemoryBuffer::getMemBufferCopy(Inputs.Contents, FileName);
Index: clang-tools-extra/trunk/clangd/CodeComplete.cpp
===================================================================
--- clang-tools-extra/trunk/clangd/CodeComplete.cpp
+++ clang-tools-extra/trunk/clangd/CodeComplete.cpp
@@ -650,7 +650,10 @@
       CompilerInstance::createDiagnostics(new DiagnosticOptions,
                                           &DummyDiagsConsumer, false),
       Input.VFS);
-  assert(CI && "Couldn't create CompilerInvocation");
+  if (!CI) {
+    log("Couldn't create CompilerInvocation");;
+    return false;
+  }
   CI->getFrontendOpts().DisableFree = false;
 
   std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer =
Index: clang-tools-extra/trunk/unittests/clangd/ClangdTests.cpp
===================================================================
--- clang-tools-extra/trunk/unittests/clangd/ClangdTests.cpp
+++ clang-tools-extra/trunk/unittests/clangd/ClangdTests.cpp
@@ -9,6 +9,7 @@
 
 #include "ClangdLSPServer.h"
 #include "ClangdServer.h"
+#include "Matchers.h"
 #include "TestFS.h"
 #include "clang/Config/config.h"
 #include "llvm/ADT/SmallVector.h"
@@ -453,6 +454,40 @@
   EXPECT_THAT(Server.getUsedBytesPerFile(), IsEmpty());
 }
 
+TEST_F(ClangdVFSTest, InvalidCompileCommand) {
+  MockFSProvider FS;
+  ErrorCheckingDiagConsumer DiagConsumer;
+  MockCompilationDatabase CDB;
+
+  ClangdServer Server(CDB, DiagConsumer, FS,
+                      /*AsyncThreadsCount=*/0,
+                      /*StorePreamblesInMemory=*/true);
+
+  auto FooCpp = getVirtualTestFilePath("foo.cpp");
+  // clang cannot create CompilerInvocation if we pass two files in the
+  // CompileCommand. We pass the file in ExtraFlags once and CDB adds another
+  // one in getCompileCommand().
+  CDB.ExtraClangFlags.push_back(FooCpp.str());
+
+  // Clang can't parse command args in that case, but we shouldn't crash.
+  Server.addDocument(FooCpp, "int main() {}");
+
+  EXPECT_EQ(Server.dumpAST(FooCpp), "<no-ast>");
+  EXPECT_ERROR(Server.findDefinitions(FooCpp, Position{0, 0}));
+  EXPECT_ERROR(Server.findDocumentHighlights(FooCpp, Position{0, 0}));
+  EXPECT_ERROR(Server.rename(FooCpp, Position{0, 0}, "new_name"));
+  // FIXME: codeComplete and signatureHelp should also return errors when they
+  // can't parse the file.
+  EXPECT_THAT(
+      Server.codeComplete(FooCpp, Position{0, 0}, clangd::CodeCompleteOptions())
+          .get()
+          .Value.items,
+      IsEmpty());
+  EXPECT_THAT(
+      Server.signatureHelp(FooCpp, Position{0, 0}).get().Value.signatures,
+      IsEmpty());
+}
+
 class ClangdThreadingTest : public ClangdVFSTest {};
 
 TEST_F(ClangdThreadingTest, StressTest) {
Index: clang-tools-extra/trunk/unittests/clangd/Matchers.h
===================================================================
--- clang-tools-extra/trunk/unittests/clangd/Matchers.h
+++ clang-tools-extra/trunk/unittests/clangd/Matchers.h
@@ -108,6 +108,28 @@
   return PolySubsequenceMatcher<Args...>(std::forward<Args>(M)...);
 }
 
+// EXPECT_ERROR seems like a pretty generic name, make sure it's not defined
+// already.
+#ifdef EXPECT_ERROR
+#error "Refusing to redefine EXPECT_ERROR"
+#endif
+
+// Consumes llvm::Expected<T>, checks it contains an error and marks it as
+// handled.
+#define EXPECT_ERROR(expectedValue)                                            \
+  do {                                                                         \
+    auto &&ComputedValue = (expectedValue);                                    \
+    if (ComputedValue) {                                                       \
+      ADD_FAILURE() << "expected an error from " << #expectedValue             \
+                    << " but got "                                             \
+                    << ::testing::PrintToString(*ComputedValue);               \
+      break;                                                                   \
+    }                                                                          \
+    handleAllErrors(ComputedValue.takeError(),                                 \
+                    [](const llvm::ErrorInfoBase &) {});                       \
+                                                                               \
+  } while (false)
+
 } // namespace clangd
 } // namespace clang
 #endif
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to