aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIlya Biryukov <ibiryukov@google.com>2018-03-16 15:23:44 +0000
committerIlya Biryukov <ibiryukov@google.com>2018-03-16 15:23:44 +0000
commit3b6826fe84373f6a101c5615771793c01510455d (patch)
treec218eba70b3e5cbdf4bfa0efca7b21e1fa03be6d
parent73d0e61849df642258421d89fea4b9e140871688 (diff)
[clangd] Handle multiple callbacks from Sema's completion
Summary: When parser backtracks, we might receive multiple code completion callbacks. Previously we had a failing assertion there, now we take first results and hope they are good enough. Reviewers: sammccall Reviewed By: sammccall Subscribers: klimek, jkorous-apple, ioeric, cfe-commits Differential Revision: https://reviews.llvm.org/D44567 git-svn-id: https://llvm.org/svn/llvm-project/clang-tools-extra/trunk@327717 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--clangd/CodeComplete.cpp9
-rw-r--r--unittests/clangd/CodeCompleteTests.cpp37
2 files changed, 45 insertions, 1 deletions
diff --git a/clangd/CodeComplete.cpp b/clangd/CodeComplete.cpp
index 6edc0769..87536459 100644
--- a/clangd/CodeComplete.cpp
+++ b/clangd/CodeComplete.cpp
@@ -450,8 +450,15 @@ struct CompletionRecorder : public CodeCompleteConsumer {
void ProcessCodeCompleteResults(class Sema &S, CodeCompletionContext Context,
CodeCompletionResult *InResults,
unsigned NumResults) override final {
+ if (CCSema) {
+ log(llvm::formatv(
+ "Multiple code complete callbacks (parser backtracked?). "
+ "Dropping results from context {0}, keeping results from {1}.",
+ getCompletionKindString(this->CCContext.getKind()),
+ getCompletionKindString(Context.getKind())));
+ return;
+ }
// Record the completion context.
- assert(!CCSema && "ProcessCodeCompleteResults called multiple times!");
CCSema = &S;
CCContext = Context;
diff --git a/unittests/clangd/CodeCompleteTests.cpp b/unittests/clangd/CodeCompleteTests.cpp
index 1e11db73..48771a38 100644
--- a/unittests/clangd/CodeCompleteTests.cpp
+++ b/unittests/clangd/CodeCompleteTests.cpp
@@ -608,6 +608,43 @@ TEST(CodeCompleteTest, NoColonColonAtTheEnd) {
EXPECT_THAT(Results.items, Not(Contains(Labeled("clang::"))));
}
+TEST(CompletionTest, BacktrackCrashes) {
+ // Sema calls code completion callbacks twice in these cases.
+ auto Results = completions(R"cpp(
+ namespace ns {
+ struct FooBarBaz {};
+ } // namespace ns
+
+ int foo(ns::FooBar^
+ )cpp");
+
+ EXPECT_THAT(Results.items, ElementsAre(Labeled("FooBarBaz")));
+
+ // Check we don't crash in that case too.
+ completions(R"cpp(
+ struct FooBarBaz {};
+ void test() {
+ if (FooBarBaz * x^) {}
+ }
+)cpp");
+}
+
+TEST(CompletionTest, CompleteInExcludedPPBranch) {
+ auto Results = completions(R"cpp(
+ int bar(int param_in_bar) {
+ }
+
+ int foo(int param_in_foo) {
+#if 0
+ par^
+#endif
+ }
+)cpp");
+
+ EXPECT_THAT(Results.items, Contains(Labeled("param_in_foo")));
+ EXPECT_THAT(Results.items, Not(Contains(Labeled("param_in_bar"))));
+}
+
SignatureHelp signatures(StringRef Text) {
MockFSProvider FS;
MockCompilationDatabase CDB;