https://github.com/MythreyaK updated https://github.com/llvm/llvm-project/pull/169880
>From ddcdd9328804c49cda512611f2dc14c4f59e0d9b Mon Sep 17 00:00:00 2001 From: Mythreya <[email protected]> Date: Thu, 27 Nov 2025 21:47:01 -0800 Subject: [PATCH 1/4] [clangd] Fuzzy-match some macros Allow results from macros that do not have leading or trailing underscores. --- clang-tools-extra/clangd/CodeComplete.cpp | 16 +++++++++---- .../clangd/unittests/CodeCompleteTests.cpp | 23 +++++++++++++++++++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index e4df7581f1315..e2566be6b9cb8 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -1435,7 +1435,8 @@ bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer, Clang->setCodeCompletionConsumer(Consumer.release()); if (Input.Preamble.RequiredModules) - Input.Preamble.RequiredModules->adjustHeaderSearchOptions(Clang->getHeaderSearchOpts()); + Input.Preamble.RequiredModules->adjustHeaderSearchOptions( + Clang->getHeaderSearchOpts()); SyntaxOnlyAction Action; if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) { @@ -2037,13 +2038,18 @@ class CodeCompleteFlow { } std::optional<float> fuzzyScore(const CompletionCandidate &C) { - // Macros can be very spammy, so we only support prefix completion. - if (((C.SemaResult && + const auto IsMacroResult = + ((C.SemaResult && C.SemaResult->Kind == CodeCompletionResult::RK_Macro) || (C.IndexResult && - C.IndexResult->SymInfo.Kind == index::SymbolKind::Macro)) && - !C.Name.starts_with_insensitive(Filter->pattern())) + C.IndexResult->SymInfo.Kind == index::SymbolKind::Macro)); + + // macros with leading and trailing underscore are probably spammy + if (IsMacroResult && (C.Name.starts_with_insensitive("_") || + C.Name.ends_with_insensitive("_"))) { return std::nullopt; + } + return Filter->match(C.Name); } diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp index e2bdb0fe46e37..c46eb719a36f8 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -4692,6 +4692,29 @@ TEST(CompletionTest, ListExplicitObjectOverloads) { } } +TEST(CompletionTest, FuzzyMatchMacro) { + auto Results = completions(R"cpp( + #define gl_foo() 42 + #define _gl_foo() 42 + int gl_frob(); + + int main() { + int x = glf^ + } + )cpp"); + + { + for (const auto &Res : Results.Completions) { + fprintf(stderr, "Name: [%s] Snippet [%s], Signature: [%s] Score %f\n", + Res.Name.c_str(), Res.SnippetSuffix.c_str(), + Res.Signature.c_str(), Res.Score.Total); + } + } + + EXPECT_THAT(Results.Completions, + ElementsAre(named("gl_frob"), named("gl_foo"))); +} + } // namespace } // namespace clangd } // namespace clang >From 3fa86b7fe0933c7bb1730a3589a079bbe98a3770 Mon Sep 17 00:00:00 2001 From: Mythreya <[email protected]> Date: Thu, 27 Nov 2025 22:42:56 -0800 Subject: [PATCH 2/4] Add config options + tests --- clang-tools-extra/clangd/ClangdServer.cpp | 1 + clang-tools-extra/clangd/CodeComplete.cpp | 23 +++++++++++++++---- clang-tools-extra/clangd/CodeComplete.h | 5 ++++ clang-tools-extra/clangd/Config.h | 8 +++++++ clang-tools-extra/clangd/ConfigCompile.cpp | 20 ++++++++++++---- clang-tools-extra/clangd/ConfigFragment.h | 6 +++++ clang-tools-extra/clangd/ConfigYAML.cpp | 4 ++++ .../clangd/unittests/CodeCompleteTests.cpp | 22 ++++++++++-------- .../clangd/unittests/ConfigYAMLTests.cpp | 14 +++++++++++ 9 files changed, 86 insertions(+), 17 deletions(-) diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp index ac1e9aa5f0ff1..f1a87dd12d905 100644 --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -458,6 +458,7 @@ void ClangdServer::codeComplete(PathRef File, Position Pos, CodeCompleteOpts.InsertIncludes = Config::current().Completion.HeaderInsertion; CodeCompleteOpts.CodePatterns = Config::current().Completion.CodePatterns; + CodeCompleteOpts.MacroFilter = Config::current().Completion.MacroFilter; // 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 e2566be6b9cb8..0358455ff1f75 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -2038,19 +2038,34 @@ class CodeCompleteFlow { } std::optional<float> fuzzyScore(const CompletionCandidate &C) { + using MacroFilterPolicy = Config::MacroFilterPolicy; + const auto IsMacroResult = ((C.SemaResult && C.SemaResult->Kind == CodeCompletionResult::RK_Macro) || (C.IndexResult && C.IndexResult->SymInfo.Kind == index::SymbolKind::Macro)); + if (!IsMacroResult) + return Filter->match(C.Name); + // macros with leading and trailing underscore are probably spammy - if (IsMacroResult && (C.Name.starts_with_insensitive("_") || - C.Name.ends_with_insensitive("_"))) { - return std::nullopt; + switch (Opts.MacroFilter) { + case MacroFilterPolicy::ExactPrefix: + if (C.Name.starts_with_insensitive(Filter->pattern())) + return Filter->match(C.Name); + else + return std::nullopt; + case MacroFilterPolicy::FuzzyMatch: + if (!C.Name.starts_with_insensitive("_") && + !C.Name.ends_with_insensitive("_")) + return Filter->match(C.Name); + else + return std::nullopt; } + llvm_unreachable("Unhandled MacroFilter option in fuzzyScore."); - return Filter->match(C.Name); + return std::nullopt; } CodeCompletion::Scores diff --git a/clang-tools-extra/clangd/CodeComplete.h b/clang-tools-extra/clangd/CodeComplete.h index 1cf3b41119043..cde22a8212e6a 100644 --- a/clang-tools-extra/clangd/CodeComplete.h +++ b/clang-tools-extra/clangd/CodeComplete.h @@ -114,6 +114,11 @@ struct CodeCompleteOptions { /// Whether to suggest code patterns & snippets or not in completion Config::CodePatternsPolicy CodePatterns = Config::CodePatternsPolicy::All; + /// Filter macros using an exact prefix, or with a fuzzy match. In both cases, + /// macros with leading or trailing underscores are strictly filtered + Config::MacroFilterPolicy MacroFilter = + Config::MacroFilterPolicy::ExactPrefix; + /// 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 01997cee08515..bc58c831e4e89 100644 --- a/clang-tools-extra/clangd/Config.h +++ b/clang-tools-extra/clangd/Config.h @@ -157,6 +157,12 @@ struct Config { None // Suggest none of the code patterns and snippets }; + enum class MacroFilterPolicy { + ExactPrefix, // Suggest macros if the prefix matches exactly + FuzzyMatch, // Fuzzy-match macros if they do not have "_" as prefix or + // suffix + }; + /// Configures code completion feature. struct { /// Whether code completion includes results that are not visible in current @@ -168,6 +174,8 @@ struct Config { HeaderInsertionPolicy HeaderInsertion = HeaderInsertionPolicy::IWYU; /// Enables code patterns & snippets suggestions CodePatternsPolicy CodePatterns = CodePatternsPolicy::All; + /// Controls how macros are filtered + MacroFilterPolicy MacroFilter = MacroFilterPolicy::ExactPrefix; } Completion; /// Configures hover feature. diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp index 18e31809aa7c7..2b41949d6d05c 100644 --- a/clang-tools-extra/clangd/ConfigCompile.cpp +++ b/clang-tools-extra/clangd/ConfigCompile.cpp @@ -564,10 +564,10 @@ struct FragmentCompiler { auto Fast = isFastTidyCheck(Str); if (!Fast.has_value()) { diag(Warning, - llvm::formatv( - "Latency of clang-tidy check '{0}' is not known. " - "It will only run if ClangTidy.FastCheckFilter is Loose or None", - Str) + llvm::formatv("Latency of clang-tidy check '{0}' is not known. " + "It will only run if ClangTidy.FastCheckFilter is " + "Loose or None", + Str) .str(), Arg.Range); } else if (!*Fast) { @@ -719,6 +719,18 @@ struct FragmentCompiler { C.Completion.CodePatterns = *Val; }); } + + if (F.MacroFilter) { + if (auto Val = + compileEnum<Config::MacroFilterPolicy>("MacroFilter", + *F.MacroFilter) + .map("ExactPrefix", Config::MacroFilterPolicy::ExactPrefix) + .map("FuzzyMatch", Config::MacroFilterPolicy::FuzzyMatch) + .value()) + Out.Apply.push_back([Val](const Params &, Config &C) { + C.Completion.MacroFilter = *Val; + }); + } } void compile(Fragment::HoverBlock &&F) { diff --git a/clang-tools-extra/clangd/ConfigFragment.h b/clang-tools-extra/clangd/ConfigFragment.h index 2afeb36574b21..7604fe4e24c97 100644 --- a/clang-tools-extra/clangd/ConfigFragment.h +++ b/clang-tools-extra/clangd/ConfigFragment.h @@ -354,6 +354,12 @@ struct Fragment { /// All => enable all code patterns and snippets suggestion /// None => disable all code patterns and snippets suggestion std::optional<Located<std::string>> CodePatterns; + /// How to filter macros before offering them as suggestions + /// Values are Config::MacroFilterPolicy: + /// ExactPrefix: Suggest macros if the prefix matches exactly + /// FuzzyMatch: Fuzzy-match macros if they do not have "_" as prefix or + /// suffix + std::optional<Located<std::string>> MacroFilter; }; CompletionBlock Completion; diff --git a/clang-tools-extra/clangd/ConfigYAML.cpp b/clang-tools-extra/clangd/ConfigYAML.cpp index 392cf19b05a55..7b6993620fb8c 100644 --- a/clang-tools-extra/clangd/ConfigYAML.cpp +++ b/clang-tools-extra/clangd/ConfigYAML.cpp @@ -255,6 +255,10 @@ class Parser { if (auto CodePatterns = scalarValue(N, "CodePatterns")) F.CodePatterns = *CodePatterns; }); + Dict.handle("MacroFilter", [&](Node &N) { + if (auto MacroFilter = scalarValue(N, "MacroFilter")) + F.MacroFilter = *MacroFilter; + }); Dict.parse(N); } diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp index c46eb719a36f8..640f2af9507f0 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -4693,7 +4693,7 @@ TEST(CompletionTest, ListExplicitObjectOverloads) { } TEST(CompletionTest, FuzzyMatchMacro) { - auto Results = completions(R"cpp( + const auto *const Code = R"cpp( #define gl_foo() 42 #define _gl_foo() 42 int gl_frob(); @@ -4701,18 +4701,22 @@ TEST(CompletionTest, FuzzyMatchMacro) { int main() { int x = glf^ } - )cpp"); + )cpp"; { - for (const auto &Res : Results.Completions) { - fprintf(stderr, "Name: [%s] Snippet [%s], Signature: [%s] Score %f\n", - Res.Name.c_str(), Res.SnippetSuffix.c_str(), - Res.Signature.c_str(), Res.Score.Total); - } + CodeCompleteOptions Opts{}; + auto Results = completions(Code, {}, Opts); + EXPECT_THAT(Results.Completions, ElementsAre(named("gl_frob"))); } - EXPECT_THAT(Results.Completions, - ElementsAre(named("gl_frob"), named("gl_foo"))); + { + CodeCompleteOptions Opts{}; + Opts.MacroFilter = Config::MacroFilterPolicy::FuzzyMatch; + + auto Results = completions(Code, {}, Opts); + EXPECT_THAT(Results.Completions, + ElementsAre(named("gl_frob"), named("gl_foo"))); + } } } // namespace diff --git a/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp b/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp index c332dcc417fe1..264cb453b413c 100644 --- a/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp +++ b/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp @@ -228,6 +228,20 @@ TEST(ParseYAML, CodePatterns) { EXPECT_THAT(Results[0].Completion.CodePatterns, llvm::ValueIs(val("None"))); } +TEST(ParseYAML, MacroFilter) { + CapturedDiags Diags; + Annotations YAML(R"yaml( + Completion: + MacroFilter: FuzzyMatch + )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.MacroFilter, + llvm::ValueIs(val("FuzzyMatch"))); +} + TEST(ParseYAML, Hover) { CapturedDiags Diags; Annotations YAML(R"yaml( >From 2099979bc6ebed9aee7f69cc2f9c5b13a3f1fb15 Mon Sep 17 00:00:00 2001 From: Mythreya <[email protected]> Date: Thu, 27 Nov 2025 23:53:55 -0800 Subject: [PATCH 3/4] Tweak test --- clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp index 640f2af9507f0..1bec601ef1d36 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -4705,6 +4705,8 @@ TEST(CompletionTest, FuzzyMatchMacro) { { CodeCompleteOptions Opts{}; + EXPECT_EQ(Opts.MacroFilter, Config::MacroFilterPolicy::ExactPrefix); + auto Results = completions(Code, {}, Opts); EXPECT_THAT(Results.Completions, ElementsAre(named("gl_frob"))); } >From fa487258a5f01573b96017c96bb2e25a2c794cba Mon Sep 17 00:00:00 2001 From: Mythreya <[email protected]> Date: Fri, 28 Nov 2025 18:03:37 -0800 Subject: [PATCH 4/4] code-review: update release notes --- clang-tools-extra/docs/ReleaseNotes.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index a6f80e3721db1..aa0f9f0508a15 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -102,6 +102,10 @@ Hover Code completion ^^^^^^^^^^^^^^^ +- Added a new ``MacroFilter`` configuration option to ``Completion`` to + allow fuzzy-matching with the ``FuzzyMatch`` option when suggesting + macros. ``ExactPrefix`` is the default, which retains previous + behavior of suggesting macros which match the prefix exactly. Code actions ^^^^^^^^^^^^ _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
