Skip to content

Conversation

@MythreyaK
Copy link
Contributor

@MythreyaK MythreyaK commented Nov 28, 2025

Adds MacroFilterPolicy

Completion:
  MacroFilter: ExactPrefix (default), FuzzyMatch

Fixes clangd/clangd#1480

Allow results from macros that do not have leading
or trailing underscores.
@MythreyaK MythreyaK marked this pull request as ready for review November 28, 2025 08:51
@llvmbot
Copy link
Member

llvmbot commented Nov 28, 2025

@llvm/pr-subscribers-clangd

@llvm/pr-subscribers-clang-tools-extra

Author: Mythreya Kuricheti (MythreyaK)

Changes

Adds MacroFilterPolicy

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 --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(

@zwuis
Copy link
Contributor

zwuis commented Nov 28, 2025

Please add a release note entry to "clang-tools-extra/docs/ReleaseNotes.rst". Thanks!

Fix for clangd/clangd#1480

You can use this syntax.

@MythreyaK
Copy link
Contributor Author

Fix for clangd/clangd#1480

You can use this syntax.

Thanks, I keep forgetting it 😅

Updated the release notes, please let me know if it can be improved.

@HighCommander4 HighCommander4 self-requested a review November 29, 2025 02:16
Copy link
Collaborator

@HighCommander4 HighCommander4 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the patch!

Looks good with a minor tweak to the behaviour.

MythreyaK and others added 2 commits December 13, 2025 03:17
If fuzzy-matching, generally exclude macros with
trailing and leading underscores, unless the input
itself begins with an underscore

Co-authored-by: HighCommander4 <[email protected]>
Copy link
Collaborator

@HighCommander4 HighCommander4 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, LGTM!

@HighCommander4 HighCommander4 merged commit d78e431 into llvm:main Dec 14, 2025
11 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Dec 14, 2025

LLVM Buildbot has detected a new failure on builder clang-armv7-global-isel running on linaro-clang-armv7-global-isel while building clang-tools-extra at step 7 "ninja check 1".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/39/builds/9110

Here is the relevant piece of the build log for the reference
Step 7 (ninja check 1) failure: stage 1 checked (failure)
******************** TEST 'LLVM :: CodeGen/X86/2009-03-23-MultiUseSched.ll' FAILED ********************
Exit Code: 2

Command Output (stdout):
--
# RUN: at line 3
/home/tcwg-buildbot/worker/clang-armv7-global-isel/stage1/bin/llc < /home/tcwg-buildbot/worker/clang-armv7-global-isel/llvm/llvm/test/CodeGen/X86/2009-03-23-MultiUseSched.ll -mtriple=x86_64-linux -mcpu=corei7 -relocation-model=static | /home/tcwg-buildbot/worker/clang-armv7-global-isel/stage1/bin/FileCheck /home/tcwg-buildbot/worker/clang-armv7-global-isel/llvm/llvm/test/CodeGen/X86/2009-03-23-MultiUseSched.ll
# executed command: /home/tcwg-buildbot/worker/clang-armv7-global-isel/stage1/bin/llc -mtriple=x86_64-linux -mcpu=corei7 -relocation-model=static
# .---command stderr------------
# | LLVM ERROR: out of memory
# | Allocation failed
# | PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace and instructions to reproduce the bug.
# | Stack dump:
# | 0.	Program arguments: /home/tcwg-buildbot/worker/clang-armv7-global-isel/stage1/bin/llc -mtriple=x86_64-linux -mcpu=corei7 -relocation-model=static
# | 1.	Running pass 'Function Pass Manager' on module '<stdin>'.
# | 2.	Running pass 'X86 DAG->DAG Instruction Selection' on function '@foo'
# | #0 0x10f26610 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/tcwg-buildbot/worker/clang-armv7-global-isel/stage1/bin/llc+0x39d6610)
# | #1 0x10f23ad4 llvm::sys::RunSignalHandlers() (/home/tcwg-buildbot/worker/clang-armv7-global-isel/stage1/bin/llc+0x39d3ad4)
# | #2 0x10f275d0 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
# | #3 0xf0cfd6f0 __default_rt_sa_restorer ./signal/../sysdeps/unix/sysv/linux/arm/sigrestorer.S:80:0
# | #4 0xf0cedb06 ./csu/../sysdeps/unix/sysv/linux/arm/libc-do-syscall.S:47:0
# | #5 0xf0d2d292 __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
# | #6 0xf0cfc840 gsignal ./signal/../sysdeps/posix/raise.c:27:6
# `-----------------------------
# error: command failed with exit status: -6
# executed command: /home/tcwg-buildbot/worker/clang-armv7-global-isel/stage1/bin/FileCheck /home/tcwg-buildbot/worker/clang-armv7-global-isel/llvm/llvm/test/CodeGen/X86/2009-03-23-MultiUseSched.ll
# .---command stderr------------
# | FileCheck error: '<stdin>' is empty.
# | FileCheck command line:  /home/tcwg-buildbot/worker/clang-armv7-global-isel/stage1/bin/FileCheck /home/tcwg-buildbot/worker/clang-armv7-global-isel/llvm/llvm/test/CodeGen/X86/2009-03-23-MultiUseSched.ll
# `-----------------------------
# error: command failed with exit status: 2

--

********************


@MythreyaK MythreyaK deleted the mythreyak/macro-fuzzy-match branch December 15, 2025 01:39
anonymouspc pushed a commit to anonymouspc/llvm that referenced this pull request Dec 15, 2025
Adds `MacroFilterPolicy` 

```yaml
Completion:
  MacroFilter: ExactPrefix (default), FuzzyMatch
```

Fixes clangd/clangd#1480
mahesh-attarde pushed a commit to mahesh-attarde/llvm-project that referenced this pull request Dec 19, 2025
Adds `MacroFilterPolicy` 

```yaml
Completion:
  MacroFilter: ExactPrefix (default), FuzzyMatch
```

Fixes clangd/clangd#1480
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add an option to use fuzzy match for macro completions too (they currently require an exact prefix match)

6 participants