[clang-tools-extra] r324732 - [clangd] Fix crash when CompilerInvocation can't be created.
Ilya Biryukov via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 9 05:51:58 PST 2018
Author: ibiryukov
Date: Fri Feb 9 05:51:57 2018
New Revision: 324732
URL: http://llvm.org/viewvc/llvm-project?rev=324732&view=rev
Log:
[clangd] Fix crash when CompilerInvocation can't be created.
Summary:
This can happen if the CompileCommand provided by compilation database
is malformed.
Reviewers: hokein, ioeric, sammccall
Reviewed By: sammccall
Subscribers: klimek, jkorous-apple, cfe-commits
Differential Revision: https://reviews.llvm.org/D43122
Modified:
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
Modified: clang-tools-extra/trunk/clangd/ClangdUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdUnit.cpp?rev=324732&r1=324731&r2=324732&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdUnit.cpp (original)
+++ clang-tools-extra/trunk/clangd/ClangdUnit.cpp Fri Feb 9 05:51:57 2018
@@ -405,10 +405,15 @@ CppFile::rebuild(ParseInputs &&Inputs) {
&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);
Modified: clang-tools-extra/trunk/clangd/CodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/CodeComplete.cpp?rev=324732&r1=324731&r2=324732&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/CodeComplete.cpp (original)
+++ clang-tools-extra/trunk/clangd/CodeComplete.cpp Fri Feb 9 05:51:57 2018
@@ -650,7 +650,10 @@ bool semaCodeComplete(std::unique_ptr<Co
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 =
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=324732&r1=324731&r2=324732&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/ClangdTests.cpp (original)
+++ clang-tools-extra/trunk/unittests/clangd/ClangdTests.cpp Fri Feb 9 05:51:57 2018
@@ -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 @@ struct Something {
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) {
Modified: clang-tools-extra/trunk/unittests/clangd/Matchers.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/Matchers.h?rev=324732&r1=324731&r2=324732&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/Matchers.h (original)
+++ clang-tools-extra/trunk/unittests/clangd/Matchers.h Fri Feb 9 05:51:57 2018
@@ -108,6 +108,28 @@ PolySubsequenceMatcher<Args...> HasSubse
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
More information about the cfe-commits
mailing list