Skip to content

Commit bfd2ef7

Browse files
authored
[clangd] Add CodePatterns config option under Completion (#137613)
Allows enabling/disabling code pattern & snippet suggestions during code completion. Resolves clangd/clangd#1867
1 parent a6c4ca8 commit bfd2ef7

File tree

9 files changed

+88
-2
lines changed

9 files changed

+88
-2
lines changed

clang-tools-extra/clangd/ClangdServer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ void ClangdServer::codeComplete(PathRef File, Position Pos,
457457
CodeCompleteOpts.ArgumentLists = Config::current().Completion.ArgumentLists;
458458
CodeCompleteOpts.InsertIncludes =
459459
Config::current().Completion.HeaderInsertion;
460+
CodeCompleteOpts.CodePatterns = Config::current().Completion.CodePatterns;
460461
// FIXME(ibiryukov): even if Preamble is non-null, we may want to check
461462
// both the old and the new version in case only one of them matches.
462463
CodeCompleteResult Result = clangd::codeComplete(

clang-tools-extra/clangd/CodeComplete.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,8 @@ struct CompletionRecorder : public CodeCompleteConsumer {
926926
// FIXME: in case there is no future sema completion callback after the
927927
// recovery mode, we might still want to provide some results (e.g. trivial
928928
// identifier-based completion).
929-
if (Context.getKind() == CodeCompletionContext::CCC_Recovery) {
929+
CodeCompletionContext::Kind ContextKind = Context.getKind();
930+
if (ContextKind == CodeCompletionContext::CCC_Recovery) {
930931
log("Code complete: Ignoring sema code complete callback with Recovery "
931932
"context.");
932933
return;
@@ -950,6 +951,12 @@ struct CompletionRecorder : public CodeCompleteConsumer {
950951
// Retain the results we might want.
951952
for (unsigned I = 0; I < NumResults; ++I) {
952953
auto &Result = InResults[I];
954+
if (Config::current().Completion.CodePatterns ==
955+
Config::CodePatternsPolicy::None &&
956+
Result.Kind == CodeCompletionResult::RK_Pattern &&
957+
// keep allowing the include files autocomplete suggestions
958+
ContextKind != CodeCompletionContext::CCC_IncludedFile)
959+
continue;
953960
// Class members that are shadowed by subclasses are usually noise.
954961
if (Result.Hidden && Result.Declaration &&
955962
Result.Declaration->isCXXClassMember())
@@ -2153,7 +2160,8 @@ class CodeCompleteFlow {
21532160

21542161
clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts() const {
21552162
clang::CodeCompleteOptions Result;
2156-
Result.IncludeCodePatterns = EnableSnippets;
2163+
Result.IncludeCodePatterns =
2164+
EnableSnippets && (CodePatterns != Config::CodePatternsPolicy::None);
21572165
Result.IncludeMacros = true;
21582166
Result.IncludeGlobals = true;
21592167
// We choose to include full comments and not do doxygen parsing in

clang-tools-extra/clangd/CodeComplete.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ struct CodeCompleteOptions {
111111
Config::ArgumentListsPolicy ArgumentLists =
112112
Config::ArgumentListsPolicy::FullPlaceholders;
113113

114+
/// Whether to suggest code patterns & snippets or not in completion
115+
Config::CodePatternsPolicy CodePatterns = Config::CodePatternsPolicy::All;
116+
114117
/// Whether to use the clang parser, or fallback to text-based completion
115118
/// (using identifiers in the current file and symbol indexes).
116119
enum CodeCompletionParse {

clang-tools-extra/clangd/Config.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,11 @@ struct Config {
152152
NeverInsert // Never insert headers as part of code completion
153153
};
154154

155+
enum class CodePatternsPolicy {
156+
All, // Suggest all code patterns and snippets
157+
None // Suggest none of the code patterns and snippets
158+
};
159+
155160
/// Configures code completion feature.
156161
struct {
157162
/// Whether code completion includes results that are not visible in current
@@ -161,6 +166,8 @@ struct Config {
161166
ArgumentListsPolicy ArgumentLists = ArgumentListsPolicy::FullPlaceholders;
162167
/// Controls if headers should be inserted when completions are accepted
163168
HeaderInsertionPolicy HeaderInsertion = HeaderInsertionPolicy::IWYU;
169+
/// Enables code patterns & snippets suggestions
170+
CodePatternsPolicy CodePatterns = CodePatternsPolicy::All;
164171
} Completion;
165172

166173
/// Configures hover feature.

clang-tools-extra/clangd/ConfigCompile.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,17 @@ struct FragmentCompiler {
707707
C.Completion.HeaderInsertion = *Val;
708708
});
709709
}
710+
711+
if (F.CodePatterns) {
712+
if (auto Val = compileEnum<Config::CodePatternsPolicy>("CodePatterns",
713+
*F.CodePatterns)
714+
.map("All", Config::CodePatternsPolicy::All)
715+
.map("None", Config::CodePatternsPolicy::None)
716+
.value())
717+
Out.Apply.push_back([Val](const Params &, Config &C) {
718+
C.Completion.CodePatterns = *Val;
719+
});
720+
}
710721
}
711722

712723
void compile(Fragment::HoverBlock &&F) {

clang-tools-extra/clangd/ConfigFragment.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,11 @@ struct Fragment {
349349
/// symbol is forward-declared
350350
/// "Never": Never insert headers
351351
std::optional<Located<std::string>> HeaderInsertion;
352+
/// Will suggest code patterns & snippets.
353+
/// Values are Config::CodePatternsPolicy:
354+
/// All => enable all code patterns and snippets suggestion
355+
/// None => disable all code patterns and snippets suggestion
356+
std::optional<Located<std::string>> CodePatterns;
352357
};
353358
CompletionBlock Completion;
354359

clang-tools-extra/clangd/ConfigYAML.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,10 @@ class Parser {
249249
if (auto HeaderInsertion = scalarValue(N, "HeaderInsertion"))
250250
F.HeaderInsertion = *HeaderInsertion;
251251
});
252+
Dict.handle("CodePatterns", [&](Node &N) {
253+
if (auto CodePatterns = scalarValue(N, "CodePatterns"))
254+
F.CodePatterns = *CodePatterns;
255+
});
252256
Dict.parse(N);
253257
}
254258

clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3326,6 +3326,40 @@ TEST(CompletionTest, AllScopesCompletion) {
33263326
kind(CompletionItemKind::EnumMember))));
33273327
}
33283328

3329+
TEST(CompletionTest, NoCodePatternsIfDisabled) {
3330+
clangd::CodeCompleteOptions Opts = {};
3331+
Opts.EnableSnippets = true;
3332+
Opts.CodePatterns = Config::CodePatternsPolicy::None;
3333+
3334+
auto Results = completions(R"cpp(
3335+
void function() {
3336+
/// Trying to trigger "for (init-statement; condition; inc-expression)
3337+
/// {statements}~" code pattern
3338+
for^
3339+
}
3340+
)cpp",
3341+
{}, Opts);
3342+
3343+
EXPECT_THAT(Results.Completions,
3344+
Not(Contains(kind(CompletionItemKind::Snippet))));
3345+
}
3346+
3347+
TEST(CompletionTest, CompleteIncludeIfCodePatternsNone) {
3348+
clangd::CodeCompleteOptions Opts = {};
3349+
Opts.EnableSnippets = true;
3350+
Opts.CodePatterns = Config::CodePatternsPolicy::None;
3351+
3352+
Annotations Test(R"cpp(#include "^)cpp");
3353+
auto TU = TestTU::withCode(Test.code());
3354+
TU.AdditionalFiles["foo/bar.h"] = "";
3355+
TU.ExtraArgs.push_back("-I" + testPath("foo"));
3356+
3357+
auto Results = completions(TU, Test.point(), {}, Opts);
3358+
EXPECT_THAT(Results.Completions,
3359+
AllOf(has("foo/", CompletionItemKind::Folder),
3360+
has("bar.h\"", CompletionItemKind::File)));
3361+
}
3362+
33293363
TEST(CompletionTest, NoQualifierIfShadowed) {
33303364
clangd::CodeCompleteOptions Opts = {};
33313365
Opts.AllScopes = true;

clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,19 @@ TEST(ParseYAML, AllScopesWarn) {
217217
EXPECT_THAT(Results[0].Completion.AllScopes, testing::Eq(std::nullopt));
218218
}
219219

220+
TEST(ParseYAML, CodePatterns) {
221+
CapturedDiags Diags;
222+
Annotations YAML(R"yaml(
223+
Completion:
224+
CodePatterns: None
225+
)yaml");
226+
auto Results =
227+
Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
228+
ASSERT_THAT(Diags.Diagnostics, IsEmpty());
229+
ASSERT_EQ(Results.size(), 1u);
230+
EXPECT_THAT(Results[0].Completion.CodePatterns, llvm::ValueIs(val("None")));
231+
}
232+
220233
TEST(ParseYAML, ShowAKA) {
221234
CapturedDiags Diags;
222235
Annotations YAML(R"yaml(

0 commit comments

Comments
 (0)