Index: clang-tools-extra/trunk/clangd/CodeComplete.h =================================================================== --- clang-tools-extra/trunk/clangd/CodeComplete.h +++ clang-tools-extra/trunk/clangd/CodeComplete.h @@ -82,6 +82,10 @@ /// Include completions that require small corrections, e.g. change '.' to /// '->' on member access etc. bool IncludeFixIts = false; + + /// Whether to generate snippets for function arguments on code-completion. + /// Needs snippets to be enabled as well. + bool EnableFunctionArgSnippets = true; }; // Semi-structured representation of a code-complete suggestion for our C++ API. Index: clang-tools-extra/trunk/clangd/CodeComplete.cpp =================================================================== --- clang-tools-extra/trunk/clangd/CodeComplete.cpp +++ clang-tools-extra/trunk/clangd/CodeComplete.cpp @@ -1413,8 +1413,17 @@ LSP.additionalTextEdits.push_back(FixIt); } } - if (Opts.EnableSnippets) - LSP.textEdit->newText += SnippetSuffix; + if (Opts.EnableSnippets && !SnippetSuffix.empty()) { + if (!Opts.EnableFunctionArgSnippets && + ((Kind == CompletionItemKind::Function) || + (Kind == CompletionItemKind::Method)) && + (SnippetSuffix.front() == '(') && (SnippetSuffix.back() == ')')) + // Check whether function has any parameters or not. + LSP.textEdit->newText += SnippetSuffix.size() > 2 ? "(${0})" : "()"; + else + LSP.textEdit->newText += SnippetSuffix; + } + // FIXME(kadircet): Do not even fill insertText after making sure textEdit is // compatible with most of the editors. LSP.insertText = LSP.textEdit->newText; Index: clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp =================================================================== --- clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp +++ clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp @@ -1648,6 +1648,58 @@ SigDoc("Doc from sema")))); } +TEST(CompletionTest, RenderWithSnippetsForFunctionArgsDisabled) { + CodeCompleteOptions Opts; + Opts.EnableFunctionArgSnippets = true; + { + CodeCompletion C; + C.RequiredQualifier = "Foo::"; + C.Name = "x"; + C.SnippetSuffix = "()"; + + auto R = C.render(Opts); + EXPECT_EQ(R.textEdit->newText, "Foo::x"); + EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText); + } + + Opts.EnableSnippets = true; + Opts.EnableFunctionArgSnippets = false; + { + CodeCompletion C; + C.RequiredQualifier = "Foo::"; + C.Name = "x"; + C.SnippetSuffix = ""; + + auto R = C.render(Opts); + EXPECT_EQ(R.textEdit->newText, "Foo::x"); + EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } + + { + CodeCompletion C; + C.RequiredQualifier = "Foo::"; + C.Name = "x"; + C.SnippetSuffix = "()"; + C.Kind = CompletionItemKind::Method; + + auto R = C.render(Opts); + EXPECT_EQ(R.textEdit->newText, "Foo::x()"); + EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } + + { + CodeCompletion C; + C.RequiredQualifier = "Foo::"; + C.Name = "x"; + C.SnippetSuffix = "(${0:bool})"; + C.Kind = CompletionItemKind::Function; + + auto R = C.render(Opts); + EXPECT_EQ(R.textEdit->newText, "Foo::x(${0})"); + EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet); + } +} + } // namespace } // namespace clangd } // namespace clang