https://github.com/HerrCai0907 created 
https://github.com/llvm/llvm-project/pull/131804

origin pr

Revert "origin pr"

This reverts commit a686695e6691fcb824b2055c3dfa8f0fd3727355.

impl option

impl

extend func

wip

test

doc

>From a686695e6691fcb824b2055c3dfa8f0fd3727355 Mon Sep 17 00:00:00 2001
From: DeNiCoN <denicon1...@gmail.com>
Date: Mon, 17 Mar 2025 08:04:32 +0000
Subject: [PATCH 1/8] origin pr

---
 clang-tools-extra/clang-tidy/CMakeLists.txt   |  2 +
 .../clang-tidy/ClangQueryCheck.cpp            | 30 +++++++
 .../clang-tidy/ClangQueryCheck.h              | 43 ++++++++++
 clang-tools-extra/clang-tidy/ClangTidy.cpp    |  8 ++
 .../clang-tidy/ClangTidyOptions.cpp           | 84 +++++++++++++++++++
 .../clang-tidy/ClangTidyOptions.h             |  8 ++
 .../clang-tidy/tool/ClangTidyMain.cpp         | 15 +++-
 clang-tools-extra/docs/clang-tidy/index.rst   | 12 +++
 .../infrastructure/query-checks.cpp           | 53 ++++++++++++
 9 files changed, 254 insertions(+), 1 deletion(-)
 create mode 100644 clang-tools-extra/clang-tidy/ClangQueryCheck.cpp
 create mode 100644 clang-tools-extra/clang-tidy/ClangQueryCheck.h
 create mode 100644 
clang-tools-extra/test/clang-tidy/infrastructure/query-checks.cpp

diff --git a/clang-tools-extra/clang-tidy/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/CMakeLists.txt
index 93117cf1d6373..76585b012d174 100644
--- a/clang-tools-extra/clang-tidy/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/CMakeLists.txt
@@ -11,6 +11,7 @@ include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR})
 add_clang_library(clangTidy STATIC
   ClangTidy.cpp
   ClangTidyCheck.cpp
+  ClangQueryCheck.cpp
   ClangTidyModule.cpp
   ClangTidyDiagnosticConsumer.cpp
   ClangTidyOptions.cpp
@@ -38,6 +39,7 @@ clang_target_link_libraries(clangTidy
   clangSerialization
   clangTooling
   clangToolingCore
+  clangQuery
   )
 
 if(CLANG_TIDY_ENABLE_STATIC_ANALYZER)
diff --git a/clang-tools-extra/clang-tidy/ClangQueryCheck.cpp 
b/clang-tools-extra/clang-tidy/ClangQueryCheck.cpp
new file mode 100644
index 0000000000000..a9f46116f7089
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/ClangQueryCheck.cpp
@@ -0,0 +1,30 @@
+//===--- ClangQueryCheck.cpp - clang-tidy ----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangQueryCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::misc {
+
+void ClangQueryCheck::registerMatchers(MatchFinder *Finder) {
+  for (const auto &Matcher : Matchers) {
+    bool Ok = Finder->addDynamicMatcher(Matcher, this);
+    assert(Ok && "Expected to get top level matcher from query parser");
+  }
+}
+
+void ClangQueryCheck::check(const MatchFinder::MatchResult &Result) {
+  auto Map = Result.Nodes.getMap();
+  for (const auto &[k, v] : Map) {
+    diag(v.getSourceRange().getBegin(), k) << v.getSourceRange();
+  }
+}
+
+} // namespace clang::tidy::misc
diff --git a/clang-tools-extra/clang-tidy/ClangQueryCheck.h 
b/clang-tools-extra/clang-tidy/ClangQueryCheck.h
new file mode 100644
index 0000000000000..3c3c702972068
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/ClangQueryCheck.h
@@ -0,0 +1,43 @@
+//===--- ClangQueryCheck.h - clang-tidy --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGQUERYCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGQUERYCHECK_H
+
+#include "ClangTidyCheck.h"
+#include "clang/ASTMatchers/Dynamic/VariantValue.h"
+#include <vector>
+
+namespace clang::query {
+class QuerySession;
+} // namespace clang::query
+
+namespace clang::tidy::misc {
+
+/// A check that matches a given matchers printing their binds as warnings
+class ClangQueryCheck : public ClangTidyCheck {
+  using MatcherVec = std::vector<ast_matchers::dynamic::DynTypedMatcher>;
+
+public:
+  ClangQueryCheck(StringRef Name, ClangTidyContext *Context,
+                  MatcherVec Matchers)
+      : ClangTidyCheck(Name, Context), Matchers(std::move(Matchers)) {}
+
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus;
+  }
+
+private:
+  MatcherVec Matchers;
+};
+
+} // namespace clang::tidy::misc
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGQUERYCHECK_H
diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp 
b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index d99847a82d168..be969c49d3e21 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -15,6 +15,7 @@
 
//===----------------------------------------------------------------------===//
 
 #include "ClangTidy.h"
+#include "ClangQueryCheck.h"
 #include "ClangTidyCheck.h"
 #include "ClangTidyDiagnosticConsumer.h"
 #include "ClangTidyModuleRegistry.h"
@@ -350,6 +351,13 @@ ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
     std::unique_ptr<ClangTidyModule> Module = E.instantiate();
     Module->addCheckFactories(*CheckFactories);
   }
+
+  for (const auto &[k, v] : Context.getOptions().ClangQueryChecks) {
+    CheckFactories->registerCheckFactory(k, [v](StringRef Name,
+                                                ClangTidyContext *Context) {
+      return std::make_unique<misc::ClangQueryCheck>(Name, Context, 
v.Matchers);
+    });
+  }
 }
 
 #if CLANG_TIDY_ENABLE_STATIC_ANALYZER
diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp 
b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
index 8bac6f161fa05..0d6edb88a1d60 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
@@ -7,6 +7,8 @@
 
//===----------------------------------------------------------------------===//
 
 #include "ClangTidyOptions.h"
+#include "../clang-query/Query.h"
+#include "../clang-query/QueryParser.h"
 #include "ClangTidyModuleRegistry.h"
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/SmallString.h"
@@ -126,6 +128,83 @@ void yamlize(IO &IO, ClangTidyOptions::OptionMap &Val, 
bool,
   }
 }
 
+std::vector<clang::ast_matchers::dynamic::DynTypedMatcher>
+processQuerySource(IO &IO, StringRef SourceRef,
+                   clang::query::QuerySession &QS) {
+  namespace query = clang::query;
+  std::vector<clang::ast_matchers::dynamic::DynTypedMatcher> Matchers;
+
+  while (!SourceRef.empty()) {
+    query::QueryRef Q = query::QueryParser::parse(SourceRef, QS);
+    switch (Q->Kind) {
+    case query::QK_Match: {
+      const auto &MatchQuerry = llvm::cast<query::MatchQuery>(*Q);
+      Matchers.push_back(MatchQuerry.Matcher);
+      break;
+    }
+    case query::QK_Let: {
+      const auto &LetQuerry = llvm::cast<query::LetQuery>(*Q);
+      LetQuerry.run(llvm::errs(), QS);
+      break;
+    }
+    case query::QK_Invalid: {
+      const auto &InvalidQuerry = llvm::cast<query::InvalidQuery>(*Q);
+      for (const auto &Line : llvm::split(InvalidQuerry.ErrStr, "\n")) {
+        IO.setError(Line);
+      }
+      break;
+    }
+    // FIXME FileQuerry should also be supported, but what to do with relative
+    // paths?
+    case query::QK_File:
+    case query::QK_DisableOutputKind:
+    case query::QK_EnableOutputKind:
+    case query::QK_SetOutputKind:
+    case query::QK_SetTraversalKind:
+    case query::QK_Help:
+    case query::QK_NoOp:
+    case query::QK_Quit:
+    case query::QK_SetBool: {
+      IO.setError("unsupported querry kind");
+    }
+    }
+    SourceRef = Q->RemainingContent;
+  }
+
+  return Matchers;
+}
+
+template <>
+void yamlize(IO &IO, ClangTidyOptions::QueryCheckMap &Val, bool,
+             EmptyContext &Ctx) {
+  IO.beginMapping();
+  if (IO.outputting()) {
+    for (auto &[k, v] : Val) {
+      IO.mapRequired(k.data(), v);
+    }
+  } else {
+    for (StringRef Key : IO.keys()) {
+      IO.mapRequired(Key.data(), Val[Key]);
+    }
+  }
+  IO.endMapping();
+}
+
+template <>
+void yamlize(IO &IO, ClangTidyOptions::QueryCheckValue &Val, bool,
+             EmptyContext &Ctx) {
+  if (IO.outputting()) {
+    StringRef SourceRef = Val.Source;
+    IO.blockScalarString(SourceRef);
+  } else {
+    StringRef SourceRef;
+    IO.blockScalarString(SourceRef);
+    Val.Source = SourceRef;
+    clang::query::QuerySession QS({});
+    Val.Matchers = processQuerySource(IO, SourceRef, QS);
+  }
+}
+
 struct ChecksVariant {
   std::optional<std::string> AsString;
   std::optional<std::vector<std::string>> AsVector;
@@ -181,6 +260,7 @@ template <> struct MappingTraits<ClangTidyOptions> {
     IO.mapOptional("InheritParentConfig", Options.InheritParentConfig);
     IO.mapOptional("UseColor", Options.UseColor);
     IO.mapOptional("SystemHeaders", Options.SystemHeaders);
+    IO.mapOptional("ClangQueryChecks", Options.ClangQueryChecks);
   }
 };
 
@@ -249,6 +329,10 @@ ClangTidyOptions &ClangTidyOptions::mergeWith(const 
ClangTidyOptions &Other,
         ClangTidyValue(KeyValue.getValue().Value,
                        KeyValue.getValue().Priority + Order));
   }
+
+  for (const auto &KeyValue : Other.ClangQueryChecks) {
+    ClangQueryChecks.insert_or_assign(KeyValue.getKey(), KeyValue.getValue());
+  }
   return *this;
 }
 
diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.h 
b/clang-tools-extra/clang-tidy/ClangTidyOptions.h
index dd78c570d25d9..3a015ed5163cd 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyOptions.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H
 
+#include "clang/ASTMatchers/Dynamic/VariantValue.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringMap.h"
@@ -126,8 +127,15 @@ struct ClangTidyOptions {
   using StringPair = std::pair<std::string, std::string>;
   using OptionMap = llvm::StringMap<ClangTidyValue>;
 
+  struct QueryCheckValue {
+    std::string Source;
+    std::vector<ast_matchers::dynamic::DynTypedMatcher> Matchers;
+  };
+  using QueryCheckMap = llvm::StringMap<QueryCheckValue>;
+
   /// Key-value mapping used to store check-specific options.
   OptionMap CheckOptions;
+  QueryCheckMap ClangQueryChecks;
 
   using ArgList = std::vector<std::string>;
 
diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp 
b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
index fa8887e4639b4..c60e6fcb8c5fa 100644
--- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
+++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
@@ -60,6 +60,18 @@ Configuration files:
   Checks                       - Same as '--checks'. Additionally, the list of
                                  globs can be specified as a list instead of a
                                  string.
+  ClangQueryChecks             - List of key-value pairs. Key specifies a name
+                                  of the new check and value specifies a list
+                                  of matchers in the form of clang-query
+                                  syntax. Example:
+                                    ClangQueryChecks:
+                                      custom-check: |
+                                        let matcher varDecl(
+                                          hasTypeLoc(
+                                            typeLoc().bind("Custom message")
+                                          )
+                                        )
+                                        match matcher
   ExcludeHeaderFilterRegex     - Same as '--exclude-header-filter'.
   ExtraArgs                    - Same as '--extra-arg'.
   ExtraArgsBefore              - Same as '--extra-arg-before'.
@@ -483,7 +495,8 @@ static StringRef closest(StringRef Value, const StringSet<> 
&Allowed) {
   return Closest;
 }
 
-static constexpr StringLiteral VerifyConfigWarningEnd = " [-verify-config]\n";
+static constexpr llvm::StringLiteral VerifyConfigWarningEnd =
+    " [-verify-config]\n";
 
 static bool verifyChecks(const StringSet<> &AllChecks, StringRef CheckGlob,
                          StringRef Source) {
diff --git a/clang-tools-extra/docs/clang-tidy/index.rst 
b/clang-tools-extra/docs/clang-tidy/index.rst
index b7a366e874130..7ad35aceb094f 100644
--- a/clang-tools-extra/docs/clang-tidy/index.rst
+++ b/clang-tools-extra/docs/clang-tidy/index.rst
@@ -292,6 +292,18 @@ An overview of all the command-line options:
     Checks                       - Same as '--checks'. Additionally, the list 
of
                                    globs can be specified as a list instead of 
a
                                    string.
+    ClangQueryChecks             - List of key-value pairs. Key specifies a 
name
+                                   of the new check and value specifies a list
+                                   of matchers in the form of clang-query
+                                   syntax. Example:
+                                     ClangQueryChecks:
+                                       custom-check: |
+                                         let matcher varDecl(
+                                           hasTypeLoc(
+                                             typeLoc().bind("Custom message")
+                                           )
+                                         )
+                                         match matcher
     ExcludeHeaderFilterRegex     - Same as '--exclude-header-filter'.
     ExtraArgs                    - Same as '--extra-arg'.
     ExtraArgsBefore              - Same as '--extra-arg-before'.
diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/query-checks.cpp 
b/clang-tools-extra/test/clang-tidy/infrastructure/query-checks.cpp
new file mode 100644
index 0000000000000..e84516a6977b7
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/infrastructure/query-checks.cpp
@@ -0,0 +1,53 @@
+// DEFINE: %{custom-call-yaml} = custom-call: 'm callExpr().bind(\"Custom 
message\")'
+//
+// DEFINE: %{custom-let-call-yaml} = custom-let-call: \"         \
+// DEFINE:     let expr varDecl(                                 \
+// DEFINE:       hasType(asString(\\\"long long\\\")),           \
+// DEFINE:       hasTypeLoc(typeLoc().bind(\\\"Let message\\\")) \
+// DEFINE:     ) \n                                              \
+// DEFINE:     match expr\"
+//
+// DEFINE: %{full-config} = "{ClangQueryChecks: 
{%{custom-call-yaml},%{custom-let-call-yaml}}}"
+
+//Check single match expression
+// RUN: clang-tidy %s -checks='-*, custom-*'                  \
+// RUN:   -config="{ClangQueryChecks: {%{custom-call-yaml}}}" \
+// RUN:   -- | FileCheck %s -check-prefix=CHECK-CUSTOM-CALL
+
+void a() {
+}
+
+// CHECK-CUSTOM-CALL: warning: Custom message [custom-call]
+// CHECK-CUSTOM-CALL-NEXT: a();{{$}}
+void b() {
+    a();
+}
+
+//Check let with match expression
+// RUN: clang-tidy %s -checks='-*, custom-*'                      \
+// RUN:   -config="{ClangQueryChecks: {%{custom-let-call-yaml}}}" \
+// RUN:   -- | FileCheck %s -check-prefix=CHECK-CUSTOM-LET
+void c() {
+    // CHECK-CUSTOM-LET: warning: Let message [custom-let-call]
+    // CHECK-CUSTOM-LET-NEXT: long long test_long_long = 0;{{$}}
+    long long test_long_long_nolint = 0; //NOLINT(custom-let-call)
+    long long test_long_long = 0;
+}
+
+//Check multiple checks in one config
+// RUN: clang-tidy %s -checks='-*, custom-*' \
+// RUN:   -config=%{full-config}             \
+// RUN:   -- | FileCheck %s -check-prefixes=CHECK-CUSTOM-CALL,CHECK-CUSTOM-LET
+
+//Check multiple checks in one config but only one enabled
+// RUN: clang-tidy %s -checks='-*, custom-call' \
+// RUN:   -config=%{full-config}                \
+// RUN:   -- | FileCheck %s -check-prefixes=CHECK-CUSTOM-CALL 
--implicit-check-not warning:
+
+//Check config dump
+// RUN: clang-tidy -dump-config -checks='-*, custom-*' \
+// RUN:   -config=%{full-config}                       \
+// RUN:   -- | FileCheck %s -check-prefix=CHECK-CONFIG
+// CHECK-CONFIG: ClangQueryChecks:
+// CHECK-CONFIG-DAG: custom-let-call:
+// CHECK-CONFIG-DAG: custom-call:  |{{$[[:space:]]}} m callExpr().bind("Custom 
message")

>From 421b26b2a83810573cb9642f8ed2417b42a85efa Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0...@163.com>
Date: Mon, 17 Mar 2025 08:11:43 +0000
Subject: [PATCH 2/8] Revert "origin pr"

This reverts commit a686695e6691fcb824b2055c3dfa8f0fd3727355.
---
 clang-tools-extra/clang-tidy/CMakeLists.txt   |  2 -
 .../clang-tidy/ClangQueryCheck.cpp            | 30 -------
 .../clang-tidy/ClangQueryCheck.h              | 43 ----------
 clang-tools-extra/clang-tidy/ClangTidy.cpp    |  8 --
 .../clang-tidy/ClangTidyOptions.cpp           | 84 -------------------
 .../clang-tidy/ClangTidyOptions.h             |  8 --
 .../clang-tidy/tool/ClangTidyMain.cpp         | 15 +---
 clang-tools-extra/docs/clang-tidy/index.rst   | 12 ---
 .../infrastructure/query-checks.cpp           | 53 ------------
 9 files changed, 1 insertion(+), 254 deletions(-)
 delete mode 100644 clang-tools-extra/clang-tidy/ClangQueryCheck.cpp
 delete mode 100644 clang-tools-extra/clang-tidy/ClangQueryCheck.h
 delete mode 100644 
clang-tools-extra/test/clang-tidy/infrastructure/query-checks.cpp

diff --git a/clang-tools-extra/clang-tidy/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/CMakeLists.txt
index 76585b012d174..93117cf1d6373 100644
--- a/clang-tools-extra/clang-tidy/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/CMakeLists.txt
@@ -11,7 +11,6 @@ include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR})
 add_clang_library(clangTidy STATIC
   ClangTidy.cpp
   ClangTidyCheck.cpp
-  ClangQueryCheck.cpp
   ClangTidyModule.cpp
   ClangTidyDiagnosticConsumer.cpp
   ClangTidyOptions.cpp
@@ -39,7 +38,6 @@ clang_target_link_libraries(clangTidy
   clangSerialization
   clangTooling
   clangToolingCore
-  clangQuery
   )
 
 if(CLANG_TIDY_ENABLE_STATIC_ANALYZER)
diff --git a/clang-tools-extra/clang-tidy/ClangQueryCheck.cpp 
b/clang-tools-extra/clang-tidy/ClangQueryCheck.cpp
deleted file mode 100644
index a9f46116f7089..0000000000000
--- a/clang-tools-extra/clang-tidy/ClangQueryCheck.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-//===--- ClangQueryCheck.cpp - clang-tidy ----------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "ClangQueryCheck.h"
-#include "clang/ASTMatchers/ASTMatchFinder.h"
-
-using namespace clang::ast_matchers;
-
-namespace clang::tidy::misc {
-
-void ClangQueryCheck::registerMatchers(MatchFinder *Finder) {
-  for (const auto &Matcher : Matchers) {
-    bool Ok = Finder->addDynamicMatcher(Matcher, this);
-    assert(Ok && "Expected to get top level matcher from query parser");
-  }
-}
-
-void ClangQueryCheck::check(const MatchFinder::MatchResult &Result) {
-  auto Map = Result.Nodes.getMap();
-  for (const auto &[k, v] : Map) {
-    diag(v.getSourceRange().getBegin(), k) << v.getSourceRange();
-  }
-}
-
-} // namespace clang::tidy::misc
diff --git a/clang-tools-extra/clang-tidy/ClangQueryCheck.h 
b/clang-tools-extra/clang-tidy/ClangQueryCheck.h
deleted file mode 100644
index 3c3c702972068..0000000000000
--- a/clang-tools-extra/clang-tidy/ClangQueryCheck.h
+++ /dev/null
@@ -1,43 +0,0 @@
-//===--- ClangQueryCheck.h - clang-tidy --------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGQUERYCHECK_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGQUERYCHECK_H
-
-#include "ClangTidyCheck.h"
-#include "clang/ASTMatchers/Dynamic/VariantValue.h"
-#include <vector>
-
-namespace clang::query {
-class QuerySession;
-} // namespace clang::query
-
-namespace clang::tidy::misc {
-
-/// A check that matches a given matchers printing their binds as warnings
-class ClangQueryCheck : public ClangTidyCheck {
-  using MatcherVec = std::vector<ast_matchers::dynamic::DynTypedMatcher>;
-
-public:
-  ClangQueryCheck(StringRef Name, ClangTidyContext *Context,
-                  MatcherVec Matchers)
-      : ClangTidyCheck(Name, Context), Matchers(std::move(Matchers)) {}
-
-  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
-  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
-  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
-    return LangOpts.CPlusPlus;
-  }
-
-private:
-  MatcherVec Matchers;
-};
-
-} // namespace clang::tidy::misc
-
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGQUERYCHECK_H
diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp 
b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index be969c49d3e21..d99847a82d168 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -15,7 +15,6 @@
 
//===----------------------------------------------------------------------===//
 
 #include "ClangTidy.h"
-#include "ClangQueryCheck.h"
 #include "ClangTidyCheck.h"
 #include "ClangTidyDiagnosticConsumer.h"
 #include "ClangTidyModuleRegistry.h"
@@ -351,13 +350,6 @@ ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
     std::unique_ptr<ClangTidyModule> Module = E.instantiate();
     Module->addCheckFactories(*CheckFactories);
   }
-
-  for (const auto &[k, v] : Context.getOptions().ClangQueryChecks) {
-    CheckFactories->registerCheckFactory(k, [v](StringRef Name,
-                                                ClangTidyContext *Context) {
-      return std::make_unique<misc::ClangQueryCheck>(Name, Context, 
v.Matchers);
-    });
-  }
 }
 
 #if CLANG_TIDY_ENABLE_STATIC_ANALYZER
diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp 
b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
index 0d6edb88a1d60..8bac6f161fa05 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
@@ -7,8 +7,6 @@
 
//===----------------------------------------------------------------------===//
 
 #include "ClangTidyOptions.h"
-#include "../clang-query/Query.h"
-#include "../clang-query/QueryParser.h"
 #include "ClangTidyModuleRegistry.h"
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/SmallString.h"
@@ -128,83 +126,6 @@ void yamlize(IO &IO, ClangTidyOptions::OptionMap &Val, 
bool,
   }
 }
 
-std::vector<clang::ast_matchers::dynamic::DynTypedMatcher>
-processQuerySource(IO &IO, StringRef SourceRef,
-                   clang::query::QuerySession &QS) {
-  namespace query = clang::query;
-  std::vector<clang::ast_matchers::dynamic::DynTypedMatcher> Matchers;
-
-  while (!SourceRef.empty()) {
-    query::QueryRef Q = query::QueryParser::parse(SourceRef, QS);
-    switch (Q->Kind) {
-    case query::QK_Match: {
-      const auto &MatchQuerry = llvm::cast<query::MatchQuery>(*Q);
-      Matchers.push_back(MatchQuerry.Matcher);
-      break;
-    }
-    case query::QK_Let: {
-      const auto &LetQuerry = llvm::cast<query::LetQuery>(*Q);
-      LetQuerry.run(llvm::errs(), QS);
-      break;
-    }
-    case query::QK_Invalid: {
-      const auto &InvalidQuerry = llvm::cast<query::InvalidQuery>(*Q);
-      for (const auto &Line : llvm::split(InvalidQuerry.ErrStr, "\n")) {
-        IO.setError(Line);
-      }
-      break;
-    }
-    // FIXME FileQuerry should also be supported, but what to do with relative
-    // paths?
-    case query::QK_File:
-    case query::QK_DisableOutputKind:
-    case query::QK_EnableOutputKind:
-    case query::QK_SetOutputKind:
-    case query::QK_SetTraversalKind:
-    case query::QK_Help:
-    case query::QK_NoOp:
-    case query::QK_Quit:
-    case query::QK_SetBool: {
-      IO.setError("unsupported querry kind");
-    }
-    }
-    SourceRef = Q->RemainingContent;
-  }
-
-  return Matchers;
-}
-
-template <>
-void yamlize(IO &IO, ClangTidyOptions::QueryCheckMap &Val, bool,
-             EmptyContext &Ctx) {
-  IO.beginMapping();
-  if (IO.outputting()) {
-    for (auto &[k, v] : Val) {
-      IO.mapRequired(k.data(), v);
-    }
-  } else {
-    for (StringRef Key : IO.keys()) {
-      IO.mapRequired(Key.data(), Val[Key]);
-    }
-  }
-  IO.endMapping();
-}
-
-template <>
-void yamlize(IO &IO, ClangTidyOptions::QueryCheckValue &Val, bool,
-             EmptyContext &Ctx) {
-  if (IO.outputting()) {
-    StringRef SourceRef = Val.Source;
-    IO.blockScalarString(SourceRef);
-  } else {
-    StringRef SourceRef;
-    IO.blockScalarString(SourceRef);
-    Val.Source = SourceRef;
-    clang::query::QuerySession QS({});
-    Val.Matchers = processQuerySource(IO, SourceRef, QS);
-  }
-}
-
 struct ChecksVariant {
   std::optional<std::string> AsString;
   std::optional<std::vector<std::string>> AsVector;
@@ -260,7 +181,6 @@ template <> struct MappingTraits<ClangTidyOptions> {
     IO.mapOptional("InheritParentConfig", Options.InheritParentConfig);
     IO.mapOptional("UseColor", Options.UseColor);
     IO.mapOptional("SystemHeaders", Options.SystemHeaders);
-    IO.mapOptional("ClangQueryChecks", Options.ClangQueryChecks);
   }
 };
 
@@ -329,10 +249,6 @@ ClangTidyOptions &ClangTidyOptions::mergeWith(const 
ClangTidyOptions &Other,
         ClangTidyValue(KeyValue.getValue().Value,
                        KeyValue.getValue().Priority + Order));
   }
-
-  for (const auto &KeyValue : Other.ClangQueryChecks) {
-    ClangQueryChecks.insert_or_assign(KeyValue.getKey(), KeyValue.getValue());
-  }
   return *this;
 }
 
diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.h 
b/clang-tools-extra/clang-tidy/ClangTidyOptions.h
index 3a015ed5163cd..dd78c570d25d9 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyOptions.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.h
@@ -9,7 +9,6 @@
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H
 
-#include "clang/ASTMatchers/Dynamic/VariantValue.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringMap.h"
@@ -127,15 +126,8 @@ struct ClangTidyOptions {
   using StringPair = std::pair<std::string, std::string>;
   using OptionMap = llvm::StringMap<ClangTidyValue>;
 
-  struct QueryCheckValue {
-    std::string Source;
-    std::vector<ast_matchers::dynamic::DynTypedMatcher> Matchers;
-  };
-  using QueryCheckMap = llvm::StringMap<QueryCheckValue>;
-
   /// Key-value mapping used to store check-specific options.
   OptionMap CheckOptions;
-  QueryCheckMap ClangQueryChecks;
 
   using ArgList = std::vector<std::string>;
 
diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp 
b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
index c60e6fcb8c5fa..fa8887e4639b4 100644
--- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
+++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
@@ -60,18 +60,6 @@ Configuration files:
   Checks                       - Same as '--checks'. Additionally, the list of
                                  globs can be specified as a list instead of a
                                  string.
-  ClangQueryChecks             - List of key-value pairs. Key specifies a name
-                                  of the new check and value specifies a list
-                                  of matchers in the form of clang-query
-                                  syntax. Example:
-                                    ClangQueryChecks:
-                                      custom-check: |
-                                        let matcher varDecl(
-                                          hasTypeLoc(
-                                            typeLoc().bind("Custom message")
-                                          )
-                                        )
-                                        match matcher
   ExcludeHeaderFilterRegex     - Same as '--exclude-header-filter'.
   ExtraArgs                    - Same as '--extra-arg'.
   ExtraArgsBefore              - Same as '--extra-arg-before'.
@@ -495,8 +483,7 @@ static StringRef closest(StringRef Value, const StringSet<> 
&Allowed) {
   return Closest;
 }
 
-static constexpr llvm::StringLiteral VerifyConfigWarningEnd =
-    " [-verify-config]\n";
+static constexpr StringLiteral VerifyConfigWarningEnd = " [-verify-config]\n";
 
 static bool verifyChecks(const StringSet<> &AllChecks, StringRef CheckGlob,
                          StringRef Source) {
diff --git a/clang-tools-extra/docs/clang-tidy/index.rst 
b/clang-tools-extra/docs/clang-tidy/index.rst
index 7ad35aceb094f..b7a366e874130 100644
--- a/clang-tools-extra/docs/clang-tidy/index.rst
+++ b/clang-tools-extra/docs/clang-tidy/index.rst
@@ -292,18 +292,6 @@ An overview of all the command-line options:
     Checks                       - Same as '--checks'. Additionally, the list 
of
                                    globs can be specified as a list instead of 
a
                                    string.
-    ClangQueryChecks             - List of key-value pairs. Key specifies a 
name
-                                   of the new check and value specifies a list
-                                   of matchers in the form of clang-query
-                                   syntax. Example:
-                                     ClangQueryChecks:
-                                       custom-check: |
-                                         let matcher varDecl(
-                                           hasTypeLoc(
-                                             typeLoc().bind("Custom message")
-                                           )
-                                         )
-                                         match matcher
     ExcludeHeaderFilterRegex     - Same as '--exclude-header-filter'.
     ExtraArgs                    - Same as '--extra-arg'.
     ExtraArgsBefore              - Same as '--extra-arg-before'.
diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/query-checks.cpp 
b/clang-tools-extra/test/clang-tidy/infrastructure/query-checks.cpp
deleted file mode 100644
index e84516a6977b7..0000000000000
--- a/clang-tools-extra/test/clang-tidy/infrastructure/query-checks.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-// DEFINE: %{custom-call-yaml} = custom-call: 'm callExpr().bind(\"Custom 
message\")'
-//
-// DEFINE: %{custom-let-call-yaml} = custom-let-call: \"         \
-// DEFINE:     let expr varDecl(                                 \
-// DEFINE:       hasType(asString(\\\"long long\\\")),           \
-// DEFINE:       hasTypeLoc(typeLoc().bind(\\\"Let message\\\")) \
-// DEFINE:     ) \n                                              \
-// DEFINE:     match expr\"
-//
-// DEFINE: %{full-config} = "{ClangQueryChecks: 
{%{custom-call-yaml},%{custom-let-call-yaml}}}"
-
-//Check single match expression
-// RUN: clang-tidy %s -checks='-*, custom-*'                  \
-// RUN:   -config="{ClangQueryChecks: {%{custom-call-yaml}}}" \
-// RUN:   -- | FileCheck %s -check-prefix=CHECK-CUSTOM-CALL
-
-void a() {
-}
-
-// CHECK-CUSTOM-CALL: warning: Custom message [custom-call]
-// CHECK-CUSTOM-CALL-NEXT: a();{{$}}
-void b() {
-    a();
-}
-
-//Check let with match expression
-// RUN: clang-tidy %s -checks='-*, custom-*'                      \
-// RUN:   -config="{ClangQueryChecks: {%{custom-let-call-yaml}}}" \
-// RUN:   -- | FileCheck %s -check-prefix=CHECK-CUSTOM-LET
-void c() {
-    // CHECK-CUSTOM-LET: warning: Let message [custom-let-call]
-    // CHECK-CUSTOM-LET-NEXT: long long test_long_long = 0;{{$}}
-    long long test_long_long_nolint = 0; //NOLINT(custom-let-call)
-    long long test_long_long = 0;
-}
-
-//Check multiple checks in one config
-// RUN: clang-tidy %s -checks='-*, custom-*' \
-// RUN:   -config=%{full-config}             \
-// RUN:   -- | FileCheck %s -check-prefixes=CHECK-CUSTOM-CALL,CHECK-CUSTOM-LET
-
-//Check multiple checks in one config but only one enabled
-// RUN: clang-tidy %s -checks='-*, custom-call' \
-// RUN:   -config=%{full-config}                \
-// RUN:   -- | FileCheck %s -check-prefixes=CHECK-CUSTOM-CALL 
--implicit-check-not warning:
-
-//Check config dump
-// RUN: clang-tidy -dump-config -checks='-*, custom-*' \
-// RUN:   -config=%{full-config}                       \
-// RUN:   -- | FileCheck %s -check-prefix=CHECK-CONFIG
-// CHECK-CONFIG: ClangQueryChecks:
-// CHECK-CONFIG-DAG: custom-let-call:
-// CHECK-CONFIG-DAG: custom-call:  |{{$[[:space:]]}} m callExpr().bind("Custom 
message")

>From 6fa8f7ee1188eae6bac1605b3c85d51c90601d9d Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0...@163.com>
Date: Mon, 17 Mar 2025 10:01:49 +0000
Subject: [PATCH 3/8] impl option

---
 .../clang-tidy/ClangTidyOptions.cpp           | 34 +++++++++++++++++--
 .../clang-tidy/ClangTidyOptions.h             |  8 +++++
 2 files changed, 40 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp 
b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
index 8bac6f161fa05..f8b387e222168 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
@@ -10,10 +10,9 @@
 #include "ClangTidyModuleRegistry.h"
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/Debug.h"
-#include "llvm/Support/Errc.h"
 #include "llvm/Support/ErrorOr.h"
-#include "llvm/Support/FileSystem.h"
 #include "llvm/Support/MemoryBufferRef.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/YAMLTraits.h"
@@ -126,6 +125,34 @@ void yamlize(IO &IO, ClangTidyOptions::OptionMap &Val, 
bool,
   }
 }
 
+namespace {
+struct MultiLineString {
+  std::string &S;
+};
+} // namespace
+
+template <> struct BlockScalarTraits<MultiLineString> {
+  static void output(const MultiLineString &S, void *Ctxt, raw_ostream &OS) {
+    OS << S.S;
+  }
+
+  static StringRef input(StringRef Str, void *Ctxt, MultiLineString &S) {
+    S.S = Str;
+    return "";
+  }
+};
+
+template <> struct SequenceElementTraits<ClangTidyOptions::CustomCheckValue> {
+  static const bool flow = false;
+};
+template <> struct MappingTraits<ClangTidyOptions::CustomCheckValue> {
+  static void mapping(IO &IO, ClangTidyOptions::CustomCheckValue &V) {
+    IO.mapRequired("Name", V.Name);
+    MultiLineString MLS{V.Query};
+    IO.mapRequired("Query", MLS);
+  }
+};
+
 struct ChecksVariant {
   std::optional<std::string> AsString;
   std::optional<std::vector<std::string>> AsVector;
@@ -181,6 +208,7 @@ template <> struct MappingTraits<ClangTidyOptions> {
     IO.mapOptional("InheritParentConfig", Options.InheritParentConfig);
     IO.mapOptional("UseColor", Options.UseColor);
     IO.mapOptional("SystemHeaders", Options.SystemHeaders);
+    IO.mapOptional("CustomeChecks", Options.CustomChecks);
   }
 };
 
@@ -249,6 +277,8 @@ ClangTidyOptions &ClangTidyOptions::mergeWith(const 
ClangTidyOptions &Other,
         ClangTidyValue(KeyValue.getValue().Value,
                        KeyValue.getValue().Priority + Order));
   }
+  mergeVectors(CustomChecks, Other.CustomChecks);
+
   return *this;
 }
 
diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.h 
b/clang-tools-extra/clang-tidy/ClangTidyOptions.h
index dd78c570d25d9..9547f94adbde6 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyOptions.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.h
@@ -129,6 +129,14 @@ struct ClangTidyOptions {
   /// Key-value mapping used to store check-specific options.
   OptionMap CheckOptions;
 
+  struct CustomCheckValue {
+    std::string Name;
+    std::string Query;
+    // FIXME: extend more features here (e.g. isLanguageVersionSupported, 
Level)
+  };
+  using CustomCheckValueList = llvm::SmallVector<CustomCheckValue>;
+  std::optional<CustomCheckValueList> CustomChecks;
+
   using ArgList = std::vector<std::string>;
 
   /// Add extra compilation arguments to the end of the list.

>From 6ab7149f0877767bc1d8db7fc561d5a87886e821 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0...@163.com>
Date: Mon, 17 Mar 2025 11:14:30 +0000
Subject: [PATCH 4/8] impl

---
 clang-tools-extra/clang-tidy/CMakeLists.txt   |  2 +
 clang-tools-extra/clang-tidy/ClangTidy.cpp    |  6 ++
 .../clang-tidy/ClangTidyForceLinker.h         |  5 ++
 .../clang-tidy/custom/CMakeLists.txt          | 20 ++++++
 .../clang-tidy/custom/CustomTidyModule.cpp    | 43 ++++++++++++
 .../clang-tidy/custom/QueryCheck.cpp          | 70 +++++++++++++++++++
 .../clang-tidy/custom/QueryCheck.h            | 35 ++++++++++
 7 files changed, 181 insertions(+)
 create mode 100644 clang-tools-extra/clang-tidy/custom/CMakeLists.txt
 create mode 100644 clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp
 create mode 100644 clang-tools-extra/clang-tidy/custom/QueryCheck.cpp
 create mode 100644 clang-tools-extra/clang-tidy/custom/QueryCheck.h

diff --git a/clang-tools-extra/clang-tidy/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/CMakeLists.txt
index 93117cf1d6373..90efd2ef1f451 100644
--- a/clang-tools-extra/clang-tidy/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/CMakeLists.txt
@@ -58,6 +58,7 @@ add_subdirectory(bugprone)
 add_subdirectory(cert)
 add_subdirectory(concurrency)
 add_subdirectory(cppcoreguidelines)
+add_subdirectory(custom)
 add_subdirectory(darwin)
 add_subdirectory(fuchsia)
 add_subdirectory(google)
@@ -85,6 +86,7 @@ set(ALL_CLANG_TIDY_CHECKS
   clangTidyCERTModule
   clangTidyConcurrencyModule
   clangTidyCppCoreGuidelinesModule
+  clangTidyCustomModule
   clangTidyDarwinModule
   clangTidyFuchsiaModule
   clangTidyGoogleModule
diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp 
b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index d99847a82d168..25950319d72c6 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -57,6 +57,10 @@ 
LLVM_INSTANTIATE_REGISTRY(clang::tidy::ClangTidyModuleRegistry)
 
 namespace clang::tidy {
 
+namespace custom {
+extern void setOptions(ClangTidyOptions const &O);
+} // namespace custom
+
 namespace {
 #if CLANG_TIDY_ENABLE_STATIC_ANALYZER
 static const char *AnalyzerCheckNamePrefix = "clang-analyzer-";
@@ -346,6 +350,7 @@ ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
     IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS)
     : Context(Context), OverlayFS(std::move(OverlayFS)),
       CheckFactories(new ClangTidyCheckFactories) {
+  custom::setOptions(Context.getOptions());
   for (ClangTidyModuleRegistry::entry E : ClangTidyModuleRegistry::entries()) {
     std::unique_ptr<ClangTidyModule> Module = E.instantiate();
     Module->addCheckFactories(*CheckFactories);
@@ -659,6 +664,7 @@ getAllChecksAndOptions(bool 
AllowEnablingAnalyzerAlphaCheckers) {
       std::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(), Opts),
       AllowEnablingAnalyzerAlphaCheckers);
   ClangTidyCheckFactories Factories;
+  custom::setOptions(Context.getOptions());
   for (const ClangTidyModuleRegistry::entry &Module :
        ClangTidyModuleRegistry::entries()) {
     Module.instantiate()->addCheckFactories(Factories);
diff --git a/clang-tools-extra/clang-tidy/ClangTidyForceLinker.h 
b/clang-tools-extra/clang-tidy/ClangTidyForceLinker.h
index adde9136ff1dd..50ac6e138df18 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyForceLinker.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyForceLinker.h
@@ -54,6 +54,11 @@ extern volatile int CppCoreGuidelinesModuleAnchorSource;
 static int LLVM_ATTRIBUTE_UNUSED CppCoreGuidelinesModuleAnchorDestination =
     CppCoreGuidelinesModuleAnchorSource;
 
+// This anchor is used to force the linker to link the CustomModule.
+extern volatile int CustomModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED CustomModuleAnchorDestination =
+    CustomModuleAnchorSource;
+
 // This anchor is used to force the linker to link the DarwinModule.
 extern volatile int DarwinModuleAnchorSource;
 static int LLVM_ATTRIBUTE_UNUSED DarwinModuleAnchorDestination =
diff --git a/clang-tools-extra/clang-tidy/custom/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/custom/CMakeLists.txt
new file mode 100644
index 0000000000000..40387b73b5253
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/custom/CMakeLists.txt
@@ -0,0 +1,20 @@
+set(LLVM_LINK_COMPONENTS
+  support
+  )
+
+add_clang_library(clangTidyCustomModule STATIC
+  CustomTidyModule.cpp
+  QueryCheck.cpp
+
+  LINK_LIBS
+  clangTidy
+  clangTidyUtils
+
+  DEPENDS
+  ClangDriverOptions
+  )
+
+clang_target_link_libraries(clangTidyCustomModule
+  PRIVATE
+  clangQuery
+  )
diff --git a/clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp 
b/clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp
new file mode 100644
index 0000000000000..23970c5a1e003
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp
@@ -0,0 +1,43 @@
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "../ClangTidyOptions.h"
+#include "QueryCheck.h"
+#include <memory>
+
+namespace clang::tidy {
+namespace custom {
+
+// FIXME: could be clearer to add parameter of addCheckFactories to pass
+// Options?
+static ClangTidyOptions const *Options = nullptr;
+extern void setOptions(ClangTidyOptions const &O) { Options = &O; }
+
+class CustomModule : public ClangTidyModule {
+public:
+  void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+    if (Options == nullptr || !Options->CustomChecks.has_value() ||
+        Options->CustomChecks->empty())
+      return;
+    for (const ClangTidyOptions::CustomCheckValue &V :
+         Options->CustomChecks.value()) {
+      CheckFactories.registerCheckFactory(
+          "custom-" + V.Name,
+          [&V](llvm::StringRef Name, ClangTidyContext *Context) {
+            return std::make_unique<custom::QueryCheck>(Name, V, Context);
+          });
+    }
+  }
+};
+
+} // namespace custom
+
+// Register the AlteraTidyModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<custom::CustomModule>
+    X("custom-module", "Adds custom query lint checks.");
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the AlteraModule.
+volatile int CustomModuleAnchorSource = 0;
+
+} // namespace clang::tidy
diff --git a/clang-tools-extra/clang-tidy/custom/QueryCheck.cpp 
b/clang-tools-extra/clang-tidy/custom/QueryCheck.cpp
new file mode 100644
index 0000000000000..b72382bb20daa
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/custom/QueryCheck.cpp
@@ -0,0 +1,70 @@
+//===--- QueryCheck.cpp - clang-tidy 
--------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "QueryCheck.h"
+#include "../../clang-query/Query.h"
+#include "../../clang-query/QueryParser.h"
+#include "clang/ASTMatchers/Dynamic/VariantValue.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::custom {
+
+QueryCheck::QueryCheck(llvm::StringRef Name,
+                       const ClangTidyOptions::CustomCheckValue &V,
+                       ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context), Matchers{} {
+  clang::query::QuerySession QS({});
+  llvm::StringRef QueryStringRef{V.Query};
+  while (!QueryStringRef.empty()) {
+    query::QueryRef Q = query::QueryParser::parse(QueryStringRef, QS);
+    switch (Q->Kind) {
+    case query::QK_Match: {
+      const auto &MatchQuerry = llvm::cast<query::MatchQuery>(*Q);
+      Matchers.push_back(MatchQuerry.Matcher);
+      break;
+    }
+    case query::QK_Let: {
+      const auto &LetQuerry = llvm::cast<query::LetQuery>(*Q);
+      LetQuerry.run(llvm::errs(), QS);
+      break;
+    }
+    case query::QK_Invalid: {
+      const auto &InvalidQuerry = llvm::cast<query::InvalidQuery>(*Q);
+      Context->configurationDiag(InvalidQuerry.ErrStr);
+      break;
+    }
+    // FIXME: TODO
+    case query::QK_File:
+    case query::QK_DisableOutputKind:
+    case query::QK_EnableOutputKind:
+    case query::QK_SetOutputKind:
+    case query::QK_SetTraversalKind:
+    case query::QK_Help:
+    case query::QK_NoOp:
+    case query::QK_Quit:
+    case query::QK_SetBool: {
+      Context->configurationDiag("unsupported querry kind");
+    }
+    }
+    QueryStringRef = Q->RemainingContent;
+  }
+}
+
+void QueryCheck::registerMatchers(MatchFinder *Finder) {
+  for (const ast_matchers::dynamic::DynTypedMatcher &M : Matchers)
+    Finder->addDynamicMatcher(M, this);
+}
+
+void QueryCheck::check(const MatchFinder::MatchResult &Result) {
+  for (auto &[Name, Node] : Result.Nodes.getMap())
+    diag(Node.getSourceRange().getBegin(), Name) << Node.getSourceRange();
+}
+
+} // namespace clang::tidy::custom
diff --git a/clang-tools-extra/clang-tidy/custom/QueryCheck.h 
b/clang-tools-extra/clang-tidy/custom/QueryCheck.h
new file mode 100644
index 0000000000000..bb5501a1e5235
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/custom/QueryCheck.h
@@ -0,0 +1,35 @@
+//===--- QueryCheck.h - clang-tidy ------------------------------*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CUSTOM_QUERYCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CUSTOM_QUERYCHECK_H
+
+#include "../ClangTidyCheck.h"
+#include "clang/ASTMatchers/Dynamic/VariantValue.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang::tidy::custom {
+
+/// FIXME: Write a short description.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/custom/query.html
+class QueryCheck : public ClangTidyCheck {
+public:
+  QueryCheck(llvm::StringRef Name, const ClangTidyOptions::CustomCheckValue &V,
+             ClangTidyContext *Context);
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  llvm::SmallVector<ast_matchers::dynamic::DynTypedMatcher> Matchers{};
+};
+
+} // namespace clang::tidy::custom
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CUSTOM_QUERYCHECK_H

>From db6b3150c82d80245e46cd4a2e9e9bddf043d9ee Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0...@163.com>
Date: Mon, 17 Mar 2025 11:54:50 +0000
Subject: [PATCH 5/8] extend func

---
 .../clang-tidy/ClangTidyOptions.cpp           | 24 +++++++++++++++++--
 .../clang-tidy/ClangTidyOptions.h             |  9 ++++++-
 .../clang-tidy/custom/CustomTidyModule.cpp    |  1 +
 .../clang-tidy/custom/QueryCheck.cpp          | 14 +++++++++--
 .../clang-tidy/custom/QueryCheck.h            |  6 +++++
 5 files changed, 49 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp 
b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
index f8b387e222168..b21b85ca38f06 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
@@ -8,6 +8,7 @@
 
 #include "ClangTidyOptions.h"
 #include "ClangTidyModuleRegistry.h"
+#include "clang/Basic/DiagnosticIDs.h"
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
@@ -71,7 +72,8 @@ struct NOptionMap {
   NOptionMap(IO &, const ClangTidyOptions::OptionMap &OptionMap) {
     Options.reserve(OptionMap.size());
     for (const auto &KeyValue : OptionMap)
-      Options.emplace_back(std::string(KeyValue.getKey()), 
KeyValue.getValue().Value);
+      Options.emplace_back(std::string(KeyValue.getKey()),
+                           KeyValue.getValue().Value);
   }
   ClangTidyOptions::OptionMap denormalize(IO &) {
     ClangTidyOptions::OptionMap Map;
@@ -135,13 +137,30 @@ template <> struct BlockScalarTraits<MultiLineString> {
   static void output(const MultiLineString &S, void *Ctxt, raw_ostream &OS) {
     OS << S.S;
   }
-
   static StringRef input(StringRef Str, void *Ctxt, MultiLineString &S) {
     S.S = Str;
     return "";
   }
 };
 
+template <> struct ScalarEnumerationTraits<clang::DiagnosticIDs::Level> {
+  static void enumeration(IO &IO, clang::DiagnosticIDs::Level &Level) {
+    IO.enumCase(Level, "Error", clang::DiagnosticIDs::Level::Error);
+    IO.enumCase(Level, "Warning", clang::DiagnosticIDs::Level::Warning);
+    IO.enumCase(Level, "Note", clang::DiagnosticIDs::Level::Note);
+  }
+};
+template <> struct SequenceElementTraits<ClangTidyOptions::CustomCheckDiag> {
+  static const bool flow = false;
+};
+template <> struct MappingTraits<ClangTidyOptions::CustomCheckDiag> {
+  static void mapping(IO &IO, ClangTidyOptions::CustomCheckDiag &D) {
+    IO.mapRequired("BindName", D.BindName);
+    MultiLineString MLS{D.Message};
+    IO.mapRequired("Message", MLS);
+    IO.mapOptional("Level", D.Level);
+  }
+};
 template <> struct SequenceElementTraits<ClangTidyOptions::CustomCheckValue> {
   static const bool flow = false;
 };
@@ -150,6 +169,7 @@ template <> struct 
MappingTraits<ClangTidyOptions::CustomCheckValue> {
     IO.mapRequired("Name", V.Name);
     MultiLineString MLS{V.Query};
     IO.mapRequired("Query", MLS);
+    IO.mapRequired("Diagnostic", V.Diags);
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.h 
b/clang-tools-extra/clang-tidy/ClangTidyOptions.h
index 9547f94adbde6..2a64ee8fdf7ea 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyOptions.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H
 
+#include "clang/Basic/DiagnosticIDs.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringMap.h"
@@ -17,6 +18,7 @@
 #include "llvm/Support/MemoryBufferRef.h"
 #include "llvm/Support/VirtualFileSystem.h"
 #include <functional>
+#include <map>
 #include <optional>
 #include <string>
 #include <system_error>
@@ -129,10 +131,15 @@ struct ClangTidyOptions {
   /// Key-value mapping used to store check-specific options.
   OptionMap CheckOptions;
 
+  struct CustomCheckDiag {
+    std::string BindName;
+    std::string Message;
+    std::optional<DiagnosticIDs::Level> Level;
+  };
   struct CustomCheckValue {
     std::string Name;
     std::string Query;
-    // FIXME: extend more features here (e.g. isLanguageVersionSupported, 
Level)
+    llvm::SmallVector<CustomCheckDiag> Diags;
   };
   using CustomCheckValueList = llvm::SmallVector<CustomCheckValue>;
   std::optional<CustomCheckValueList> CustomChecks;
diff --git a/clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp 
b/clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp
index 23970c5a1e003..d7178b81b4c4e 100644
--- a/clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp
@@ -22,6 +22,7 @@ class CustomModule : public ClangTidyModule {
     for (const ClangTidyOptions::CustomCheckValue &V :
          Options->CustomChecks.value()) {
       CheckFactories.registerCheckFactory(
+          // add custom- prefix to avoid conflicts with builtin checks
           "custom-" + V.Name,
           [&V](llvm::StringRef Name, ClangTidyContext *Context) {
             return std::make_unique<custom::QueryCheck>(Name, V, Context);
diff --git a/clang-tools-extra/clang-tidy/custom/QueryCheck.cpp 
b/clang-tools-extra/clang-tidy/custom/QueryCheck.cpp
index b72382bb20daa..61db01ce2a5c2 100644
--- a/clang-tools-extra/clang-tidy/custom/QueryCheck.cpp
+++ b/clang-tools-extra/clang-tidy/custom/QueryCheck.cpp
@@ -10,6 +10,8 @@
 #include "../../clang-query/Query.h"
 #include "../../clang-query/QueryParser.h"
 #include "clang/ASTMatchers/Dynamic/VariantValue.h"
+#include "clang/Basic/DiagnosticIDs.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
 
 using namespace clang::ast_matchers;
@@ -19,7 +21,13 @@ namespace clang::tidy::custom {
 QueryCheck::QueryCheck(llvm::StringRef Name,
                        const ClangTidyOptions::CustomCheckValue &V,
                        ClangTidyContext *Context)
-    : ClangTidyCheck(Name, Context), Matchers{} {
+    : ClangTidyCheck(Name, Context) {
+  for (const ClangTidyOptions::CustomCheckDiag &D : V.Diags) {
+    auto It = Diags.try_emplace(D.BindName, llvm::SmallVector<Diag>{}).first;
+    It->second.emplace_back(
+        Diag{D.Message, D.Level.value_or(DiagnosticIDs::Warning)});
+  }
+
   clang::query::QuerySession QS({});
   llvm::StringRef QueryStringRef{V.Query};
   while (!QueryStringRef.empty()) {
@@ -64,7 +72,9 @@ void QueryCheck::registerMatchers(MatchFinder *Finder) {
 
 void QueryCheck::check(const MatchFinder::MatchResult &Result) {
   for (auto &[Name, Node] : Result.Nodes.getMap())
-    diag(Node.getSourceRange().getBegin(), Name) << Node.getSourceRange();
+    if (Diags.contains(Name))
+      for (const Diag &D : Diags[Name])
+        diag(D.Message, D.Level) << Node.getSourceRange();
 }
 
 } // namespace clang::tidy::custom
diff --git a/clang-tools-extra/clang-tidy/custom/QueryCheck.h 
b/clang-tools-extra/clang-tidy/custom/QueryCheck.h
index bb5501a1e5235..f46a20185a195 100644
--- a/clang-tools-extra/clang-tidy/custom/QueryCheck.h
+++ b/clang-tools-extra/clang-tidy/custom/QueryCheck.h
@@ -12,6 +12,7 @@
 #include "../ClangTidyCheck.h"
 #include "clang/ASTMatchers/Dynamic/VariantValue.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
 
 namespace clang::tidy::custom {
 
@@ -28,6 +29,11 @@ class QueryCheck : public ClangTidyCheck {
 
 private:
   llvm::SmallVector<ast_matchers::dynamic::DynTypedMatcher> Matchers{};
+  struct Diag {
+    std::string Message;
+    DiagnosticIDs::Level Level;
+  };
+  llvm::StringMap<llvm::SmallVector<Diag>> Diags{};
 };
 
 } // namespace clang::tidy::custom

>From dba8a8ca84999e82a5300b7547d96c283e2ff993 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0...@163.com>
Date: Mon, 17 Mar 2025 21:59:10 +0000
Subject: [PATCH 6/8] wip

---
 clang-tools-extra/clang-tidy/ClangTidy.cpp    |  9 ++--
 .../clang-tidy/ClangTidyModule.h              |  2 +
 .../clang-tidy/custom/CustomTidyModule.cpp    | 44 +++++++++++--------
 .../clang-tidy/custom/QueryCheck.cpp          | 36 ++++++++++++---
 .../clang-tidy/custom/QueryCheck.h            | 11 ++---
 .../checkers/custom/Inputs/clang-tidy.yml     | 22 ++++++++++
 .../custom/Inputs/incorrect-clang-tidy.yml    | 10 +++++
 .../checkers/custom/query-incorrect-query.cpp |  3 ++
 .../custom/query-partially-active-check.cpp   |  5 +++
 .../test/clang-tidy/checkers/custom/query.cpp |  7 +++
 10 files changed, 114 insertions(+), 35 deletions(-)
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/custom/Inputs/clang-tidy.yml
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/custom/Inputs/incorrect-clang-tidy.yml
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/custom/query-incorrect-query.cpp
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/custom/query-partially-active-check.cpp
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/custom/query.cpp

diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp 
b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index 25950319d72c6..f2a69e01a32c5 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -58,7 +58,8 @@ 
LLVM_INSTANTIATE_REGISTRY(clang::tidy::ClangTidyModuleRegistry)
 namespace clang::tidy {
 
 namespace custom {
-extern void setOptions(ClangTidyOptions const &O);
+extern void registerCustomChecks(ClangTidyOptions const &O,
+                                 ClangTidyCheckFactories &Factories);
 } // namespace custom
 
 namespace {
@@ -350,7 +351,7 @@ ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
     IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS)
     : Context(Context), OverlayFS(std::move(OverlayFS)),
       CheckFactories(new ClangTidyCheckFactories) {
-  custom::setOptions(Context.getOptions());
+  custom::registerCustomChecks(Context.getOptions(), *CheckFactories);
   for (ClangTidyModuleRegistry::entry E : ClangTidyModuleRegistry::entries()) {
     std::unique_ptr<ClangTidyModule> Module = E.instantiate();
     Module->addCheckFactories(*CheckFactories);
@@ -421,7 +422,7 @@ ClangTidyASTConsumerFactory::createASTConsumer(
                         .getCurrentWorkingDirectory();
   if (WorkingDir)
     Context.setCurrentBuildDirectory(WorkingDir.get());
-
+  custom::registerCustomChecks(Context.getOptions(), *CheckFactories);
   std::vector<std::unique_ptr<ClangTidyCheck>> Checks =
       CheckFactories->createChecksForLanguage(&Context);
 
@@ -664,7 +665,7 @@ getAllChecksAndOptions(bool 
AllowEnablingAnalyzerAlphaCheckers) {
       std::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(), Opts),
       AllowEnablingAnalyzerAlphaCheckers);
   ClangTidyCheckFactories Factories;
-  custom::setOptions(Context.getOptions());
+  custom::registerCustomChecks(Context.getOptions(), Factories);
   for (const ClangTidyModuleRegistry::entry &Module :
        ClangTidyModuleRegistry::entries()) {
     Module.instantiate()->addCheckFactories(Factories);
diff --git a/clang-tools-extra/clang-tidy/ClangTidyModule.h 
b/clang-tools-extra/clang-tidy/ClangTidyModule.h
index 28f54331755a7..6f0b2bf32a291 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyModule.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyModule.h
@@ -62,6 +62,8 @@ class ClangTidyCheckFactories {
                          });
   }
 
+  void erase(llvm::StringRef CheckName) { Factories.erase(CheckName); }
+
   /// Create instances of checks that are enabled.
   std::vector<std::unique_ptr<ClangTidyCheck>>
   createChecks(ClangTidyContext *Context) const;
diff --git a/clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp 
b/clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp
index d7178b81b4c4e..e11a39f1a4ccf 100644
--- a/clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp
@@ -3,34 +3,40 @@
 #include "../ClangTidyModuleRegistry.h"
 #include "../ClangTidyOptions.h"
 #include "QueryCheck.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
 #include <memory>
 
 namespace clang::tidy {
 namespace custom {
 
-// FIXME: could be clearer to add parameter of addCheckFactories to pass
-// Options?
-static ClangTidyOptions const *Options = nullptr;
-extern void setOptions(ClangTidyOptions const &O) { Options = &O; }
-
 class CustomModule : public ClangTidyModule {
 public:
-  void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
-    if (Options == nullptr || !Options->CustomChecks.has_value() ||
-        Options->CustomChecks->empty())
-      return;
-    for (const ClangTidyOptions::CustomCheckValue &V :
-         Options->CustomChecks.value()) {
-      CheckFactories.registerCheckFactory(
-          // add custom- prefix to avoid conflicts with builtin checks
-          "custom-" + V.Name,
-          [&V](llvm::StringRef Name, ClangTidyContext *Context) {
-            return std::make_unique<custom::QueryCheck>(Name, V, Context);
-          });
-    }
-  }
+  void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {}
 };
 
+// FIXME: could be clearer to add parameter of addCheckFactories to pass
+// Options?
+extern void registerCustomChecks(ClangTidyOptions const &Options,
+                                 ClangTidyCheckFactories &Factories) {
+  static llvm::SmallSet<llvm::SmallString<32>, 8> CustomCheckNames{};
+  if (!Options.CustomChecks.has_value() || Options.CustomChecks->empty())
+    return;
+  for (llvm::SmallString<32> const &Name : CustomCheckNames)
+    Factories.erase(Name);
+  for (const ClangTidyOptions::CustomCheckValue &V :
+       Options.CustomChecks.value()) {
+    llvm::SmallString<32> Name = llvm::StringRef{"custom-" + V.Name};
+    Factories.registerCheckFactory(
+        // add custom- prefix to avoid conflicts with builtin checks
+        Name, [&V](llvm::StringRef Name, ClangTidyContext *Context) {
+          return std::make_unique<custom::QueryCheck>(Name, V, Context);
+        });
+    CustomCheckNames.insert(std::move(Name));
+  }
+}
+
 } // namespace custom
 
 // Register the AlteraTidyModule using this statically initialized variable.
diff --git a/clang-tools-extra/clang-tidy/custom/QueryCheck.cpp 
b/clang-tools-extra/clang-tidy/custom/QueryCheck.cpp
index 61db01ce2a5c2..c69e76918f7ed 100644
--- a/clang-tools-extra/clang-tidy/custom/QueryCheck.cpp
+++ b/clang-tools-extra/clang-tidy/custom/QueryCheck.cpp
@@ -9,10 +9,12 @@
 #include "QueryCheck.h"
 #include "../../clang-query/Query.h"
 #include "../../clang-query/QueryParser.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/ASTMatchers/Dynamic/VariantValue.h"
 #include "clang/Basic/DiagnosticIDs.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
+#include <string>
 
 using namespace clang::ast_matchers;
 
@@ -23,9 +25,16 @@ QueryCheck::QueryCheck(llvm::StringRef Name,
                        ClangTidyContext *Context)
     : ClangTidyCheck(Name, Context) {
   for (const ClangTidyOptions::CustomCheckDiag &D : V.Diags) {
-    auto It = Diags.try_emplace(D.BindName, llvm::SmallVector<Diag>{}).first;
-    It->second.emplace_back(
-        Diag{D.Message, D.Level.value_or(DiagnosticIDs::Warning)});
+    auto DiagnosticIdIt =
+        Diags
+            .try_emplace(D.Level.value_or(DiagnosticIDs::Warning),
+                         llvm::StringMap<llvm::SmallVector<std::string>>{})
+            .first;
+    auto DiagMessageIt =
+        DiagnosticIdIt->getSecond()
+            .try_emplace(D.BindName, llvm::SmallVector<std::string>{})
+            .first;
+    DiagMessageIt->second.emplace_back(D.Message);
   }
 
   clang::query::QuerySession QS({});
@@ -71,10 +80,23 @@ void QueryCheck::registerMatchers(MatchFinder *Finder) {
 }
 
 void QueryCheck::check(const MatchFinder::MatchResult &Result) {
+  auto Emit = [this](DiagMaps const &DiagMaps, std::string const &BindName,
+                     DynTypedNode const &Node, DiagnosticIDs::Level Level) {
+    if (!DiagMaps.contains(Level))
+      return;
+    auto &DiagMap = DiagMaps.at(Level);
+    if (!DiagMap.contains(BindName))
+      return;
+    for (const std::string &Message : DiagMap.at(BindName)) {
+      diag(Node.getSourceRange().getBegin(), Message, Level);
+    }
+  };
+  for (auto &[Name, Node] : Result.Nodes.getMap())
+    Emit(Diags, Name, Node, DiagnosticIDs::Error);
   for (auto &[Name, Node] : Result.Nodes.getMap())
-    if (Diags.contains(Name))
-      for (const Diag &D : Diags[Name])
-        diag(D.Message, D.Level) << Node.getSourceRange();
+    Emit(Diags, Name, Node, DiagnosticIDs::Warning);
+  // place Note last, otherwise it will not be emitted
+  for (auto &[Name, Node] : Result.Nodes.getMap())
+    Emit(Diags, Name, Node, DiagnosticIDs::Note);
 }
-
 } // namespace clang::tidy::custom
diff --git a/clang-tools-extra/clang-tidy/custom/QueryCheck.h 
b/clang-tools-extra/clang-tidy/custom/QueryCheck.h
index f46a20185a195..ded4cad4e3459 100644
--- a/clang-tools-extra/clang-tidy/custom/QueryCheck.h
+++ b/clang-tools-extra/clang-tidy/custom/QueryCheck.h
@@ -11,6 +11,8 @@
 
 #include "../ClangTidyCheck.h"
 #include "clang/ASTMatchers/Dynamic/VariantValue.h"
+#include "clang/Basic/DiagnosticIDs.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
 
@@ -29,11 +31,10 @@ class QueryCheck : public ClangTidyCheck {
 
 private:
   llvm::SmallVector<ast_matchers::dynamic::DynTypedMatcher> Matchers{};
-  struct Diag {
-    std::string Message;
-    DiagnosticIDs::Level Level;
-  };
-  llvm::StringMap<llvm::SmallVector<Diag>> Diags{};
+  using DiagMaps =
+      llvm::DenseMap<DiagnosticIDs::Level,
+                     llvm::StringMap<llvm::SmallVector<std::string>>>;
+  DiagMaps Diags;
 };
 
 } // namespace clang::tidy::custom
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/custom/Inputs/clang-tidy.yml 
b/clang-tools-extra/test/clang-tidy/checkers/custom/Inputs/clang-tidy.yml
new file mode 100644
index 0000000000000..0af974515aa30
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/custom/Inputs/clang-tidy.yml
@@ -0,0 +1,22 @@
+CustomeChecks:
+  - Name: test-diag-level
+    Query: |
+      match varDecl(
+          hasType(asString("long")),
+          hasTypeLoc(typeLoc().bind("long"))
+      ).bind("decl")
+    Diagnostic:
+      - BindName: long
+        Message: use 'int' instead of 'long'
+        Level: Warning
+      - BindName: decl
+        Message: declaration of 'long'
+        Level: Note
+  - Name: test-let-bind
+    Query: |
+      let expr varDecl(isStaticStorageClass()).bind("vd")
+      match expr
+    Diagnostic:
+      - BindName: vd
+        Message: find static variable
+        Level: Warning
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/custom/Inputs/incorrect-clang-tidy.yml
 
b/clang-tools-extra/test/clang-tidy/checkers/custom/Inputs/incorrect-clang-tidy.yml
new file mode 100644
index 0000000000000..9596d8e4b03a7
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/custom/Inputs/incorrect-clang-tidy.yml
@@ -0,0 +1,10 @@
+CustomeChecks:
+  - Name: test-let-bind
+    Query: |
+      let expr varDecl(isStaticStorageClass()).bind("vd")
+      match expr
+      set output print
+    Diagnostic:
+      - BindName: vd
+        Message: find static variable
+        Level: Warning
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/custom/query-incorrect-query.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/custom/query-incorrect-query.cpp
new file mode 100644
index 0000000000000..cfc2753ca9be7
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/custom/query-incorrect-query.cpp
@@ -0,0 +1,3 @@
+// RUN: %check_clang_tidy %s custom-* %t 
--config-file=%S/Inputs/incorrect-clang-tidy.yml
+
+// CHECK-MESSAGES: warning: unsupported querry kind [clang-tidy-config]
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/custom/query-partially-active-check.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/custom/query-partially-active-check.cpp
new file mode 100644
index 0000000000000..962313ddb587b
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/custom/query-partially-active-check.cpp
@@ -0,0 +1,5 @@
+// RUN: %check_clang_tidy %s custom-test-let-bind %t 
--config-file=%S/Inputs/clang-tidy.yml
+
+extern long E;
+static int S;
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: find static variable 
[custom-test-let-bind]
diff --git a/clang-tools-extra/test/clang-tidy/checkers/custom/query.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/custom/query.cpp
new file mode 100644
index 0000000000000..e9a27301bd611
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/custom/query.cpp
@@ -0,0 +1,7 @@
+// RUN: %check_clang_tidy %s custom-* %t --config-file=%S/Inputs/clang-tidy.yml
+
+extern long E;
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: use 'int' instead of 'long' 
[custom-test-diag-level]
+// CHECK-MESSAGES: [[@LINE-2]]:1: note: declaration of 'long'
+static int S;
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: find static variable 
[custom-test-let-bind]

>From 0df6f7eee3093ccf1f77320367379155e65e4629 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0...@163.com>
Date: Mon, 17 Mar 2025 22:41:40 +0000
Subject: [PATCH 7/8] test

---
 .../custom-query-check/append-clang-tidy.yml  |  8 ++++
 .../custom-query-check/empty-clang-tidy.yml   |  1 +
 .../override-clang-tidy.yml                   | 11 +++++
 .../custom-query-check/root-clang-tidy.yml    | 11 +++++
 .../Inputs/custom-query-check/vfsoverlay.yaml | 44 ++++++++++++++++++
 .../infrastructure/custom-query-check.cpp     | 45 +++++++++++++++++++
 6 files changed, 120 insertions(+)
 create mode 100644 
clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/append-clang-tidy.yml
 create mode 100644 
clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/empty-clang-tidy.yml
 create mode 100644 
clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/override-clang-tidy.yml
 create mode 100644 
clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/root-clang-tidy.yml
 create mode 100644 
clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/vfsoverlay.yaml
 create mode 100644 
clang-tools-extra/test/clang-tidy/infrastructure/custom-query-check.cpp

diff --git 
a/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/append-clang-tidy.yml
 
b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/append-clang-tidy.yml
new file mode 100644
index 0000000000000..5d816eec99f00
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/append-clang-tidy.yml
@@ -0,0 +1,8 @@
+InheritParentConfig: true
+CustomeChecks:
+  - Name: function-decl
+    Query: match functionDecl().bind("func")
+    Diagnostic:
+      - BindName: func
+        Message: find function decl
+        Level: Warning
diff --git 
a/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/empty-clang-tidy.yml
 
b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/empty-clang-tidy.yml
new file mode 100644
index 0000000000000..1f16f2a33b3ce
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/empty-clang-tidy.yml
@@ -0,0 +1 @@
+InheritParentConfig: false
\ No newline at end of file
diff --git 
a/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/override-clang-tidy.yml
 
b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/override-clang-tidy.yml
new file mode 100644
index 0000000000000..0ed6a68ff2af3
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/override-clang-tidy.yml
@@ -0,0 +1,11 @@
+CustomeChecks:
+  - Name: avoid-long-type
+    Query: |
+      match varDecl(
+          hasType(asString("long")),
+          hasTypeLoc(typeLoc().bind("long"))
+      )
+    Diagnostic:
+      - BindName: long
+        Message: use 'int' instead of 'long' override
+        Level: Warning
diff --git 
a/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/root-clang-tidy.yml
 
b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/root-clang-tidy.yml
new file mode 100644
index 0000000000000..9c06a91c56811
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/root-clang-tidy.yml
@@ -0,0 +1,11 @@
+CustomeChecks:
+  - Name: avoid-long-type
+    Query: |
+      match varDecl(
+          hasType(asString("long")),
+          hasTypeLoc(typeLoc().bind("long"))
+      )
+    Diagnostic:
+      - BindName: long
+        Message: use 'int' instead of 'long'
+        Level: Warning
diff --git 
a/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/vfsoverlay.yaml
 
b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/vfsoverlay.yaml
new file mode 100644
index 0000000000000..2b507f60092c3
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/vfsoverlay.yaml
@@ -0,0 +1,44 @@
+version: 0
+roots:
+  - name: OUT_DIR
+    type: directory
+    contents:
+      - name: .clang-tidy
+        type: file
+        external-contents: INPUT_DIR/root-clang-tidy.yml
+      - name: main.cpp
+        type: file
+        external-contents: MAIN_FILE
+      - name: subdir
+        type: directory
+        contents:
+          - name: main.cpp
+            type: file
+            external-contents: MAIN_FILE
+      - name: subdir-override
+        type: directory
+        contents:
+          - name: main.cpp
+            type: file
+            external-contents: MAIN_FILE
+          - name: .clang-tidy
+            type: file
+            external-contents: INPUT_DIR/override-clang-tidy.yml
+      - name: subdir-empty
+        type: directory
+        contents:
+          - name: main.cpp
+            type: file
+            external-contents: MAIN_FILE
+          - name: .clang-tidy
+            type: file
+            external-contents: INPUT_DIR/empty-clang-tidy.yml
+      - name: subdir-append
+        type: directory
+        contents:
+          - name: main.cpp
+            type: file
+            external-contents: MAIN_FILE
+          - name: .clang-tidy
+            type: file
+            external-contents: INPUT_DIR/append-clang-tidy.yml
diff --git 
a/clang-tools-extra/test/clang-tidy/infrastructure/custom-query-check.cpp 
b/clang-tools-extra/test/clang-tidy/infrastructure/custom-query-check.cpp
new file mode 100644
index 0000000000000..b91c1726b3e54
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/infrastructure/custom-query-check.cpp
@@ -0,0 +1,45 @@
+// RUN: sed -e "s:INPUT_DIR:%S/Inputs/custom-query-check:g" -e 
"s:OUT_DIR:%t:g" -e "s:MAIN_FILE:%s:g" 
%S/Inputs/custom-query-check/vfsoverlay.yaml > %t.yaml
+// RUN: clang-tidy %t/main.cpp -checks='-*,custom-*' -vfsoverlay %t.yaml | 
FileCheck %s --check-prefix=CHECK-SAME-DIR
+// RUN: clang-tidy %t/subdir/main.cpp -checks='-*,custom-*' -vfsoverlay 
%t.yaml | FileCheck %s --check-prefix=CHECK-SUB-DIR-BASE
+// RUN: clang-tidy %t/subdir-override/main.cpp -checks='-*,custom-*' 
-vfsoverlay %t.yaml | FileCheck %s --check-prefix=CHECK-SUB-DIR-OVERRIDE
+// RUN: clang-tidy %t/subdir-empty/main.cpp -checks='-*,custom-*' -vfsoverlay 
%t.yaml --allow-no-checks | FileCheck %s --check-prefix=CHECK-SUB-DIR-EMPTY
+// RUN: clang-tidy %t/subdir-append/main.cpp -checks='-*,custom-*' -vfsoverlay 
%t.yaml | FileCheck %s --check-prefix=CHECK-SUB-DIR-APPEND
+// RUN: clang-tidy %t/subdir-append/main.cpp -checks='-*,custom-*' -vfsoverlay 
%t.yaml --list-checks | FileCheck %s --check-prefix=LIST-CHECK
+// RUN: clang-tidy %t/subdir-append/main.cpp -checks='-*,custom-*' -vfsoverlay 
%t.yaml --dump-config | FileCheck %s --check-prefix=DUMP-CONFIG
+// REQUIRES: shell
+
+
+long V;
+// CHECK-SAME-DIR: [[@LINE-1]]:1: warning: use 'int' instead of 'long' 
[custom-avoid-long-type]
+// CHECK-SUB-DIR-BASE: [[@LINE-2]]:1: warning: use 'int' instead of 'long' 
[custom-avoid-long-type]
+// CHECK-SUB-DIR-OVERRIDE: [[@LINE-3]]:1: warning: use 'int' instead of 'long' 
override [custom-avoid-long-type]
+// CHECK-SUB-DIR-EMPTY: No checks enabled.
+// CHECK-SUB-DIR-APPEND: [[@LINE-5]]:1: warning: use 'int' instead of 'long' 
[custom-avoid-long-type]
+
+void f();
+// CHECK-SUB-DIR-APPEND: [[@LINE-1]]:1: warning: find function decl 
[custom-function-decl]
+
+// LIST-CHECK: Enabled checks:
+// LIST-CHECK:   custom-avoid-long-type
+// LIST-CHECK:   custom-function-decl
+
+// DUMP-CONFIG: CustomeChecks:
+// DUMP-CONFIG: - Name: avoid-long-type
+// DUMP-CONFIG:   Query: |
+// DUMP-CONFIG:     match varDecl(
+// DUMP-CONFIG:       hasType(asString("long")),
+// DUMP-CONFIG:       hasTypeLoc(typeLoc().bind("long"))
+// DUMP-CONFIG:     )
+// DUMP-CONFIG:   Diagnostic:
+// DUMP-CONFIG:    - BindName: long
+// DUMP-CONFIG:      Message: |
+// DUMP-CONFIG:           use 'int' instead of 'long'
+// DUMP-CONFIG:      Level:           Warning
+// DUMP-CONFIG: - Name: function-decl
+// DUMP-CONFIG:   Query: |
+// DUMP-CONFIG:     match functionDecl().bind("func")
+// DUMP-CONFIG:   Diagnostic:
+// DUMP-CONFIG:    - BindName: func
+// DUMP-CONFIG:      Message: |
+// DUMP-CONFIG:        find function decl
+// DUMP-CONFIG:   Level: Warning

>From 5bb2c6c287186cf2427a325fe481aa3e7757a0ac Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0...@163.com>
Date: Tue, 18 Mar 2025 13:55:22 +0000
Subject: [PATCH 8/8] doc

---
 .../clang-tidy/ClangTidyOptions.cpp           |  2 +-
 .../clang-tidy/tool/ClangTidyMain.cpp         |  2 +
 clang-tools-extra/docs/ReleaseNotes.rst       |  3 +
 .../clang-tidy/QueryBasedCustomChecks.rst     | 57 +++++++++++++++++++
 clang-tools-extra/docs/clang-tidy/index.rst   |  3 +
 .../checkers/custom/Inputs/clang-tidy.yml     |  2 +-
 .../custom/Inputs/incorrect-clang-tidy.yml    |  2 +-
 .../custom-query-check/append-clang-tidy.yml  |  2 +-
 .../override-clang-tidy.yml                   |  2 +-
 .../custom-query-check/root-clang-tidy.yml    |  2 +-
 .../infrastructure/custom-query-check.cpp     |  2 +-
 11 files changed, 72 insertions(+), 7 deletions(-)
 create mode 100644 clang-tools-extra/docs/clang-tidy/QueryBasedCustomChecks.rst

diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp 
b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
index b21b85ca38f06..acedbd8d41faa 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
@@ -228,7 +228,7 @@ template <> struct MappingTraits<ClangTidyOptions> {
     IO.mapOptional("InheritParentConfig", Options.InheritParentConfig);
     IO.mapOptional("UseColor", Options.UseColor);
     IO.mapOptional("SystemHeaders", Options.SystemHeaders);
-    IO.mapOptional("CustomeChecks", Options.CustomChecks);
+    IO.mapOptional("CustomChecks", Options.CustomChecks);
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp 
b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
index fa8887e4639b4..5784b05d2281d 100644
--- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
+++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
@@ -60,6 +60,8 @@ Configuration files:
   Checks                       - Same as '--checks'. Additionally, the list of
                                  globs can be specified as a list instead of a
                                  string.
+  CustomChecks                 - Array of user defined checks based on
+                                 clang-query syntax.
   ExcludeHeaderFilterRegex     - Same as '--exclude-header-filter'.
   ExtraArgs                    - Same as '--extra-arg'.
   ExtraArgsBefore              - Same as '--extra-arg-before'.
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 2252efb498c2c..6d22f83f2248b 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -96,6 +96,9 @@ Improvements to clang-tidy
   `SystemHeaders` option is enabled.
   Note: this may lead to false negatives; downstream users may need to adjust
   their checks to preserve existing behavior.
+- :program:`clang-tidy` now supports query based custom checks by 
`CustomChecks`
+  configuration option.
+  :doc:`Query Based Custom Check Document <clang-tidy/QueryBasedCustomChecks>`
 
 New checks
 ^^^^^^^^^^
diff --git a/clang-tools-extra/docs/clang-tidy/QueryBasedCustomChecks.rst 
b/clang-tools-extra/docs/clang-tidy/QueryBasedCustomChecks.rst
new file mode 100644
index 0000000000000..6efd8fe6797df
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/QueryBasedCustomChecks.rst
@@ -0,0 +1,57 @@
+====================================
+Query Based Custom Clang-Tidy Checks
+====================================
+
+Introduction
+============
+
+This page provides examples of how to add query based custom checks for
+:program:`clang-tidy`.
+
+Custom checks are based on clang-query syntax. Every custom checks will be
+registered in `custom` module to avoid name conflict. They can be enabled or
+disabled by the checks option like the builtin checks.
+
+Custom checks support inheritance from parent configurations like other
+configuration items.
+
+Configuration
+=============
+
+`CustomChecks` is a list of custom checks. Each check must contain
+  - Name: check name can been used in `-checks` option.
+  - Query: query string
+  - Diagnostic: list of diagnostics to be reported.
+     - BindName: name of the node to be bound in `Query`.
+     - Message: message to be reported.
+     - Level: severity of the diagnostic, the possible values are `Note`, 
`Warning`, `Error`.
+
+Example
+=======
+
+.. code-block:: yaml
+
+  Checks: -*,custom-call-main-function
+  CustomChecks:
+    - Name: call-main-function
+      Query: |
+          match callExpr(
+            callee(
+              functionDecl(isMain()).bind("fn")
+            )
+          ).bind("callee")
+      Diagnostic:
+        - BindName: fn
+          Message: main function.
+          Level: Note
+        - BindName: callee
+          Message: call to main function.
+          Level: Warning
+
+.. code-block:: c++
+
+  int main(); // note: main function.
+
+  void bar() {
+    main(); // warning: call to main function. [custom-call-main-function]
+  }
diff --git a/clang-tools-extra/docs/clang-tidy/index.rst 
b/clang-tools-extra/docs/clang-tidy/index.rst
index b7a366e874130..83b3a4d485df5 100644
--- a/clang-tools-extra/docs/clang-tidy/index.rst
+++ b/clang-tools-extra/docs/clang-tidy/index.rst
@@ -10,6 +10,7 @@ See also:
    :maxdepth: 1
 
    List of Clang-Tidy Checks <checks/list>
+   Query Based Custom Clang-Tidy Checks <QueryBasedCustomChecks>
    Clang-tidy IDE/Editor Integrations <Integrations>
    Getting Involved <Contributing>
    External Clang-Tidy Examples <ExternalClang-TidyExamples>
@@ -292,6 +293,8 @@ An overview of all the command-line options:
     Checks                       - Same as '--checks'. Additionally, the list 
of
                                    globs can be specified as a list instead of 
a
                                    string.
+    CustomChecks                 - Array of user defined checks based on
+                                   clang-query syntax.
     ExcludeHeaderFilterRegex     - Same as '--exclude-header-filter'.
     ExtraArgs                    - Same as '--extra-arg'.
     ExtraArgsBefore              - Same as '--extra-arg-before'.
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/custom/Inputs/clang-tidy.yml 
b/clang-tools-extra/test/clang-tidy/checkers/custom/Inputs/clang-tidy.yml
index 0af974515aa30..b4524e247feae 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/custom/Inputs/clang-tidy.yml
+++ b/clang-tools-extra/test/clang-tidy/checkers/custom/Inputs/clang-tidy.yml
@@ -1,4 +1,4 @@
-CustomeChecks:
+CustomChecks:
   - Name: test-diag-level
     Query: |
       match varDecl(
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/custom/Inputs/incorrect-clang-tidy.yml
 
b/clang-tools-extra/test/clang-tidy/checkers/custom/Inputs/incorrect-clang-tidy.yml
index 9596d8e4b03a7..4cad7364c1297 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/custom/Inputs/incorrect-clang-tidy.yml
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/custom/Inputs/incorrect-clang-tidy.yml
@@ -1,4 +1,4 @@
-CustomeChecks:
+CustomChecks:
   - Name: test-let-bind
     Query: |
       let expr varDecl(isStaticStorageClass()).bind("vd")
diff --git 
a/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/append-clang-tidy.yml
 
b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/append-clang-tidy.yml
index 5d816eec99f00..5b25ec061ba63 100644
--- 
a/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/append-clang-tidy.yml
+++ 
b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/append-clang-tidy.yml
@@ -1,5 +1,5 @@
 InheritParentConfig: true
-CustomeChecks:
+CustomChecks:
   - Name: function-decl
     Query: match functionDecl().bind("func")
     Diagnostic:
diff --git 
a/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/override-clang-tidy.yml
 
b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/override-clang-tidy.yml
index 0ed6a68ff2af3..ec243b8396ea8 100644
--- 
a/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/override-clang-tidy.yml
+++ 
b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/override-clang-tidy.yml
@@ -1,4 +1,4 @@
-CustomeChecks:
+CustomChecks:
   - Name: avoid-long-type
     Query: |
       match varDecl(
diff --git 
a/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/root-clang-tidy.yml
 
b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/root-clang-tidy.yml
index 9c06a91c56811..861ed10be1a5f 100644
--- 
a/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/root-clang-tidy.yml
+++ 
b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/root-clang-tidy.yml
@@ -1,4 +1,4 @@
-CustomeChecks:
+CustomChecks:
   - Name: avoid-long-type
     Query: |
       match varDecl(
diff --git 
a/clang-tools-extra/test/clang-tidy/infrastructure/custom-query-check.cpp 
b/clang-tools-extra/test/clang-tidy/infrastructure/custom-query-check.cpp
index b91c1726b3e54..13834660385d1 100644
--- a/clang-tools-extra/test/clang-tidy/infrastructure/custom-query-check.cpp
+++ b/clang-tools-extra/test/clang-tidy/infrastructure/custom-query-check.cpp
@@ -23,7 +23,7 @@ void f();
 // LIST-CHECK:   custom-avoid-long-type
 // LIST-CHECK:   custom-function-decl
 
-// DUMP-CONFIG: CustomeChecks:
+// DUMP-CONFIG: CustomChecks:
 // DUMP-CONFIG: - Name: avoid-long-type
 // DUMP-CONFIG:   Query: |
 // DUMP-CONFIG:     match varDecl(

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to