llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

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

Author: Peiqi Li (voyager-jhk)

<details>
<summary>Changes</summary>

Enable query-based custom checks in clangd behind a new 
`Diagnostics.ClangTidy.ExperimentalCustomChecks` configuration option.

Custom checks are registered from the per-file clang-tidy options and remain 
subject to clangd's `FastCheckFilter` policy.

Fixes #<!-- -->206696

Assisted by GPT-5.6

---
Full diff: https://github.com/llvm/llvm-project/pull/216336.diff


10 Files Affected:

- (modified) clang-tools-extra/clangd/Config.h (+1) 
- (modified) clang-tools-extra/clangd/ConfigCompile.cpp (+5) 
- (modified) clang-tools-extra/clangd/ConfigFragment.h (+4) 
- (modified) clang-tools-extra/clangd/ConfigYAML.cpp (+4) 
- (modified) clang-tools-extra/clangd/ParsedAST.cpp (+20-3) 
- (modified) clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp (+14) 
- (modified) clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp (+15) 
- (modified) clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp (+43) 
- (modified) clang-tools-extra/docs/ReleaseNotes.md (+17-10) 
- (modified) clang-tools-extra/docs/clang-tidy/QueryBasedCustomChecks.rst (+19) 


``````````diff
diff --git a/clang-tools-extra/clangd/Config.h 
b/clang-tools-extra/clangd/Config.h
index a94a1727199bd..7365c59bb1b36 100644
--- a/clang-tools-extra/clangd/Config.h
+++ b/clang-tools-extra/clangd/Config.h
@@ -111,6 +111,7 @@ struct Config {
       std::string Checks;
       llvm::StringMap<std::string> CheckOptions;
       FastCheckPolicy FastCheckFilter = FastCheckPolicy::Strict;
+      bool ExperimentalCustomChecks = false;
     } ClangTidy;
 
     IncludesPolicy UnusedIncludes = IncludesPolicy::Strict;
diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp 
b/clang-tools-extra/clangd/ConfigCompile.cpp
index 2b41949d6d05c..34394453ca8a4 100644
--- a/clang-tools-extra/clangd/ConfigCompile.cpp
+++ b/clang-tools-extra/clangd/ConfigCompile.cpp
@@ -624,6 +624,11 @@ struct FragmentCompiler {
         Out.Apply.push_back([Val](const Params &, Config &C) {
           C.Diagnostics.ClangTidy.FastCheckFilter = *Val;
         });
+    if (F.ExperimentalCustomChecks)
+      Out.Apply.push_back(
+          [Enabled = **F.ExperimentalCustomChecks](const Params &, Config &C) {
+            C.Diagnostics.ClangTidy.ExperimentalCustomChecks = Enabled;
+          });
   }
 
   void compile(Fragment::DiagnosticsBlock::IncludesBlock &&F) {
diff --git a/clang-tools-extra/clangd/ConfigFragment.h 
b/clang-tools-extra/clangd/ConfigFragment.h
index 7604fe4e24c97..560c8d0ed2cf3 100644
--- a/clang-tools-extra/clangd/ConfigFragment.h
+++ b/clang-tools-extra/clangd/ConfigFragment.h
@@ -297,6 +297,10 @@ struct Fragment {
       ///   Loose: Run checks unless they are known to be slow.
       ///   None: Run checks regardless of their speed.
       std::optional<Located<std::string>> FastCheckFilter;
+
+      /// Whether to enable experimental query-based custom checks configured
+      /// in .clang-tidy files.
+      std::optional<Located<bool>> ExperimentalCustomChecks;
     };
     ClangTidyBlock ClangTidy;
   };
diff --git a/clang-tools-extra/clangd/ConfigYAML.cpp 
b/clang-tools-extra/clangd/ConfigYAML.cpp
index 940c7b8bd2de1..ad1bd814f8405 100644
--- a/clang-tools-extra/clangd/ConfigYAML.cpp
+++ b/clang-tools-extra/clangd/ConfigYAML.cpp
@@ -174,6 +174,10 @@ class Parser {
       if (auto FastCheckFilter = scalarValue(N, "FastCheckFilter"))
         F.FastCheckFilter = *FastCheckFilter;
     });
+    Dict.handle("ExperimentalCustomChecks", [&](Node &N) {
+      if (auto Value = boolValue(N, "ExperimentalCustomChecks"))
+        F.ExperimentalCustomChecks = *Value;
+    });
     Dict.parse(N);
   }
 
diff --git a/clang-tools-extra/clangd/ParsedAST.cpp 
b/clang-tools-extra/clangd/ParsedAST.cpp
index df56420cd7f24..b498f8535abf6 100644
--- a/clang-tools-extra/clangd/ParsedAST.cpp
+++ b/clang-tools-extra/clangd/ParsedAST.cpp
@@ -7,6 +7,7 @@
 
//===----------------------------------------------------------------------===//
 
 #include "ParsedAST.h"
+#include "../clang-tidy/ClangTidy.h"
 #include "../clang-tidy/ClangTidyCheck.h"
 #include "../clang-tidy/ClangTidyDiagnosticConsumer.h"
 #include "../clang-tidy/ClangTidyModule.h"
@@ -69,6 +70,7 @@
 #include <cstddef>
 #include <iterator>
 #include <memory>
+#include <mutex>
 #include <optional>
 #include <string>
 #include <tuple>
@@ -574,15 +576,30 @@ ParsedAST::build(llvm::StringRef Filename, const 
ParseInputs &Inputs,
         E.instantiate()->addCheckFactories(*CTFactories);
       return CTFactories;
     }();
-    tidy::ClangTidyCheckFactories FastFactories = filterFastTidyChecks(
-        *AllCTFactories, Cfg.Diagnostics.ClangTidy.FastCheckFilter);
     CTContext.emplace(std::make_unique<tidy::DefaultOptionsProvider>(
-        tidy::ClangTidyGlobalOptions(), ClangTidyOpts));
+                          tidy::ClangTidyGlobalOptions(), ClangTidyOpts),
+                      /*AllowEnablingAnalyzerAlphaCheckers=*/false,
+                      /*EnableModuleHeadersParsing=*/false,
+                      Cfg.Diagnostics.ClangTidy.ExperimentalCustomChecks);
     // The lifetime of DiagnosticOptions is managed by \c Clang.
     CTContext->setDiagnosticsEngine(nullptr, &Clang->getDiagnostics());
     CTContext->setASTContext(&Clang->getASTContext());
     CTContext->setCurrentFile(Filename);
     CTContext->setSelfContainedDiags(true);
+    tidy::ClangTidyCheckFactories CTCheckFactories = *AllCTFactories;
+#if CLANG_TIDY_ENABLE_QUERY_BASED_CUSTOM_CHECKS
+    if (CTContext->canExperimentalCustomChecks() &&
+        tidy::custom::RegisterCustomChecks) {
+      // RegisterCustomChecks tracks names in process-wide mutable state.
+      // Serializing its use keeps concurrent AST builds independent.
+      static std::mutex CustomChecksMu;
+      std::lock_guard<std::mutex> Lock(CustomChecksMu);
+      tidy::custom::RegisterCustomChecks(CTContext->getOptions(),
+                                         CTCheckFactories);
+    }
+#endif
+    tidy::ClangTidyCheckFactories FastFactories = filterFastTidyChecks(
+        CTCheckFactories, Cfg.Diagnostics.ClangTidy.FastCheckFilter);
     CTChecks = FastFactories.createChecksForLanguage(&*CTContext);
     Preprocessor *PP = &Clang->getPreprocessor();
     for (const auto &Check : CTChecks) {
diff --git a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp 
b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
index 5fecf32f8e5a5..6759afa79bbcd 100644
--- a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
@@ -333,6 +333,20 @@ TEST_F(ConfigCompileTests, Tidy) {
 #endif
 }
 
+TEST_F(ConfigCompileTests, TidyExperimentalCustomChecks) {
+  EXPECT_FALSE(Conf.Diagnostics.ClangTidy.ExperimentalCustomChecks);
+
+  Frag.Diagnostics.ClangTidy.ExperimentalCustomChecks = true;
+  EXPECT_TRUE(compileAndApply());
+  EXPECT_TRUE(Conf.Diagnostics.ClangTidy.ExperimentalCustomChecks);
+
+  Fragment Override;
+  Override.Diagnostics.ClangTidy.ExperimentalCustomChecks = false;
+  auto Compiled = std::move(Override).compile(Diags.callback());
+  EXPECT_TRUE(Compiled(Parm, Conf));
+  EXPECT_FALSE(Conf.Diagnostics.ClangTidy.ExperimentalCustomChecks);
+}
+
 TEST_F(ConfigCompileTests, TidyBadChecks) {
   auto &Tidy = Frag.Diagnostics.ClangTidy;
   Tidy.Add.emplace_back("unknown-check");
diff --git a/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp 
b/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp
index 264cb453b413c..753cd14eaa32c 100644
--- a/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp
@@ -320,6 +320,21 @@ TEST(ParseYAML, IncludesAnalyzeAngledIncludes) {
               llvm::ValueIs(val(true)));
 }
 
+TEST(ParseYAML, ClangTidyExperimentalCustomChecks) {
+  CapturedDiags Diags;
+  Annotations YAML(R"yaml(
+Diagnostics:
+  ClangTidy:
+    ExperimentalCustomChecks: true
+  )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].Diagnostics.ClangTidy.ExperimentalCustomChecks,
+              llvm::ValueIs(val(true)));
+}
+
 TEST(ParseYAML, Style) {
   CapturedDiags Diags;
   Annotations YAML(R"yaml(
diff --git a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp 
b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
index 6d91ac1ef1e8e..ed743f072822b 100644
--- a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
@@ -18,6 +18,7 @@
 #include "TestIndex.h"
 #include "TestTU.h"
 #include "TidyProvider.h"
+#include "clang-tidy-config.h"
 #include "index/MemIndex.h"
 #include "index/Ref.h"
 #include "index/Relation.h"
@@ -359,6 +360,48 @@ TEST(DiagnosticsTest, ClangTidy) {
                "function 'bar' is within a recursive call chain"))));
 }
 
+#if CLANGD_TIDY_CHECKS && CLANG_TIDY_ENABLE_QUERY_BASED_CUSTOM_CHECKS
+TEST(DiagnosticsTest, ClangTidyExperimentalCustomChecks) {
+  Annotations Test(R"cpp(
+    int x = $literal[[0]];
+  )cpp");
+  auto TU = TestTU::withCode(Test.code());
+  TU.ClangTidyProvider = [](tidy::ClangTidyOptions &Opts, llvm::StringRef) {
+    Opts.Checks = "-*,custom-integer-literal";
+    tidy::ClangTidyOptions::CustomCheckValue Check;
+    Check.Name = "integer-literal";
+    Check.Query = R"(match integerLiteral().bind("literal"))";
+    tidy::ClangTidyOptions::CustomCheckDiag Diagnostic;
+    Diagnostic.BindName = "literal";
+    Diagnostic.Message = "integer literal found";
+    Diagnostic.Level = DiagnosticIDs::Warning;
+    Check.Diags.push_back(std::move(Diagnostic));
+    Opts.CustomChecks.emplace();
+    Opts.CustomChecks->push_back(std::move(Check));
+  };
+
+  auto DiagnosticsFor = [&](bool Enabled, Config::FastCheckPolicy Policy) {
+    Config Cfg;
+    Cfg.Diagnostics.ClangTidy.ExperimentalCustomChecks = Enabled;
+    Cfg.Diagnostics.ClangTidy.FastCheckFilter = Policy;
+    WithContextValue WithCfg(Config::Key, std::move(Cfg));
+    auto AST = TU.build();
+    return std::vector<clangd::Diag>(AST.getDiagnostics());
+  };
+  auto CustomDiagnostic =
+      AllOf(Diag(Test.range("literal"), "integer literal found"),
+            diagSource(Diag::ClangTidy), diagName("custom-integer-literal"),
+            diagSeverity(DiagnosticsEngine::Warning));
+
+  EXPECT_THAT(DiagnosticsFor(false, Config::FastCheckPolicy::Loose), 
IsEmpty());
+  EXPECT_THAT(DiagnosticsFor(true, Config::FastCheckPolicy::Strict), 
IsEmpty());
+  EXPECT_THAT(DiagnosticsFor(true, Config::FastCheckPolicy::Loose),
+              ElementsAre(CustomDiagnostic));
+  EXPECT_THAT(DiagnosticsFor(true, Config::FastCheckPolicy::None),
+              ElementsAre(CustomDiagnostic));
+}
+#endif
+
 TEST(DiagnosticsTest, ClangTidyRedundantParenthesesFix) {
   Annotations Test(R"cpp(
     int func() {
diff --git a/clang-tools-extra/docs/ReleaseNotes.md 
b/clang-tools-extra/docs/ReleaseNotes.md
index 29de9aef9e4b6..d4e3935629b06 100644
--- a/clang-tools-extra/docs/ReleaseNotes.md
+++ b/clang-tools-extra/docs/ReleaseNotes.md
@@ -10,6 +10,7 @@ myst:
 % ReleaseNotes.md and ReleaseNotesTemplate.txt.
 
 {#extra-clang-tools-release-releasenotestitle}
+
 # Extra Clang Tools {{env.config.release}} {{ (('(In-Progress) ' if 
env.app.tags.has('PreRelease') else '') ~ 'Release Notes') }}
 
 ```{contents}
@@ -41,11 +42,12 @@ the latest release, please see the [Clang Web 
Site](https://clang.llvm.org) or
 the [LLVM Web Site](https://llvm.org).
 
 Note that if you are reading this file from a Git checkout or the
-main Clang web page, this document applies to the *next* release, not
+main Clang web page, this document applies to the _next_ release, not
 the current one. To see the release notes for a specific release, please
 see the [releases page](https://llvm.org/releases/).
 
 {#what-s-new-in-extra-clang-tools-release}
+
 ## What's New in Extra Clang Tools {{env.config.release}}?
 
 Some of the major new features and improvements to Extra Clang Tools are listed
@@ -58,7 +60,7 @@ infrastructure are described first, followed by tool-specific 
sections.
 
 - The deprecated `zircon` clang-tidy module has been removed. Users of
   `zircon-temporary-objects` should migrate to {doc}`fuchsia-temporary-objects
-  <clang-tidy/checks/fuchsia/temporary-objects>`.
+<clang-tidy/checks/fuchsia/temporary-objects>`.
 
 - In 22nd release, The `clang-tidy/ClangTidyModuleRegistry.h` header was 
deprecated.
   All of the symbols it used to define were moved into 
`clang-tidy/ClangTidyModule.h`.
@@ -70,6 +72,11 @@ infrastructure are described first, followed by 
tool-specific sections.
 
 #### Diagnostics
 
+- Query-based custom clang-tidy checks can now be enabled with the
+  `Diagnostics.ClangTidy.ExperimentalCustomChecks` clangd configuration option.
+  Custom checks are subject to `FastCheckFilter`, and therefore require
+  `FastCheckFilter: Loose` or `None` to run.
+
 #### Semantic Highlighting
 
 #### Compile flags
@@ -101,7 +108,7 @@ infrastructure are described first, followed by 
tool-specific sections.
 #### New checks
 
 - New {doc}`performance-expensive-value-or
-  <clang-tidy/checks/performance/expensive-value-or>` check.
+<clang-tidy/checks/performance/expensive-value-or>` check.
 
   Finds calls to `value_or` (and alternative spellings `valueOr`,
   `ValueOr`) on optional types where the return type is expensive to copy.
@@ -111,37 +118,37 @@ infrastructure are described first, followed by 
tool-specific sections.
 #### Changes in existing checks
 
 - Fixed a crash in {doc}`bugprone-misplaced-operator-in-strlen-in-alloc
-  <clang-tidy/checks/bugprone/misplaced-operator-in-strlen-in-alloc>` when
+<clang-tidy/checks/bugprone/misplaced-operator-in-strlen-in-alloc>` when
   checking an array new expression without a size expression.
 
 - Fixed a crash in {doc}`bugprone-std-namespace-modification
-  <clang-tidy/checks/bugprone/std-namespace-modification>` when checking
+<clang-tidy/checks/bugprone/std-namespace-modification>` when checking
   lambda closure types used as template arguments.
 
 - Improved {doc}`cppcoreguidelines-pro-type-member-init
-  <clang-tidy/checks/cppcoreguidelines/pro-type-member-init>` check by treating
+<clang-tidy/checks/cppcoreguidelines/pro-type-member-init>` check by treating
   `std::array` the same as built-in arrays when `IgnoreArrays` option is 
enabled.
 
 - Improved {doc}`misc-redundant-expression
-  <clang-tidy/checks/misc/redundant-expression>` by fixing false positives in
+<clang-tidy/checks/misc/redundant-expression>` by fixing false positives in
   nested expressions involving different macros or a mix of macro and
   non-macro operands.
 
 - Improved {doc}`modernize-return-braced-init-list
-  <clang-tidy/checks/modernize/return-braced-init-list>` check to no longer
+<clang-tidy/checks/modernize/return-braced-init-list>` check to no longer
   rewrite the return value when the constructed type has a
   `std::initializer_list` constructor, as the braced form could select a
   different constructor.
 
 - Improved {doc}`readability-named-parameter
-  <clang-tidy/checks/readability/named-parameter>` check by ignoring
+<clang-tidy/checks/readability/named-parameter>` check by ignoring
   standard tag types (e.g. `std::in_place_t`, `std::allocator_arg_t`,
   `std::nothrow_t`, iterator tags, lock tags, etc.) that are used
   exclusively for overload resolution. Added the {option}`IgnoredTypes`
   option to allow customizing the set of ignored types.
 
 - Improved {doc}`readability-use-std-min-max
-  <clang-tidy/checks/readability/use-std-min-max>` check by fixing spurious
+<clang-tidy/checks/readability/use-std-min-max>` check by fixing spurious
   trailing semicolons and lost comments when the `if` body has no braces.
 
 #### Removed checks
diff --git a/clang-tools-extra/docs/clang-tidy/QueryBasedCustomChecks.rst 
b/clang-tools-extra/docs/clang-tidy/QueryBasedCustomChecks.rst
index 1d91fad975c7f..73dded0087bdc 100644
--- a/clang-tools-extra/docs/clang-tidy/QueryBasedCustomChecks.rst
+++ b/clang-tools-extra/docs/clang-tidy/QueryBasedCustomChecks.rst
@@ -63,6 +63,25 @@ Example
     main(); // warning: call to main function. [custom-call-main-function]
   }
 
+Using with clangd
+=================
+
+To enable query-based custom checks in clangd, add the following to the clangd
+configuration:
+
+.. code-block:: yaml
+
+  Diagnostics:
+    ClangTidy:
+      ExperimentalCustomChecks: true
+      FastCheckFilter: Loose
+
+The custom-check definitions and check selection remain part of the clang-tidy
+configuration. ``ExperimentalCustomChecks`` does not override clangd's
+``FastCheckFilter``. Because custom checks are not present in clangd's
+fast-check database, ``Strict`` excludes them, while ``Loose`` and ``None``
+allow them.
+
 Matters Need Attention
 ======================
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/216336
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to