ilya-biryukov created this revision.
ilya-biryukov added reviewers: hokein, ioeric, sammccall.
Herald added subscribers: jkorous-apple, klimek.
This can happen if the CompileCommand provided by compilation database
is malformed.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D43122

Files:
  clangd/ClangdUnit.cpp
  clangd/CodeComplete.cpp
  unittests/clangd/ClangdTests.cpp

Index: unittests/clangd/ClangdTests.cpp
===================================================================
--- unittests/clangd/ClangdTests.cpp
+++ unittests/clangd/ClangdTests.cpp
@@ -38,6 +38,25 @@
 
 namespace {
 
+// 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
+
+// Checks there is an error and marks it as handled.
+#define EXPECT_ERROR(expectedValue)                                            \
+  do {                                                                         \
+    auto &&ComputedValue = (expectedValue);                                    \
+    if (ComputedValue) {                                                       \
+      ADD_FAILURE() << "expected an error";                                    \
+      break;                                                                   \
+    }                                                                          \
+    handleAllErrors(ComputedValue.takeError(),                                 \
+                    [](const llvm::ErrorInfoBase &) {});                       \
+                                                                               \
+  } while (false)
+
 // Don't wait for async ops in clangd test more than that to avoid blocking
 // indefinitely in case of bugs.
 static const std::chrono::seconds DefaultFutureTimeout =
@@ -453,6 +472,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: clangd/CodeComplete.cpp
===================================================================
--- clangd/CodeComplete.cpp
+++ 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: clangd/ClangdUnit.cpp
===================================================================
--- clangd/ClangdUnit.cpp
+++ clangd/ClangdUnit.cpp
@@ -405,6 +405,12 @@
                                             &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;
   }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to