[clang-tools-extra] [clang-tidy] support query based custom check (PR #131804)
Congcong Cai via cfe-commits
cfe-commits at lists.llvm.org
Tue Mar 18 19:12:38 PDT 2025
https://github.com/HerrCai0907 updated https://github.com/llvm/llvm-project/pull/131804
>From a686695e6691fcb824b2055c3dfa8f0fd3727355 Mon Sep 17 00:00:00 2001
From: DeNiCoN <denicon1234 at gmail.com>
Date: Mon, 17 Mar 2025 08:04:32 +0000
Subject: [PATCH 01/11] 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 <congcongcai0907 at 163.com>
Date: Mon, 17 Mar 2025 08:11:43 +0000
Subject: [PATCH 02/11] 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 <congcongcai0907 at 163.com>
Date: Mon, 17 Mar 2025 10:01:49 +0000
Subject: [PATCH 03/11] 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 <congcongcai0907 at 163.com>
Date: Mon, 17 Mar 2025 11:14:30 +0000
Subject: [PATCH 04/11] 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 <congcongcai0907 at 163.com>
Date: Mon, 17 Mar 2025 11:54:50 +0000
Subject: [PATCH 05/11] 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 <congcongcai0907 at 163.com>
Date: Mon, 17 Mar 2025 21:59:10 +0000
Subject: [PATCH 06/11] 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 <congcongcai0907 at 163.com>
Date: Mon, 17 Mar 2025 22:41:40 +0000
Subject: [PATCH 07/11] 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 <congcongcai0907 at 163.com>
Date: Tue, 18 Mar 2025 13:55:22 +0000
Subject: [PATCH 08/11] 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(
>From 64c45dc6033be5eeb906ccf53561f64f4aac8067 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Tue, 18 Mar 2025 14:04:39 +0000
Subject: [PATCH 09/11] fix comment
---
clang-tools-extra/clang-tidy/ClangTidyOptions.cpp | 5 ++---
clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp | 4 ++--
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
index acedbd8d41faa..dd06e502b338c 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
@@ -290,15 +290,14 @@ ClangTidyOptions &ClangTidyOptions::mergeWith(const ClangTidyOptions &Other,
overrideValue(UseColor, Other.UseColor);
mergeVectors(ExtraArgs, Other.ExtraArgs);
mergeVectors(ExtraArgsBefore, Other.ExtraArgsBefore);
-
+ // FIXME: how to handle duplicate names check?
+ mergeVectors(CustomChecks, Other.CustomChecks);
for (const auto &KeyValue : Other.CheckOptions) {
CheckOptions.insert_or_assign(
KeyValue.getKey(),
ClangTidyValue(KeyValue.getValue().Value,
KeyValue.getValue().Priority + Order));
}
- mergeVectors(CustomChecks, Other.CustomChecks);
-
return *this;
}
diff --git a/clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp b/clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp
index e11a39f1a4ccf..6150634fbc4bc 100644
--- a/clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp
@@ -16,8 +16,8 @@ class CustomModule : public ClangTidyModule {
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {}
};
-// FIXME: could be clearer to add parameter of addCheckFactories to pass
-// Options?
+// We need to register the checks more flexibly than builtin modules. The checks
+// will changed dynamically when switching to different source file.
extern void registerCustomChecks(ClangTidyOptions const &Options,
ClangTidyCheckFactories &Factories) {
static llvm::SmallSet<llvm::SmallString<32>, 8> CustomCheckNames{};
>From b6505940716dcdc1992157b4463e005639e0ecf8 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Wed, 19 Mar 2025 09:58:10 +0800
Subject: [PATCH 10/11] Update
clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp
Co-authored-by: Baranov Victor <bar.victor.2002 at gmail.com>
---
clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp b/clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp
index 6150634fbc4bc..3fe94d8e5e941 100644
--- a/clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp
@@ -39,7 +39,7 @@ extern void registerCustomChecks(ClangTidyOptions const &Options,
} // namespace custom
-// Register the AlteraTidyModule using this statically initialized variable.
+// Register the CustomTidyModule using this statically initialized variable.
static ClangTidyModuleRegistry::Add<custom::CustomModule>
X("custom-module", "Adds custom query lint checks.");
>From b56c07c359936b91a2951b8aaf577298573037fd Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Wed, 19 Mar 2025 10:10:34 +0800
Subject: [PATCH 11/11] fix review
---
clang-tools-extra/clang-tidy/custom/QueryCheck.cpp | 6 +++---
clang-tools-extra/clang-tidy/custom/QueryCheck.h | 6 ++----
clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp | 2 +-
.../docs/clang-tidy/QueryBasedCustomChecks.rst | 6 +++---
clang-tools-extra/docs/clang-tidy/index.rst | 2 +-
.../Inputs/custom-query-check/empty-clang-tidy.yml | 2 +-
6 files changed, 11 insertions(+), 13 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/custom/QueryCheck.cpp b/clang-tools-extra/clang-tidy/custom/QueryCheck.cpp
index c69e76918f7ed..dc698d18be505 100644
--- a/clang-tools-extra/clang-tidy/custom/QueryCheck.cpp
+++ b/clang-tools-extra/clang-tidy/custom/QueryCheck.cpp
@@ -91,12 +91,12 @@ void QueryCheck::check(const MatchFinder::MatchResult &Result) {
diag(Node.getSourceRange().getBegin(), Message, Level);
}
};
- for (auto &[Name, Node] : Result.Nodes.getMap())
+ for (const auto &[Name, Node] : Result.Nodes.getMap())
Emit(Diags, Name, Node, DiagnosticIDs::Error);
- for (auto &[Name, Node] : Result.Nodes.getMap())
+ for (const auto &[Name, Node] : Result.Nodes.getMap())
Emit(Diags, Name, Node, DiagnosticIDs::Warning);
// place Note last, otherwise it will not be emitted
- for (auto &[Name, Node] : Result.Nodes.getMap())
+ for (const 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 ded4cad4e3459..1fd1d0ccb9ea0 100644
--- a/clang-tools-extra/clang-tidy/custom/QueryCheck.h
+++ b/clang-tools-extra/clang-tidy/custom/QueryCheck.h
@@ -18,10 +18,8 @@
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
+/// Implement of Clang-Query based check.
+/// Not directly visible to users.
class QueryCheck : public ClangTidyCheck {
public:
QueryCheck(llvm::StringRef Name, const ClangTidyOptions::CustomCheckValue &V,
diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
index 5784b05d2281d..0c5a7ff518653 100644
--- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
+++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
@@ -61,7 +61,7 @@ Configuration files:
globs can be specified as a list instead of a
string.
CustomChecks - Array of user defined checks based on
- clang-query syntax.
+ 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/clang-tidy/QueryBasedCustomChecks.rst b/clang-tools-extra/docs/clang-tidy/QueryBasedCustomChecks.rst
index 6efd8fe6797df..a41837a73548e 100644
--- a/clang-tools-extra/docs/clang-tidy/QueryBasedCustomChecks.rst
+++ b/clang-tools-extra/docs/clang-tidy/QueryBasedCustomChecks.rst
@@ -8,9 +8,9 @@ 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 are based on :program:`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 built-in checks.
Custom checks support inheritance from parent configurations like other
configuration items.
diff --git a/clang-tools-extra/docs/clang-tidy/index.rst b/clang-tools-extra/docs/clang-tidy/index.rst
index 83b3a4d485df5..70f67582b1f5b 100644
--- a/clang-tools-extra/docs/clang-tidy/index.rst
+++ b/clang-tools-extra/docs/clang-tidy/index.rst
@@ -294,7 +294,7 @@ An overview of all the command-line options:
globs can be specified as a list instead of a
string.
CustomChecks - Array of user defined checks based on
- clang-query syntax.
+ 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/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
index 1f16f2a33b3ce..2e9a13e720f4e 100644
--- 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
@@ -1 +1 @@
-InheritParentConfig: false
\ No newline at end of file
+InheritParentConfig: false
More information about the cfe-commits
mailing list