Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

HerrCai0907
Copy link
Contributor

@HerrCai0907 HerrCai0907 commented Mar 18, 2025

summary

  • remove ERROR diag level, it can be done by warning as error
  • add cmake option to design enable / disable this feature
  • configuration format: I prefer that we should still use structured options

Design for Compatibility

For new field design

  1. we must make sure the required fields do not change in quiet long time.
  2. we should tolerant the unknown optional field (do not exist now) in the future.

For large project integration (3rd party)

  1. For config itself, since we can tolerant the unknown optional fields and required fields should not change, the user can decide whether to use custom check from third-party.
    2.For clang-query, if there are some break change, since the query will be parsed at check time, the user can disable the check and it will not damage the whole clang-tidy

Inherit from #123734
RFC: https://discourse.llvm.org/t/support-query-based-clang-tidy-external-check/85331

this patch introduce query based custom check by CustomChecks options.

The major improvement compared with #123734:

  1. don't need to define config yaml file in command line
  2. all behavior including InheritFromParantConfig is same as other config.
  3. change configuration schema from KV structured to List structured to make extend new function easier.
  4. Split bind string and diag message to two field to give more freedom to design query.

example:

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
int main(); // note: main function.

void bar() {
  main(); // warning: call to main function. [custom-call-main-function]
}

To make this PR don't do too much things that hard to review, here are some possible features not included in this PR

  • support language
  • support traverse
  • easier used template string in diagnostics message

Copy link
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@HerrCai0907 HerrCai0907 marked this pull request as ready for review March 18, 2025 13:56
@HerrCai0907 HerrCai0907 changed the title origin pr [clang-tidy] support query based custom check Mar 18, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 18, 2025

@llvm/pr-subscribers-clang-tidy

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

Author: Congcong Cai (HerrCai0907)

Changes

Patch is 31.84 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/131804.diff

25 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/CMakeLists.txt (+2)
  • (modified) clang-tools-extra/clang-tidy/ClangTidy.cpp (+8-1)
  • (modified) clang-tools-extra/clang-tidy/ClangTidyForceLinker.h (+5)
  • (modified) clang-tools-extra/clang-tidy/ClangTidyModule.h (+2)
  • (modified) clang-tools-extra/clang-tidy/ClangTidyOptions.cpp (+53-3)
  • (modified) clang-tools-extra/clang-tidy/ClangTidyOptions.h (+15)
  • (added) clang-tools-extra/clang-tidy/custom/CMakeLists.txt (+20)
  • (added) clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp (+50)
  • (added) clang-tools-extra/clang-tidy/custom/QueryCheck.cpp (+102)
  • (added) clang-tools-extra/clang-tidy/custom/QueryCheck.h (+42)
  • (modified) clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp (+2)
  • (modified) clang-tools-extra/docs/ReleaseNotes.rst (+3)
  • (added) clang-tools-extra/docs/clang-tidy/QueryBasedCustomChecks.rst (+57)
  • (modified) clang-tools-extra/docs/clang-tidy/index.rst (+3)
  • (added) clang-tools-extra/test/clang-tidy/checkers/custom/Inputs/clang-tidy.yml (+22)
  • (added) clang-tools-extra/test/clang-tidy/checkers/custom/Inputs/incorrect-clang-tidy.yml (+10)
  • (added) clang-tools-extra/test/clang-tidy/checkers/custom/query-incorrect-query.cpp (+3)
  • (added) clang-tools-extra/test/clang-tidy/checkers/custom/query-partially-active-check.cpp (+5)
  • (added) clang-tools-extra/test/clang-tidy/checkers/custom/query.cpp (+7)
  • (added) clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/append-clang-tidy.yml (+8)
  • (added) clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/empty-clang-tidy.yml (+1)
  • (added) clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/override-clang-tidy.yml (+11)
  • (added) clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/root-clang-tidy.yml (+11)
  • (added) clang-tools-extra/test/clang-tidy/infrastructure/Inputs/custom-query-check/vfsoverlay.yaml (+44)
  • (added) clang-tools-extra/test/clang-tidy/infrastructure/custom-query-check.cpp (+45)
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..f2a69e01a32c5 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -57,6 +57,11 @@ LLVM_INSTANTIATE_REGISTRY(clang::tidy::ClangTidyModuleRegistry)
 
 namespace clang::tidy {
 
+namespace custom {
+extern void registerCustomChecks(ClangTidyOptions const &O,
+                                 ClangTidyCheckFactories &Factories);
+} // namespace custom
+
 namespace {
 #if CLANG_TIDY_ENABLE_STATIC_ANALYZER
 static const char *AnalyzerCheckNamePrefix = "clang-analyzer-";
@@ -346,6 +351,7 @@ ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
     IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS)
     : Context(Context), OverlayFS(std::move(OverlayFS)),
       CheckFactories(new ClangTidyCheckFactories) {
+  custom::registerCustomChecks(Context.getOptions(), *CheckFactories);
   for (ClangTidyModuleRegistry::entry E : ClangTidyModuleRegistry::entries()) {
     std::unique_ptr<ClangTidyModule> Module = E.instantiate();
     Module->addCheckFactories(*CheckFactories);
@@ -416,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);
 
@@ -659,6 +665,7 @@ getAllChecksAndOptions(bool AllowEnablingAnalyzerAlphaCheckers) {
       std::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(), Opts),
       AllowEnablingAnalyzerAlphaCheckers);
   ClangTidyCheckFactories Factories;
+  custom::registerCustomChecks(Context.getOptions(), Factories);
   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/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/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
index 8bac6f161fa05..acedbd8d41faa 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
@@ -8,12 +8,12 @@
 
 #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"
 #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"
@@ -72,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;
@@ -126,6 +127,52 @@ 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 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;
+};
+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);
+    IO.mapRequired("Diagnostic", V.Diags);
+  }
+};
+
 struct ChecksVariant {
   std::optional<std::string> AsString;
   std::optional<std::vector<std::string>> AsVector;
@@ -181,6 +228,7 @@ template <> struct MappingTraits<ClangTidyOptions> {
     IO.mapOptional("InheritParentConfig", Options.InheritParentConfig);
     IO.mapOptional("UseColor", Options.UseColor);
     IO.mapOptional("SystemHeaders", Options.SystemHeaders);
+    IO.mapOptional("CustomChecks", Options.CustomChecks);
   }
 };
 
@@ -249,6 +297,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..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,6 +131,19 @@ 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;
+    llvm::SmallVector<CustomCheckDiag> Diags;
+  };
+  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.
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..e11a39f1a4ccf
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp
@@ -0,0 +1,50 @@
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#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 {
+
+class CustomModule : public ClangTidyModule {
+public:
+  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.
+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..c69e76918f7ed
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/custom/QueryCheck.cpp
@@ -0,0 +1,102 @@
+//===--- 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/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;
+
+namespace clang::tidy::custom {
+
+QueryCheck::QueryCheck(llvm::StringRef Name,
+                       const ClangTidyOptions::CustomCheckValue &V,
+                       ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context) {
+  for (const ClangTidyOptions::CustomCheckDiag &D : V.Diags) {
+    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({});
+  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) {
+  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())
+    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
new file mode 100644
index 0000000000000..ded4cad4e3459
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/custom/QueryCheck.h
@@ -0,0 +1,42 @@
+//===--- 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 "clang/Basic/DiagnosticIDs.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.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{};
+  using DiagMaps =
+      llvm::DenseMap<DiagnosticIDs::Level,
+                     llvm::StringMap<llvm::SmallVector<std::string>>>;
+  DiagMaps Diags;
+};
+
+} // namespace clang::tidy::custom
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CUSTOM_QUERYCHECK_H
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 val...
[truncated]

@HerrCai0907 HerrCai0907 force-pushed the users/ccc/clang-tidy/query-check branch from c6e485e to 64c45dc Compare March 18, 2025 14:05
@HerrCai0907
Copy link
Contributor Author

--dump-config will create incorrect YAML due to #131694.

@carlosgalvezp
Copy link
Contributor

Sorry for being late for the review. This is a major new feature of clang-tidy, so I believe it would be good to have an RFC before looking at the detailed implementation. What problem does it solve, why should clang-tidy solve it, what the API towards the user should be, etc. Should we do that?

@olologin
Copy link

olologin commented Mar 19, 2025

@carlosgalvezp Hi, I tried to explain everything here: #107680
@HerrCai0907 maybe you can reference that issue in the first post in this PR.

Copy link

github-actions bot commented Aug 30, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@HerrCai0907 HerrCai0907 force-pushed the users/ccc/clang-tidy/query-check branch from a462def to a373c55 Compare August 30, 2025 09:46
@5chmidti
Copy link
Contributor

5chmidti commented Sep 1, 2025

I won't have access to my machine for 2 weeks, so I can't try it out in the coming days, sorry. I'll see if I can do at least some review on mobile, but my general thoughts are in discourse.

For now: I think the documentation should be extended to explain that the AST is not a fixed construct, and it will change between versions (e.g., I think there was a nested namespace change recently). Also, we should encourage users to think about upstreaming checks when it makes sense

@HerrCai0907 HerrCai0907 merged commit d05b7f1 into main Sep 17, 2025
10 checks passed
@HerrCai0907 HerrCai0907 deleted the users/ccc/clang-tidy/query-check branch September 17, 2025 02:10
@llvm-ci
Copy link
Collaborator

llvm-ci commented Sep 17, 2025

LLVM Buildbot has detected a new failure on builder clang-ppc64le-rhel running on ppc64le-clang-rhel-test while building clang-tools-extra at step 5 "build-unified-tree".

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

Here is the relevant piece of the build log for the reference
Step 5 (build-unified-tree) failure: build (failure)
...
115.617 [1178/192/5292] Building CXX object tools/clang/tools/extra/clang-tidy/bugprone/CMakeFiles/obj.clangTidyBugproneModule.dir/StringviewNullptrCheck.cpp.o
115.704 [1177/192/5293] Building CXX object tools/clang/tools/extra/clang-tidy/cppcoreguidelines/CMakeFiles/obj.clangTidyCppCoreGuidelinesModule.dir/AvoidGotoCheck.cpp.o
117.501 [1176/192/5294] Building CXX object tools/clang/tools/extra/clang-tidy/cppcoreguidelines/CMakeFiles/obj.clangTidyCppCoreGuidelinesModule.dir/AvoidReferenceCoroutineParametersCheck.cpp.o
117.525 [1175/192/5295] Building CXX object tools/clang/tools/extra/clang-tidy/bugprone/CMakeFiles/obj.clangTidyBugproneModule.dir/BugproneTidyModule.cpp.o
119.325 [1174/192/5296] Building CXX object tools/clang/tools/extra/clang-tidy/cppcoreguidelines/CMakeFiles/obj.clangTidyCppCoreGuidelinesModule.dir/AvoidNonConstGlobalVariablesCheck.cpp.o
123.424 [1173/192/5297] Building AMDGPUGenPreLegalizeGICombiner.inc...
123.777 [1172/192/5298] Building AMDGPUGenMCPseudoLowering.inc...
127.626 [1171/192/5299] Building AMDGPUGenPostLegalizeGICombiner.inc...
127.697 [1170/192/5300] Building CXX object tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidy.cpp.o
128.041 [1169/192/5301] Linking CXX shared library lib/libclangTidy.so.22.0git
FAILED: lib/libclangTidy.so.22.0git 
: && /home/buildbots/llvm-external-buildbots/clang.19.1.7/bin/clang++ --gcc-toolchain=/gcc-toolchain/usr -fPIC -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual -Wno-nested-anon-types -O3 -DNDEBUG  -Wl,-z,defs -Wl,-z,nodelete -Wl,--color-diagnostics   -Wl,--gc-sections  -Xlinker --dependency-file=tools/clang/tools/extra/clang-tidy/CMakeFiles/clangTidy.dir/link.d -shared -Wl,-soname,libclangTidy.so.22.0git -o lib/libclangTidy.so.22.0git tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidy.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidyCheck.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidyModule.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidyDiagnosticConsumer.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidyOptions.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidyProfiling.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ExpandModularHeadersPPCallbacks.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/GlobList.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/NoLintDirectiveHandler.cpp.o  -Wl,-rpath,"\$ORIGIN/../lib:/home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-rhel-test/clang-ppc64le-rhel/build/lib:"  lib/libclangTooling.so.22.0git  lib/libclangStaticAnalyzerFrontend.so.22.0git  lib/libclangStaticAnalyzerCore.so.22.0git  lib/libclangFormat.so.22.0git  lib/libclangFrontend.so.22.0git  lib/libclangSerialization.so.22.0git  lib/libclangToolingCore.so.22.0git  lib/libclangRewrite.so.22.0git  lib/libclangAnalysis.so.22.0git  lib/libclangASTMatchers.so.22.0git  lib/libclangAST.so.22.0git  lib/libclangLex.so.22.0git  lib/libclangBasic.so.22.0git  lib/libLLVMFrontendOpenMP.so.22.0git  lib/libLLVMSupport.so.22.0git  -Wl,-rpath-link,/home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-rhel-test/clang-ppc64le-rhel/build/lib && :
ld.lld: error: undefined symbol: clang::tidy::custom::registerCustomChecks(clang::tidy::ClangTidyOptions const&, clang::tidy::ClangTidyCheckFactories&)
>>> referenced by ClangTidy.cpp
>>>               tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidy.cpp.o:(clang::tidy::ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(clang::tidy::ClangTidyContext&, llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>))
>>> referenced by ClangTidy.cpp
>>>               tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidy.cpp.o:(clang::tidy::ClangTidyASTConsumerFactory::createASTConsumer(clang::CompilerInstance&, llvm::StringRef))
>>> referenced by ClangTidy.cpp
>>>               tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidy.cpp.o:(clang::tidy::getAllChecksAndOptions(bool, bool))
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
129.916 [1169/191/5302] Building AMDGPUGenRegBankGICombiner.inc...
130.732 [1169/190/5303] Building AMDGPUGenMCCodeEmitter.inc...
131.290 [1169/189/5304] Building AMDGPUGenSubtargetInfo.inc...
131.571 [1169/188/5305] Building AMDGPUGenDisassemblerTables.inc...
134.412 [1169/187/5306] Building CXX object tools/clang/tools/extra/clang-tidy/cppcoreguidelines/CMakeFiles/obj.clangTidyCppCoreGuidelinesModule.dir/InterfacesGlobalInitCheck.cpp.o
136.289 [1169/186/5307] Building CXX object tools/clang/tools/extra/clang-tidy/cppcoreguidelines/CMakeFiles/obj.clangTidyCppCoreGuidelinesModule.dir/CppCoreGuidelinesTidyModule.cpp.o
136.988 [1169/185/5308] Building CXX object tools/clang/tools/extra/clang-tidy/bugprone/CMakeFiles/obj.clangTidyBugproneModule.dir/NotNullTerminatedResultCheck.cpp.o
138.482 [1169/184/5309] Building CXX object tools/clang/tools/extra/clang-tidy/cppcoreguidelines/CMakeFiles/obj.clangTidyCppCoreGuidelinesModule.dir/MisleadingCaptureDefaultByValueCheck.cpp.o
138.810 [1169/183/5310] Building CXX object tools/clang/tools/extra/clang-tidy/darwin/CMakeFiles/obj.clangTidyDarwinModule.dir/DispatchOnceNonstaticCheck.cpp.o
139.045 [1169/182/5311] Building CXX object tools/clang/tools/extra/clang-tidy/cppcoreguidelines/CMakeFiles/obj.clangTidyCppCoreGuidelinesModule.dir/InitVariablesCheck.cpp.o
139.057 [1169/181/5312] Building AMDGPUGenSearchableTables.inc...
139.447 [1169/180/5313] Building CXX object tools/clang/tools/extra/clang-tidy/darwin/CMakeFiles/obj.clangTidyDarwinModule.dir/AvoidSpinlockCheck.cpp.o
140.016 [1169/179/5314] Building CXX object tools/clang/tools/extra/clang-tidy/fuchsia/CMakeFiles/obj.clangTidyFuchsiaModule.dir/OverloadedOperatorCheck.cpp.o
140.154 [1169/178/5315] Building CXX object tools/clang/tools/extra/clang-tidy/cppcoreguidelines/CMakeFiles/obj.clangTidyCppCoreGuidelinesModule.dir/UseEnumClassCheck.cpp.o
140.206 [1169/177/5316] Building CXX object tools/clang/tools/extra/clang-tidy/cppcoreguidelines/CMakeFiles/obj.clangTidyCppCoreGuidelinesModule.dir/ProTypeUnionAccessCheck.cpp.o
140.298 [1169/176/5317] Building CXX object tools/clang/tools/extra/clang-tidy/fuchsia/CMakeFiles/obj.clangTidyFuchsiaModule.dir/DefaultArgumentsCallsCheck.cpp.o
140.383 [1169/175/5318] Building CXX object tools/clang/tools/extra/clang-tidy/fuchsia/CMakeFiles/obj.clangTidyFuchsiaModule.dir/MultipleInheritanceCheck.cpp.o
140.648 [1169/174/5319] Building CXX object tools/clang/tools/extra/clang-tidy/cppcoreguidelines/CMakeFiles/obj.clangTidyCppCoreGuidelinesModule.dir/NoMallocCheck.cpp.o
140.796 [1169/173/5320] Building CXX object tools/clang/tools/extra/clang-tidy/cppcoreguidelines/CMakeFiles/obj.clangTidyCppCoreGuidelinesModule.dir/ProTypeReinterpretCastCheck.cpp.o
140.939 [1169/172/5321] Building CXX object tools/clang/tools/extra/clang-tidy/google/CMakeFiles/obj.clangTidyGoogleModule.dir/UnnamedNamespaceInHeaderCheck.cpp.o
141.103 [1169/171/5322] Building CXX object tools/clang/tools/extra/clang-tidy/cppcoreguidelines/CMakeFiles/obj.clangTidyCppCoreGuidelinesModule.dir/ProTypeConstCastCheck.cpp.o
141.259 [1169/170/5323] Building CXX object tools/clang/tools/extra/clang-tidy/cppcoreguidelines/CMakeFiles/obj.clangTidyCppCoreGuidelinesModule.dir/ProTypeStaticCastDowncastCheck.cpp.o
141.402 [1169/169/5324] Building CXX object tools/clang/tools/extra/clang-tidy/fuchsia/CMakeFiles/obj.clangTidyFuchsiaModule.dir/StaticallyConstructedObjectsCheck.cpp.o
141.539 [1169/168/5325] Building CXX object tools/clang/tools/extra/clang-tidy/llvm/CMakeFiles/obj.clangTidyLLVMModule.dir/UseRangesCheck.cpp.o
141.590 [1169/167/5326] Building CXX object tools/clang/tools/extra/clang-tidy/fuchsia/CMakeFiles/obj.clangTidyFuchsiaModule.dir/TrailingReturnCheck.cpp.o
141.716 [1169/166/5327] Building CXX object tools/clang/tools/extra/clang-tidy/fuchsia/CMakeFiles/obj.clangTidyFuchsiaModule.dir/VirtualInheritanceCheck.cpp.o
141.758 [1169/165/5328] Building CXX object tools/clang/tools/extra/clang-tidy/hicpp/CMakeFiles/obj.clangTidyHICPPModule.dir/IgnoredRemoveResultCheck.cpp.o
141.810 [1169/164/5329] Building CXX object tools/clang/tools/extra/clang-tidy/hicpp/CMakeFiles/obj.clangTidyHICPPModule.dir/NoAssemblerCheck.cpp.o
142.036 [1169/163/5330] Building CXX object tools/clang/tools/extra/clang-tidy/google/CMakeFiles/obj.clangTidyGoogleModule.dir/DefaultArgumentsCheck.cpp.o

@peterwaller-arm
Copy link
Contributor

I see builds failing in the link, per the report from @llvm-ci above: https://lab.llvm.org/buildbot/#/builders/145/builds/9815

FAILED: lib/libclangTidy.so.22.0git 
: && /home/buildbots/llvm-external-buildbots/clang.19.1.7/bin/clang++ --gcc-toolchain=/gcc-toolchain/usr -fPIC -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual -Wno-nested-anon-types -O3 -DNDEBUG  -Wl,-z,defs -Wl,-z,nodelete -Wl,--color-diagnostics   -Wl,--gc-sections  -Xlinker --dependency-file=tools/clang/tools/extra/clang-tidy/CMakeFiles/clangTidy.dir/link.d -shared -Wl,-soname,libclangTidy.so.22.0git -o lib/libclangTidy.so.22.0git tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidy.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidyCheck.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidyModule.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidyDiagnosticConsumer.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidyOptions.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidyProfiling.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ExpandModularHeadersPPCallbacks.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/GlobList.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/NoLintDirectiveHandler.cpp.o  -Wl,-rpath,"\$ORIGIN/../lib:/home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-rhel-test/clang-ppc64le-rhel/build/lib:"  lib/libclangTooling.so.22.0git  lib/libclangStaticAnalyzerFrontend.so.22.0git  lib/libclangStaticAnalyzerCore.so.22.0git  lib/libclangFormat.so.22.0git  lib/libclangFrontend.so.22.0git  lib/libclangSerialization.so.22.0git  lib/libclangToolingCore.so.22.0git  lib/libclangRewrite.so.22.0git  lib/libclangAnalysis.so.22.0git  lib/libclangASTMatchers.so.22.0git  lib/libclangAST.so.22.0git  lib/libclangLex.so.22.0git  lib/libclangBasic.so.22.0git  lib/libLLVMFrontendOpenMP.so.22.0git  lib/libLLVMSupport.so.22.0git  -Wl,-rpath-link,/home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-rhel-test/clang-ppc64le-rhel/build/lib && :
ld.lld: error: undefined symbol: clang::tidy::custom::registerCustomChecks(clang::tidy::ClangTidyOptions const&, clang::tidy::ClangTidyCheckFactories&)
>>> referenced by ClangTidy.cpp
>>>               tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidy.cpp.o:(clang::tidy::ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(clang::tidy::ClangTidyContext&, llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>))
>>> referenced by ClangTidy.cpp
>>>               tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidy.cpp.o:(clang::tidy::ClangTidyASTConsumerFactory::createASTConsumer(clang::CompilerInstance&, llvm::StringRef))
>>> referenced by ClangTidy.cpp
>>>               tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidy.cpp.o:(clang::tidy::getAllChecksAndOptions(bool, bool))
clang++: error: linker command failed with exit code 1 (use -v to see invocation)

@llvm-ci
Copy link
Collaborator

llvm-ci commented Sep 17, 2025

LLVM Buildbot has detected a new failure on builder sanitizer-x86_64-linux-fast running on sanitizer-buildbot3 while building clang-tools-extra at step 2 "annotate".

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

Here is the relevant piece of the build log for the reference
Step 2 (annotate) failure: 'python ../sanitizer_buildbot/sanitizers/zorg/buildbot/builders/sanitizers/buildbot_selector.py' (failure)
...
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:530: note: using lld-link: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/lld-link
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:530: note: using ld64.lld: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/ld64.lld
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:530: note: using wasm-ld: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/wasm-ld
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:530: note: using ld.lld: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/ld.lld
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:530: note: using lld-link: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/lld-link
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:530: note: using ld64.lld: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/ld64.lld
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:530: note: using wasm-ld: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/wasm-ld
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/main.py:74: note: The test suite configuration requested an individual test timeout of 0 seconds but a timeout of 900 seconds was requested on the command line. Forcing timeout to be 900 seconds.
-- Testing: 91994 tests, 64 workers --
Testing:  0.. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90.
FAIL: LLVM :: ExecutionEngine/JITLink/x86-64/MachO_weak_references.s (68448 of 91994)
******************** TEST 'LLVM :: ExecutionEngine/JITLink/x86-64/MachO_weak_references.s' FAILED ********************
Exit Code: -6

Command Output (stdout):
--
# RUN: at line 1
rm -rf /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/test/ExecutionEngine/JITLink/x86-64/Output/MachO_weak_references.s.tmp && mkdir -p /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/test/ExecutionEngine/JITLink/x86-64/Output/MachO_weak_references.s.tmp
# executed command: rm -rf /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/test/ExecutionEngine/JITLink/x86-64/Output/MachO_weak_references.s.tmp
# note: command had no output on stdout or stderr
# executed command: mkdir -p /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/test/ExecutionEngine/JITLink/x86-64/Output/MachO_weak_references.s.tmp
# note: command had no output on stdout or stderr
# RUN: at line 2
/home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/llvm-mc -triple=x86_64-apple-macosx10.9 -filetype=obj -o /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/test/ExecutionEngine/JITLink/x86-64/Output/MachO_weak_references.s.tmp/macho_weak_refs.o /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/test/ExecutionEngine/JITLink/x86-64/MachO_weak_references.s
# executed command: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/llvm-mc -triple=x86_64-apple-macosx10.9 -filetype=obj -o /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/test/ExecutionEngine/JITLink/x86-64/Output/MachO_weak_references.s.tmp/macho_weak_refs.o /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/test/ExecutionEngine/JITLink/x86-64/MachO_weak_references.s
# note: command had no output on stdout or stderr
# RUN: at line 3
/home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/llvm-jitlink -noexec -check-name=jitlink-check-bar-present -abs bar=0x1 -check=/home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/test/ExecutionEngine/JITLink/x86-64/MachO_weak_references.s /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/test/ExecutionEngine/JITLink/x86-64/Output/MachO_weak_references.s.tmp/macho_weak_refs.o
# executed command: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/llvm-jitlink -noexec -check-name=jitlink-check-bar-present -abs bar=0x1 -check=/home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/test/ExecutionEngine/JITLink/x86-64/MachO_weak_references.s /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/test/ExecutionEngine/JITLink/x86-64/Output/MachO_weak_references.s.tmp/macho_weak_refs.o
# note: command had no output on stdout or stderr
# RUN: at line 4
/home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/llvm-jitlink -noexec -check-name=jitlink-check-bar-absent -check=/home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/test/ExecutionEngine/JITLink/x86-64/MachO_weak_references.s /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/test/ExecutionEngine/JITLink/x86-64/Output/MachO_weak_references.s.tmp/macho_weak_refs.o
# executed command: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/llvm-jitlink -noexec -check-name=jitlink-check-bar-absent -check=/home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/test/ExecutionEngine/JITLink/x86-64/MachO_weak_references.s /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/test/ExecutionEngine/JITLink/x86-64/Output/MachO_weak_references.s.tmp/macho_weak_refs.o
# .---command stderr------------
# | libc++abi: Pure virtual function called!
# `-----------------------------
# error: command failed with exit status: -6

--

********************
Testing:  0.. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90.. 
Slowest Tests:
--------------------------------------------------------------------------
399.65s: LLVM :: CodeGen/AMDGPU/sched-group-barrier-pipeline-solver.mir
281.77s: Clang :: Driver/fsanitize.c
211.82s: Clang :: Preprocessor/riscv-target-features.c
190.96s: LLVM :: CodeGen/AMDGPU/amdgcn.bitcast.1024bit.ll
180.93s: Clang :: OpenMP/target_update_codegen.cpp
Step 10 (stage2/asan_ubsan check) failure: stage2/asan_ubsan check (failure)
...
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:530: note: using lld-link: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/lld-link
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:530: note: using ld64.lld: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/ld64.lld
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:530: note: using wasm-ld: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/wasm-ld
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:530: note: using ld.lld: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/ld.lld
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:530: note: using lld-link: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/lld-link
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:530: note: using ld64.lld: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/ld64.lld
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/llvm/config.py:530: note: using wasm-ld: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/wasm-ld
llvm-lit: /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/utils/lit/lit/main.py:74: note: The test suite configuration requested an individual test timeout of 0 seconds but a timeout of 900 seconds was requested on the command line. Forcing timeout to be 900 seconds.
-- Testing: 91994 tests, 64 workers --
Testing:  0.. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90.
FAIL: LLVM :: ExecutionEngine/JITLink/x86-64/MachO_weak_references.s (68448 of 91994)
******************** TEST 'LLVM :: ExecutionEngine/JITLink/x86-64/MachO_weak_references.s' FAILED ********************
Exit Code: -6

Command Output (stdout):
--
# RUN: at line 1
rm -rf /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/test/ExecutionEngine/JITLink/x86-64/Output/MachO_weak_references.s.tmp && mkdir -p /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/test/ExecutionEngine/JITLink/x86-64/Output/MachO_weak_references.s.tmp
# executed command: rm -rf /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/test/ExecutionEngine/JITLink/x86-64/Output/MachO_weak_references.s.tmp
# note: command had no output on stdout or stderr
# executed command: mkdir -p /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/test/ExecutionEngine/JITLink/x86-64/Output/MachO_weak_references.s.tmp
# note: command had no output on stdout or stderr
# RUN: at line 2
/home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/llvm-mc -triple=x86_64-apple-macosx10.9 -filetype=obj -o /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/test/ExecutionEngine/JITLink/x86-64/Output/MachO_weak_references.s.tmp/macho_weak_refs.o /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/test/ExecutionEngine/JITLink/x86-64/MachO_weak_references.s
# executed command: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/llvm-mc -triple=x86_64-apple-macosx10.9 -filetype=obj -o /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/test/ExecutionEngine/JITLink/x86-64/Output/MachO_weak_references.s.tmp/macho_weak_refs.o /home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/test/ExecutionEngine/JITLink/x86-64/MachO_weak_references.s
# note: command had no output on stdout or stderr
# RUN: at line 3
/home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/llvm-jitlink -noexec -check-name=jitlink-check-bar-present -abs bar=0x1 -check=/home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/test/ExecutionEngine/JITLink/x86-64/MachO_weak_references.s /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/test/ExecutionEngine/JITLink/x86-64/Output/MachO_weak_references.s.tmp/macho_weak_refs.o
# executed command: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/llvm-jitlink -noexec -check-name=jitlink-check-bar-present -abs bar=0x1 -check=/home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/test/ExecutionEngine/JITLink/x86-64/MachO_weak_references.s /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/test/ExecutionEngine/JITLink/x86-64/Output/MachO_weak_references.s.tmp/macho_weak_refs.o
# note: command had no output on stdout or stderr
# RUN: at line 4
/home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/llvm-jitlink -noexec -check-name=jitlink-check-bar-absent -check=/home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/test/ExecutionEngine/JITLink/x86-64/MachO_weak_references.s /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/test/ExecutionEngine/JITLink/x86-64/Output/MachO_weak_references.s.tmp/macho_weak_refs.o
# executed command: /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/bin/llvm-jitlink -noexec -check-name=jitlink-check-bar-absent -check=/home/b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/test/ExecutionEngine/JITLink/x86-64/MachO_weak_references.s /home/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan_ubsan/test/ExecutionEngine/JITLink/x86-64/Output/MachO_weak_references.s.tmp/macho_weak_refs.o
# .---command stderr------------
# | libc++abi: Pure virtual function called!
# `-----------------------------
# error: command failed with exit status: -6

--

********************
Testing:  0.. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90.. 
Slowest Tests:
--------------------------------------------------------------------------
399.65s: LLVM :: CodeGen/AMDGPU/sched-group-barrier-pipeline-solver.mir
281.77s: Clang :: Driver/fsanitize.c
211.82s: Clang :: Preprocessor/riscv-target-features.c
190.96s: LLVM :: CodeGen/AMDGPU/amdgcn.bitcast.1024bit.ll
180.93s: Clang :: OpenMP/target_update_codegen.cpp

ingomueller-net added a commit that referenced this pull request Sep 17, 2025
This PR provides a quick fix for the bazel builds that got broken by
#131804. That PR introduced a new CMake option that enables custom
clang-tidy checks that are provided by cmake-query. This PR disables
those checks, which is the minimal fix. A more proper fix would
introduce a new `custom` check that is added to the tool if a particular
flag value is set; however, the library depends on clang-query, which
isn't part of the bazel build, yet, and I don't want to spend the time
now to make all of that work as well. The discussion in the PR provides
my current state in case somebody wants to pick up that work.

Signed-off-by: Ingo Müller <[email protected]>
@HerrCai0907
Copy link
Contributor Author

I see builds failing in the link, per the report from @llvm-ci above: https://lab.llvm.org/buildbot/#/builders/145/builds/9815

FAILED: lib/libclangTidy.so.22.0git 
: && /home/buildbots/llvm-external-buildbots/clang.19.1.7/bin/clang++ --gcc-toolchain=/gcc-toolchain/usr -fPIC -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual -Wno-nested-anon-types -O3 -DNDEBUG  -Wl,-z,defs -Wl,-z,nodelete -Wl,--color-diagnostics   -Wl,--gc-sections  -Xlinker --dependency-file=tools/clang/tools/extra/clang-tidy/CMakeFiles/clangTidy.dir/link.d -shared -Wl,-soname,libclangTidy.so.22.0git -o lib/libclangTidy.so.22.0git tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidy.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidyCheck.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidyModule.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidyDiagnosticConsumer.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidyOptions.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidyProfiling.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ExpandModularHeadersPPCallbacks.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/GlobList.cpp.o tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/NoLintDirectiveHandler.cpp.o  -Wl,-rpath,"\$ORIGIN/../lib:/home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-rhel-test/clang-ppc64le-rhel/build/lib:"  lib/libclangTooling.so.22.0git  lib/libclangStaticAnalyzerFrontend.so.22.0git  lib/libclangStaticAnalyzerCore.so.22.0git  lib/libclangFormat.so.22.0git  lib/libclangFrontend.so.22.0git  lib/libclangSerialization.so.22.0git  lib/libclangToolingCore.so.22.0git  lib/libclangRewrite.so.22.0git  lib/libclangAnalysis.so.22.0git  lib/libclangASTMatchers.so.22.0git  lib/libclangAST.so.22.0git  lib/libclangLex.so.22.0git  lib/libclangBasic.so.22.0git  lib/libLLVMFrontendOpenMP.so.22.0git  lib/libLLVMSupport.so.22.0git  -Wl,-rpath-link,/home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-rhel-test/clang-ppc64le-rhel/build/lib && :
ld.lld: error: undefined symbol: clang::tidy::custom::registerCustomChecks(clang::tidy::ClangTidyOptions const&, clang::tidy::ClangTidyCheckFactories&)
>>> referenced by ClangTidy.cpp
>>>               tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidy.cpp.o:(clang::tidy::ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(clang::tidy::ClangTidyContext&, llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>))
>>> referenced by ClangTidy.cpp
>>>               tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidy.cpp.o:(clang::tidy::ClangTidyASTConsumerFactory::createASTConsumer(clang::CompilerInstance&, llvm::StringRef))
>>> referenced by ClangTidy.cpp
>>>               tools/clang/tools/extra/clang-tidy/CMakeFiles/obj.clangTidy.dir/ClangTidy.cpp.o:(clang::tidy::getAllChecksAndOptions(bool, bool))
clang++: error: linker command failed with exit code 1 (use -v to see invocation)

I don't find any cmake build issue. According to error message, it looks like clangTidyCustomModule does not be linked. Are there anyone can reproduce this build issue?

@ingomueller-net
Copy link
Contributor

I can reproduce locally. This only happens with the CMake build, so it is unrelated to #159289, which fixed the bazel build. I'll take a look into the CMake targets now.

ingomueller-net added a commit that referenced this pull request Sep 17, 2025
ingomueller-net added a commit that referenced this pull request Sep 17, 2025
ingomueller-net added a commit that referenced this pull request Sep 17, 2025
Reverts #131804.

This breaks a build bot; see discussion in the original PR. I could
reproduce this problem locally. The problem is that the original PR
makes use of `registerCustomChecks` in `ClangTidy.cpp` but does not add
the new custom module to the dependencies of the target that builds that
file. Adding the dependency would create a cyclic dependency, so the fix
doesn't seem obvious. See details in the PR description.
ingomueller-net added a commit that referenced this pull request Sep 17, 2025
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Sep 17, 2025
…59380)

Reverts llvm/llvm-project#131804.

This breaks a build bot; see discussion in the original PR. I could
reproduce this problem locally. The problem is that the original PR
makes use of `registerCustomChecks` in `ClangTidy.cpp` but does not add
the new custom module to the dependencies of the target that builds that
file. Adding the dependency would create a cyclic dependency, so the fix
doesn't seem obvious. See details in the PR description.
@HerrCai0907 HerrCai0907 restored the users/ccc/clang-tidy/query-check branch September 18, 2025 09:04
HerrCai0907 added a commit that referenced this pull request Sep 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.