https://github.com/Noustaa updated https://github.com/llvm/llvm-project/pull/137613
>From 7e715447d242d7e409e02059d2948fb3417fb00f Mon Sep 17 00:00:00 2001 From: Noustaa <nous...@gmail.com> Date: Mon, 28 Apr 2025 12:38:36 +0200 Subject: [PATCH] [clangd] Add CodePatterns config option under Completion Allows enabling/disabling code patterns & snippets suggestion from completion. This can be done either with YAML config or CLI with --code-patterns --- clang-tools-extra/clangd/ClangdServer.cpp | 1 + clang-tools-extra/clangd/CodeComplete.cpp | 7 ++++++- clang-tools-extra/clangd/CodeComplete.h | 3 +++ clang-tools-extra/clangd/Config.h | 7 +++++++ clang-tools-extra/clangd/ConfigCompile.cpp | 11 +++++++++++ clang-tools-extra/clangd/ConfigFragment.h | 6 ++++++ clang-tools-extra/clangd/ConfigYAML.cpp | 4 ++++ clang-tools-extra/clangd/tool/ClangdMain.cpp | 19 +++++++++++++++++++ .../clangd/unittests/CodeCompleteTests.cpp | 18 ++++++++++++++++++ .../clangd/unittests/ConfigYAMLTests.cpp | 13 +++++++++++++ 10 files changed, 88 insertions(+), 1 deletion(-) diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp index 52844129834c3..b499683621f53 100644 --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -457,6 +457,7 @@ void ClangdServer::codeComplete(PathRef File, Position Pos, CodeCompleteOpts.ArgumentLists = Config::current().Completion.ArgumentLists; CodeCompleteOpts.InsertIncludes = Config::current().Completion.HeaderInsertion; + CodeCompleteOpts.CodePatterns = Config::current().Completion.CodePatterns; // FIXME(ibiryukov): even if Preamble is non-null, we may want to check // both the old and the new version in case only one of them matches. CodeCompleteResult Result = clangd::codeComplete( diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index 0eb196fbad46a..171690b6e78b4 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -950,6 +950,10 @@ struct CompletionRecorder : public CodeCompleteConsumer { // Retain the results we might want. for (unsigned I = 0; I < NumResults; ++I) { auto &Result = InResults[I]; + if (Config::current().Completion.CodePatterns == + Config::CodePatternsPolicy::None && + Result.Kind == CodeCompletionResult::RK_Pattern) + continue; // Class members that are shadowed by subclasses are usually noise. if (Result.Hidden && Result.Declaration && Result.Declaration->isCXXClassMember()) @@ -2153,7 +2157,8 @@ class CodeCompleteFlow { clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts() const { clang::CodeCompleteOptions Result; - Result.IncludeCodePatterns = EnableSnippets; + Result.IncludeCodePatterns = + EnableSnippets && (CodePatterns != Config::CodePatternsPolicy::None); Result.IncludeMacros = true; Result.IncludeGlobals = true; // We choose to include full comments and not do doxygen parsing in diff --git a/clang-tools-extra/clangd/CodeComplete.h b/clang-tools-extra/clangd/CodeComplete.h index 83d347054119e..1cf3b41119043 100644 --- a/clang-tools-extra/clangd/CodeComplete.h +++ b/clang-tools-extra/clangd/CodeComplete.h @@ -111,6 +111,9 @@ struct CodeCompleteOptions { Config::ArgumentListsPolicy ArgumentLists = Config::ArgumentListsPolicy::FullPlaceholders; + /// Whether to suggest code patterns & snippets or not in completion + Config::CodePatternsPolicy CodePatterns = Config::CodePatternsPolicy::All; + /// Whether to use the clang parser, or fallback to text-based completion /// (using identifiers in the current file and symbol indexes). enum CodeCompletionParse { diff --git a/clang-tools-extra/clangd/Config.h b/clang-tools-extra/clangd/Config.h index 2891a6d1e77b0..83e0fce847271 100644 --- a/clang-tools-extra/clangd/Config.h +++ b/clang-tools-extra/clangd/Config.h @@ -152,6 +152,11 @@ struct Config { NeverInsert // Never insert headers as part of code completion }; + enum class CodePatternsPolicy { + All, // Suggest all code patterns and snippets + None // Suggest none of the code patterns and snippets + }; + /// Configures code completion feature. struct { /// Whether code completion includes results that are not visible in current @@ -161,6 +166,8 @@ struct Config { ArgumentListsPolicy ArgumentLists = ArgumentListsPolicy::FullPlaceholders; /// Controls if headers should be inserted when completions are accepted HeaderInsertionPolicy HeaderInsertion = HeaderInsertionPolicy::IWYU; + /// Enables code patterns & snippets suggestions + CodePatternsPolicy CodePatterns = CodePatternsPolicy::All; } Completion; /// Configures hover feature. diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp index 13c2405e76df7..35d35f747a868 100644 --- a/clang-tools-extra/clangd/ConfigCompile.cpp +++ b/clang-tools-extra/clangd/ConfigCompile.cpp @@ -707,6 +707,17 @@ struct FragmentCompiler { C.Completion.HeaderInsertion = *Val; }); } + + if (F.CodePatterns) { + if (auto Val = compileEnum<Config::CodePatternsPolicy>("CodePatterns", + *F.CodePatterns) + .map("All", Config::CodePatternsPolicy::All) + .map("None", Config::CodePatternsPolicy::None) + .value()) + Out.Apply.push_back([Val](const Params &, Config &C) { + C.Completion.CodePatterns = *Val; + }); + } } void compile(Fragment::HoverBlock &&F) { diff --git a/clang-tools-extra/clangd/ConfigFragment.h b/clang-tools-extra/clangd/ConfigFragment.h index 2363b483ab96d..c5d95ef125dee 100644 --- a/clang-tools-extra/clangd/ConfigFragment.h +++ b/clang-tools-extra/clangd/ConfigFragment.h @@ -349,6 +349,12 @@ struct Fragment { /// symbol is forward-declared /// "Never": Never insert headers std::optional<Located<std::string>> HeaderInsertion; + /// Will suggest code patterns & snippets. + /// CLI option available '--code-patterns': + /// Values are Config::CodePatternsPolicy: + /// all => enable all code patterns and snippets suggestion + /// none => disable all code patterns and snippets suggestion + std::optional<Located<std::string>> CodePatterns; }; CompletionBlock Completion; diff --git a/clang-tools-extra/clangd/ConfigYAML.cpp b/clang-tools-extra/clangd/ConfigYAML.cpp index 47c6e1cd0f7e7..ff457d8701307 100644 --- a/clang-tools-extra/clangd/ConfigYAML.cpp +++ b/clang-tools-extra/clangd/ConfigYAML.cpp @@ -249,6 +249,10 @@ class Parser { if (auto HeaderInsertion = scalarValue(N, "HeaderInsertion")) F.HeaderInsertion = *HeaderInsertion; }); + Dict.handle("CodePatterns", [&](Node &N) { + if (auto CodePatterns = scalarValue(N, "CodePatterns")) + F.CodePatterns = *CodePatterns; + }); Dict.parse(N); } diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp index 4bd256d6be22b..688b4d4fee17b 100644 --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -267,6 +267,17 @@ opt<Config::HeaderInsertionPolicy> HeaderInsertion{ "Never insert #include directives as part of code completion")), }; +opt<Config::CodePatternsPolicy> CodePatterns{ + "code-patterns", + cat(Features), + desc("Code completion menu will suggest code patterns and snippets."), + init(CodeCompleteOptions().CodePatterns), + values(clEnumValN(Config::CodePatternsPolicy::All, "all", + "Enable all code patterns and snippets."), + clEnumValN(Config::CodePatternsPolicy::None, "none", + "Disable all code patterns and snippets.")), +}; + opt<bool> ImportInsertions{ "import-insertions", cat(Features), @@ -669,6 +680,7 @@ class FlagsConfigProvider : public config::Provider { std::optional<Config::BackgroundPolicy> BGPolicy; std::optional<Config::ArgumentListsPolicy> ArgumentLists; std::optional<Config::HeaderInsertionPolicy> HeaderInsertionPolicy; + std::optional<Config::CodePatternsPolicy> CodePatternsPolicy; // If --compile-commands-dir arg was invoked, check value and override // default path. @@ -723,6 +735,10 @@ class FlagsConfigProvider : public config::Provider { : Config::ArgumentListsPolicy::Delimiters; } + if (CodePatterns == Config::CodePatternsPolicy::None) { + CodePatternsPolicy = Config::CodePatternsPolicy::None; + } + Frag = [=](const config::Params &, Config &C) { if (CDBSearch) C.CompileFlags.CDBSearch = *CDBSearch; @@ -736,6 +752,8 @@ class FlagsConfigProvider : public config::Provider { C.Completion.HeaderInsertion = *HeaderInsertionPolicy; if (AllScopesCompletion.getNumOccurrences()) C.Completion.AllScopes = AllScopesCompletion; + if (CodePatternsPolicy) + C.Completion.CodePatterns = *CodePatternsPolicy; if (Test) C.Index.StandardLibrary = false; @@ -949,6 +967,7 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var Opts.CodeComplete.BundleOverloads = CompletionStyle != Detailed; Opts.CodeComplete.ShowOrigins = ShowOrigins; Opts.CodeComplete.InsertIncludes = HeaderInsertion; + Opts.CodeComplete.CodePatterns = CodePatterns; Opts.CodeComplete.ImportInsertions = ImportInsertions; if (!HeaderInsertionDecorators) { Opts.CodeComplete.IncludeIndicator.Insert.clear(); diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp index 718bee2e40b11..8387a847f706a 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -3326,6 +3326,24 @@ TEST(CompletionTest, AllScopesCompletion) { kind(CompletionItemKind::EnumMember)))); } +TEST(CompletionTest, NoCodePatternsIfDisabled) { + clangd::CodeCompleteOptions Opts = {}; + Opts.EnableSnippets = true; + Opts.CodePatterns = Config::CodePatternsPolicy::None; + + auto Results = completions(R"cpp( + void function() { + /// Trying to trigger "for (init-statement; condition; inc-expression) + /// {statements}~" code pattern + for^ + } + )cpp", + {}, Opts); + + EXPECT_THAT(Results.Completions, + Not(Contains(kind(CompletionItemKind::Snippet)))); +} + TEST(CompletionTest, NoQualifierIfShadowed) { clangd::CodeCompleteOptions Opts = {}; Opts.AllScopes = true; diff --git a/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp b/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp index 979d725461fd0..d71b8d5f9302a 100644 --- a/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp +++ b/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp @@ -217,6 +217,19 @@ TEST(ParseYAML, AllScopesWarn) { EXPECT_THAT(Results[0].Completion.AllScopes, testing::Eq(std::nullopt)); } +TEST(ParseYAML, CodePatterns) { + CapturedDiags Diags; + Annotations YAML(R"yaml( + Completion: + CodePatterns: None + )yaml"); + auto Results = + Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback()); + ASSERT_THAT(Diags.Diagnostics, IsEmpty()); + ASSERT_EQ(Results.size(), 1u); + EXPECT_THAT(Results[0].Completion.CodePatterns, llvm::ValueIs(val("None"))); +} + TEST(ParseYAML, ShowAKA) { CapturedDiags Diags; Annotations YAML(R"yaml( _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits