[clang-tools-extra] [clangd] Add option to fuzzy-match macros in code-complete (PR #169880)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 28 00:52:13 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-tools-extra
Author: Mythreya Kuricheti (MythreyaK)
<details>
<summary>Changes</summary>
Adds `MacroFilterPolicy`
```yaml
Completion:
MacroFilter: ExactPrefix (default), FuzzyMatch
```
Fix for clangd/clangd#<!-- -->1480
---
Full diff: https://github.com/llvm/llvm-project/pull/169880.diff
9 Files Affected:
- (modified) clang-tools-extra/clangd/ClangdServer.cpp (+1)
- (modified) clang-tools-extra/clangd/CodeComplete.cpp (+28-7)
- (modified) clang-tools-extra/clangd/CodeComplete.h (+5)
- (modified) clang-tools-extra/clangd/Config.h (+8)
- (modified) clang-tools-extra/clangd/ConfigCompile.cpp (+16-4)
- (modified) clang-tools-extra/clangd/ConfigFragment.h (+6)
- (modified) clang-tools-extra/clangd/ConfigYAML.cpp (+4)
- (modified) clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp (+29)
- (modified) clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp (+14)
``````````diff
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 e4df7581f1315..0358455ff1f75 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,14 +2038,34 @@ class CodeCompleteFlow {
}
std::optional<float> fuzzyScore(const CompletionCandidate &C) {
- // Macros can be very spammy, so we only support prefix completion.
- if (((C.SemaResult &&
+ using MacroFilterPolicy = Config::MacroFilterPolicy;
+
+ 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()))
- return std::nullopt;
- return Filter->match(C.Name);
+ C.IndexResult->SymInfo.Kind == index::SymbolKind::Macro));
+
+ if (!IsMacroResult)
+ return Filter->match(C.Name);
+
+ // macros with leading and trailing underscore are probably spammy
+ 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 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 e2bdb0fe46e37..1bec601ef1d36 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -4692,6 +4692,35 @@ TEST(CompletionTest, ListExplicitObjectOverloads) {
}
}
+TEST(CompletionTest, FuzzyMatchMacro) {
+ const auto *const Code = R"cpp(
+ #define gl_foo() 42
+ #define _gl_foo() 42
+ int gl_frob();
+
+ int main() {
+ int x = glf^
+ }
+ )cpp";
+
+ {
+ CodeCompleteOptions Opts{};
+ EXPECT_EQ(Opts.MacroFilter, Config::MacroFilterPolicy::ExactPrefix);
+
+ auto Results = completions(Code, {}, Opts);
+ EXPECT_THAT(Results.Completions, ElementsAre(named("gl_frob")));
+ }
+
+ {
+ CodeCompleteOptions Opts{};
+ Opts.MacroFilter = Config::MacroFilterPolicy::FuzzyMatch;
+
+ auto Results = completions(Code, {}, Opts);
+ EXPECT_THAT(Results.Completions,
+ ElementsAre(named("gl_frob"), named("gl_foo")));
+ }
+}
+
} // namespace
} // namespace clangd
} // namespace clang
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(
``````````
</details>
https://github.com/llvm/llvm-project/pull/169880
More information about the cfe-commits
mailing list