Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a686695
origin pr
DeNiCoN Mar 17, 2025
421b26b
Revert "origin pr"
HerrCai0907 Mar 17, 2025
6fa8f7e
impl option
HerrCai0907 Mar 17, 2025
6ab7149
impl
HerrCai0907 Mar 17, 2025
db6b315
extend func
HerrCai0907 Mar 17, 2025
dba8a8c
wip
HerrCai0907 Mar 17, 2025
0df6f7e
test
HerrCai0907 Mar 17, 2025
5bb2c6c
doc
HerrCai0907 Mar 18, 2025
64c45dc
fix comment
HerrCai0907 Mar 18, 2025
b650594
Update clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp
HerrCai0907 Mar 19, 2025
b56c07c
fix review
HerrCai0907 Mar 19, 2025
5bbf53d
Merge branch 'main' into users/ccc/clang-tidy/query-check
HerrCai0907 Mar 25, 2025
b43991f
Merge remote-tracking branch 'origin/users/ccc/clang-tidy/query-check…
HerrCai0907 May 25, 2025
b2cecb8
add CLANG_TIDY_ENABLE_QUERY_BASED_CUSTOM_CHECKS cmake config
HerrCai0907 May 25, 2025
71eeaa1
Merge branch 'main' of https://github.com/llvm/llvm-project into user…
HerrCai0907 Jun 13, 2025
8be412c
remove ERROR level
HerrCai0907 Jun 13, 2025
1367f0b
fix typo
HerrCai0907 Jun 13, 2025
595e0a6
test, doc
HerrCai0907 Jun 13, 2025
190ad52
typo
HerrCai0907 Jun 13, 2025
5500699
fix review
HerrCai0907 Jun 16, 2025
4ce48a5
Apply suggestions from code review
HerrCai0907 Jun 16, 2025
fd15b05
Apply suggestions from code review
HerrCai0907 Jun 22, 2025
73dfc6e
Merge branch 'main' into users/ccc/clang-tidy/query-check
HerrCai0907 Jul 6, 2025
dce9682
Merge remote-tracking branch 'origin/main' into users/ccc/clang-tidy/…
HerrCai0907 Aug 30, 2025
b534fe9
add --enable-experimental-custom-checks
HerrCai0907 Aug 30, 2025
a373c55
rename
HerrCai0907 Aug 30, 2025
0a99d0c
format
HerrCai0907 Aug 30, 2025
9c1828f
Merge remote-tracking branch 'origin/main' into users/ccc/clang-tidy/…
HerrCai0907 Sep 4, 2025
2a3e0f1
doc
HerrCai0907 Sep 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang-tools-extra/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ include(GNUInstallDirs)

option(CLANG_TIDY_ENABLE_STATIC_ANALYZER
"Include static analyzer checks in clang-tidy" ON)
option(CLANG_TIDY_ENABLE_QUERY_BASED_CUSTOM_CHECKS
"Enable query-based custom checks in clang-tidy" ON)

if(CLANG_INCLUDE_TESTS)
umbrella_lit_testsuite_begin(check-clang-tools)
Expand Down
5 changes: 5 additions & 0 deletions clang-tools-extra/clang-tidy/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -101,6 +102,10 @@ set(ALL_CLANG_TIDY_CHECKS
clangTidyReadabilityModule
clangTidyZirconModule
)

if(CLANG_TIDY_ENABLE_QUERY_BASED_CUSTOM_CHECKS)
list(APPEND ALL_CLANG_TIDY_CHECKS clangTidyCustomModule)
endif()
if(CLANG_TIDY_ENABLE_STATIC_ANALYZER)
list(APPEND ALL_CLANG_TIDY_CHECKS clangTidyMPIModule)
endif()
Expand Down
15 changes: 14 additions & 1 deletion clang-tools-extra/clang-tidy/ClangTidy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ LLVM_INSTANTIATE_REGISTRY(clang::tidy::ClangTidyModuleRegistry)

namespace clang::tidy {

namespace custom {
extern void registerCustomChecks(const ClangTidyOptions &O,
ClangTidyCheckFactories &Factories);
} // namespace custom

namespace {
#if CLANG_TIDY_ENABLE_STATIC_ANALYZER
static const char *AnalyzerCheckNamePrefix = "clang-analyzer-";
Expand Down Expand Up @@ -341,6 +346,9 @@ ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS)
: Context(Context), OverlayFS(std::move(OverlayFS)),
CheckFactories(new ClangTidyCheckFactories) {
#if CLANG_TIDY_ENABLE_QUERY_BASED_CUSTOM_CHECKS
custom::registerCustomChecks(Context.getOptions(), *CheckFactories);
#endif
for (ClangTidyModuleRegistry::entry E : ClangTidyModuleRegistry::entries()) {
std::unique_ptr<ClangTidyModule> Module = E.instantiate();
Module->addCheckFactories(*CheckFactories);
Expand Down Expand Up @@ -411,7 +419,9 @@ ClangTidyASTConsumerFactory::createASTConsumer(
.getCurrentWorkingDirectory();
if (WorkingDir)
Context.setCurrentBuildDirectory(WorkingDir.get());

#if CLANG_TIDY_ENABLE_QUERY_BASED_CUSTOM_CHECKS
custom::registerCustomChecks(Context.getOptions(), *CheckFactories);
#endif
std::vector<std::unique_ptr<ClangTidyCheck>> Checks =
CheckFactories->createChecksForLanguage(&Context);

Expand Down Expand Up @@ -651,6 +661,9 @@ getAllChecksAndOptions(bool AllowEnablingAnalyzerAlphaCheckers) {
std::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(), Opts),
AllowEnablingAnalyzerAlphaCheckers);
ClangTidyCheckFactories Factories;
#if CLANG_TIDY_ENABLE_QUERY_BASED_CUSTOM_CHECKS
custom::registerCustomChecks(Context.getOptions(), Factories);
#endif
for (const ClangTidyModuleRegistry::entry &Module :
ClangTidyModuleRegistry::entries()) {
Module.instantiate()->addCheckFactories(Factories);
Expand Down
7 changes: 7 additions & 0 deletions clang-tools-extra/clang-tidy/ClangTidyForceLinker.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ extern volatile int CppCoreGuidelinesModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED CppCoreGuidelinesModuleAnchorDestination =
CppCoreGuidelinesModuleAnchorSource;

#if CLANG_TIDY_ENABLE_QUERY_BASED_CUSTOM_CHECKS
// This anchor is used to force the linker to link the CustomModule.
extern volatile int CustomModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED CustomModuleAnchorDestination =
CustomModuleAnchorSource;
#endif

// This anchor is used to force the linker to link the DarwinModule.
extern volatile int DarwinModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED DarwinModuleAnchorDestination =
Expand Down
2 changes: 2 additions & 0 deletions clang-tools-extra/clang-tidy/ClangTidyModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ class ClangTidyCheckFactories {
});
}

void eraseCheck(llvm::StringRef CheckName) { Factories.erase(CheckName); }

/// Create instances of checks that are enabled.
std::vector<std::unique_ptr<ClangTidyCheck>>
createChecks(ClangTidyContext *Context) const;
Expand Down
51 changes: 50 additions & 1 deletion clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@

#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/ErrorOr.h"
#include "llvm/Support/MemoryBufferRef.h"
Expand Down Expand Up @@ -125,6 +127,51 @@ 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, "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;
Expand Down Expand Up @@ -180,6 +227,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);
}
};

Expand Down Expand Up @@ -241,7 +289,8 @@ 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(),
Expand Down
14 changes: 14 additions & 0 deletions clang-tools-extra/clang-tidy/ClangTidyOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -129,6 +130,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.
Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/clang-tidy/clang-tidy-config.h.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
#define CLANG_TIDY_CONFIG_H

#cmakedefine01 CLANG_TIDY_ENABLE_STATIC_ANALYZER
#cmakedefine01 CLANG_TIDY_ENABLE_QUERY_BASED_CUSTOM_CHECKS

#endif
22 changes: 22 additions & 0 deletions clang-tools-extra/clang-tidy/custom/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
if(CLANG_TIDY_ENABLE_QUERY_BASED_CUSTOM_CHECKS)
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
)
endif()
50 changes: 50 additions & 0 deletions clang-tools-extra/clang-tidy/custom/CustomTidyModule.cpp
Original file line number Diff line number Diff line change
@@ -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 {}
};

// 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(const ClangTidyOptions &Options,
ClangTidyCheckFactories &Factories) {
static llvm::SmallSet<llvm::SmallString<32>, 8> CustomCheckNames{};
if (!Options.CustomChecks.has_value() || Options.CustomChecks->empty())
return;
for (const llvm::SmallString<32> &Name : CustomCheckNames)
Factories.eraseCheck(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 CustomTidyModule 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; // NOLINT (misc-use-internal-linkage)

} // namespace clang::tidy
Loading
Loading