diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -491,6 +491,9 @@ // we need to complete 'forward<$1>($0)'. return "($0)"; + if (Snippet->empty()) + return ""; + bool MayHaveArgList = Completion.Kind == CompletionItemKind::Function || Completion.Kind == CompletionItemKind::Method || Completion.Kind == CompletionItemKind::Constructor || @@ -529,8 +532,6 @@ return *Snippet; // Replace argument snippets with a simplified pattern. - if (Snippet->empty()) - return ""; if (MayHaveArgList) { // Functions snippets can be of 2 types: // - containing only function arguments, e.g. diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -1014,6 +1014,23 @@ EXPECT_THAT(Results.Completions, Not(Contains(labeled("clang::")))); } +TEST(CompletionTests, EmptySnippetDoesNotCrash) { + // See https://github.com/clangd/clangd/issues/1216 + auto Results = completions(R"cpp( + int main() { + auto w = [&](auto &&f) { return f(f); }; + auto f = w([&](auto &&f) { + return [&](auto &&n) { + if (n == 0) { + return 1; + } + return n * ^(f)(n - 1); + }; + })(10); + } + )cpp"); +} + TEST(CompletionTest, BacktrackCrashes) { // Sema calls code completion callbacks twice in these cases. auto Results = completions(R"cpp(