Skip to content

Commit 584af2f

Browse files
HerrCai0907DeNiCoNvbvictor
authored
reapply "[clang-tidy] support query based custom check" (#159547)
reapply #131804 and #159289 Fixed cmake link issue. --------- Co-authored-by: DeNiCoN <[email protected]> Co-authored-by: Baranov Victor <[email protected]>
1 parent 2654b51 commit 584af2f

36 files changed

+746
-36
lines changed

clang-tools-extra/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ include(GNUInstallDirs)
55

66
option(CLANG_TIDY_ENABLE_STATIC_ANALYZER
77
"Include static analyzer checks in clang-tidy" ON)
8+
option(CLANG_TIDY_ENABLE_QUERY_BASED_CUSTOM_CHECKS
9+
"Enable query-based custom checks in clang-tidy" ON)
810

911
if(CLANG_INCLUDE_TESTS)
1012
umbrella_lit_testsuite_begin(check-clang-tools)

clang-tools-extra/clang-tidy/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ add_subdirectory(bugprone)
5858
add_subdirectory(cert)
5959
add_subdirectory(concurrency)
6060
add_subdirectory(cppcoreguidelines)
61+
add_subdirectory(custom)
6162
add_subdirectory(darwin)
6263
add_subdirectory(fuchsia)
6364
add_subdirectory(google)
@@ -101,6 +102,10 @@ set(ALL_CLANG_TIDY_CHECKS
101102
clangTidyReadabilityModule
102103
clangTidyZirconModule
103104
)
105+
106+
if(CLANG_TIDY_ENABLE_QUERY_BASED_CUSTOM_CHECKS)
107+
list(APPEND ALL_CLANG_TIDY_CHECKS clangTidyCustomModule)
108+
endif()
104109
if(CLANG_TIDY_ENABLE_STATIC_ANALYZER)
105110
list(APPEND ALL_CLANG_TIDY_CHECKS clangTidyMPIModule)
106111
endif()

clang-tools-extra/clang-tidy/ClangTidy.cpp

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ LLVM_INSTANTIATE_REGISTRY(clang::tidy::ClangTidyModuleRegistry)
5353

5454
namespace clang::tidy {
5555

56+
#if CLANG_TIDY_ENABLE_QUERY_BASED_CUSTOM_CHECKS
57+
namespace custom {
58+
void (*RegisterCustomChecks)(const ClangTidyOptions &O,
59+
ClangTidyCheckFactories &Factories) = nullptr;
60+
} // namespace custom
61+
#endif
62+
5663
namespace {
5764
#if CLANG_TIDY_ENABLE_STATIC_ANALYZER
5865
#define ANALYZER_CHECK_NAME_PREFIX "clang-analyzer-"
@@ -342,6 +349,10 @@ ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
342349
IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS)
343350
: Context(Context), OverlayFS(std::move(OverlayFS)),
344351
CheckFactories(new ClangTidyCheckFactories) {
352+
#if CLANG_TIDY_ENABLE_QUERY_BASED_CUSTOM_CHECKS
353+
if (Context.canExperimentalCustomChecks() && custom::RegisterCustomChecks)
354+
custom::RegisterCustomChecks(Context.getOptions(), *CheckFactories);
355+
#endif
345356
for (ClangTidyModuleRegistry::entry E : ClangTidyModuleRegistry::entries()) {
346357
std::unique_ptr<ClangTidyModule> Module = E.instantiate();
347358
Module->addCheckFactories(*CheckFactories);
@@ -411,7 +422,10 @@ ClangTidyASTConsumerFactory::createASTConsumer(
411422
.getCurrentWorkingDirectory();
412423
if (WorkingDir)
413424
Context.setCurrentBuildDirectory(WorkingDir.get());
414-
425+
#if CLANG_TIDY_ENABLE_QUERY_BASED_CUSTOM_CHECKS
426+
if (Context.canExperimentalCustomChecks() && custom::RegisterCustomChecks)
427+
custom::RegisterCustomChecks(Context.getOptions(), *CheckFactories);
428+
#endif
415429
std::vector<std::unique_ptr<ClangTidyCheck>> Checks =
416430
CheckFactories->createChecksForLanguage(&Context);
417431

@@ -497,13 +511,13 @@ ClangTidyOptions::OptionMap ClangTidyASTConsumerFactory::getCheckOptions() {
497511
return Options;
498512
}
499513

500-
std::vector<std::string>
501-
getCheckNames(const ClangTidyOptions &Options,
502-
bool AllowEnablingAnalyzerAlphaCheckers) {
514+
std::vector<std::string> getCheckNames(const ClangTidyOptions &Options,
515+
bool AllowEnablingAnalyzerAlphaCheckers,
516+
bool ExperimentalCustomChecks) {
503517
clang::tidy::ClangTidyContext Context(
504518
std::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(),
505519
Options),
506-
AllowEnablingAnalyzerAlphaCheckers);
520+
AllowEnablingAnalyzerAlphaCheckers, false, ExperimentalCustomChecks);
507521
ClangTidyASTConsumerFactory Factory(Context);
508522
return Factory.getCheckNames();
509523
}
@@ -524,11 +538,12 @@ void filterCheckOptions(ClangTidyOptions &Options,
524538

525539
ClangTidyOptions::OptionMap
526540
getCheckOptions(const ClangTidyOptions &Options,
527-
bool AllowEnablingAnalyzerAlphaCheckers) {
541+
bool AllowEnablingAnalyzerAlphaCheckers,
542+
bool ExperimentalCustomChecks) {
528543
clang::tidy::ClangTidyContext Context(
529544
std::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(),
530545
Options),
531-
AllowEnablingAnalyzerAlphaCheckers);
546+
AllowEnablingAnalyzerAlphaCheckers, false, ExperimentalCustomChecks);
532547
ClangTidyDiagnosticConsumer DiagConsumer(Context);
533548
auto DiagOpts = std::make_unique<DiagnosticOptions>();
534549
DiagnosticsEngine DE(llvm::makeIntrusiveRefCnt<DiagnosticIDs>(), *DiagOpts,
@@ -665,15 +680,19 @@ void exportReplacements(const llvm::StringRef MainFilePath,
665680
YAML << TUD;
666681
}
667682

668-
ChecksAndOptions
669-
getAllChecksAndOptions(bool AllowEnablingAnalyzerAlphaCheckers) {
683+
ChecksAndOptions getAllChecksAndOptions(bool AllowEnablingAnalyzerAlphaCheckers,
684+
bool ExperimentalCustomChecks) {
670685
ChecksAndOptions Result;
671686
ClangTidyOptions Opts;
672687
Opts.Checks = "*";
673688
clang::tidy::ClangTidyContext Context(
674689
std::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(), Opts),
675-
AllowEnablingAnalyzerAlphaCheckers);
690+
AllowEnablingAnalyzerAlphaCheckers, false, ExperimentalCustomChecks);
676691
ClangTidyCheckFactories Factories;
692+
#if CLANG_TIDY_ENABLE_QUERY_BASED_CUSTOM_CHECKS
693+
if (ExperimentalCustomChecks && custom::RegisterCustomChecks)
694+
custom::RegisterCustomChecks(Context.getOptions(), Factories);
695+
#endif
677696
for (const ClangTidyModuleRegistry::entry &Module :
678697
ClangTidyModuleRegistry::entries()) {
679698
Module.instantiate()->addCheckFactories(Factories);

clang-tools-extra/clang-tidy/ClangTidy.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,16 @@ class ClangTidyASTConsumerFactory {
5656
/// Fills the list of check names that are enabled when the provided
5757
/// filters are applied.
5858
std::vector<std::string> getCheckNames(const ClangTidyOptions &Options,
59-
bool AllowEnablingAnalyzerAlphaCheckers);
59+
bool AllowEnablingAnalyzerAlphaCheckers,
60+
bool ExperimentalCustomChecks);
6061

6162
struct ChecksAndOptions {
6263
llvm::StringSet<> Checks;
6364
llvm::StringSet<> Options;
6465
};
6566

66-
ChecksAndOptions
67-
getAllChecksAndOptions(bool AllowEnablingAnalyzerAlphaCheckers = true);
67+
ChecksAndOptions getAllChecksAndOptions(bool AllowEnablingAnalyzerAlphaCheckers,
68+
bool ExperimentalCustomChecks);
6869

6970
/// Returns the effective check-specific options.
7071
///
@@ -74,7 +75,8 @@ getAllChecksAndOptions(bool AllowEnablingAnalyzerAlphaCheckers = true);
7475
/// Options.
7576
ClangTidyOptions::OptionMap
7677
getCheckOptions(const ClangTidyOptions &Options,
77-
bool AllowEnablingAnalyzerAlphaCheckers);
78+
bool AllowEnablingAnalyzerAlphaCheckers,
79+
bool ExperimentalCustomChecks);
7880

7981
/// Filters CheckOptions in \p Options to only include options specified in
8082
/// the \p EnabledChecks which is a sorted vector.
@@ -125,6 +127,10 @@ void exportReplacements(StringRef MainFilePath,
125127
const std::vector<ClangTidyError> &Errors,
126128
raw_ostream &OS);
127129

130+
namespace custom {
131+
extern void (*RegisterCustomChecks)(const ClangTidyOptions &O,
132+
ClangTidyCheckFactories &Factories);
133+
} // namespace custom
128134
} // end namespace tidy
129135
} // end namespace clang
130136

clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,11 +160,12 @@ ClangTidyError::ClangTidyError(StringRef CheckName,
160160

161161
ClangTidyContext::ClangTidyContext(
162162
std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider,
163-
bool AllowEnablingAnalyzerAlphaCheckers, bool EnableModuleHeadersParsing)
163+
bool AllowEnablingAnalyzerAlphaCheckers, bool EnableModuleHeadersParsing,
164+
bool ExperimentalCustomChecks)
164165
: OptionsProvider(std::move(OptionsProvider)),
165-
166166
AllowEnablingAnalyzerAlphaCheckers(AllowEnablingAnalyzerAlphaCheckers),
167-
EnableModuleHeadersParsing(EnableModuleHeadersParsing) {
167+
EnableModuleHeadersParsing(EnableModuleHeadersParsing),
168+
ExperimentalCustomChecks(ExperimentalCustomChecks) {
168169
// Before the first translation unit we can get errors related to command-line
169170
// parsing, use dummy string for the file name in this case.
170171
setCurrentFile("dummy");

clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/ADT/StringSet.h"
2020
#include "llvm/Support/Regex.h"
2121
#include <optional>
22+
#include <utility>
2223

2324
namespace clang {
2425

@@ -68,10 +69,13 @@ struct ClangTidyStats {
6869
/// \endcode
6970
class ClangTidyContext {
7071
public:
72+
ClangTidyContext(std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider)
73+
: ClangTidyContext(std::move(OptionsProvider), false, false, false) {}
7174
/// Initializes \c ClangTidyContext instance.
7275
ClangTidyContext(std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider,
73-
bool AllowEnablingAnalyzerAlphaCheckers = false,
74-
bool EnableModuleHeadersParsing = false);
76+
bool AllowEnablingAnalyzerAlphaCheckers,
77+
bool EnableModuleHeadersParsing,
78+
bool ExperimentalCustomChecks);
7579
/// Sets the DiagnosticsEngine that diag() will emit diagnostics to.
7680
// FIXME: this is required initialization, and should be a constructor param.
7781
// Fix the context -> diag engine -> consumer -> context initialization cycle.
@@ -210,6 +214,10 @@ class ClangTidyContext {
210214
return EnableModuleHeadersParsing;
211215
}
212216

217+
// whether experimental custom checks can be enabled.
218+
// enabled with `--experimental-custom-checks`
219+
bool canExperimentalCustomChecks() const { return ExperimentalCustomChecks; }
220+
213221
void setSelfContainedDiags(bool Value) { SelfContainedDiags = Value; }
214222

215223
bool areDiagsSelfContained() const { return SelfContainedDiags; }
@@ -258,6 +266,7 @@ class ClangTidyContext {
258266

259267
bool AllowEnablingAnalyzerAlphaCheckers;
260268
bool EnableModuleHeadersParsing;
269+
bool ExperimentalCustomChecks;
261270

262271
bool SelfContainedDiags = false;
263272

clang-tools-extra/clang-tidy/ClangTidyForceLinker.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ extern volatile int CppCoreGuidelinesModuleAnchorSource;
5454
static int LLVM_ATTRIBUTE_UNUSED CppCoreGuidelinesModuleAnchorDestination =
5555
CppCoreGuidelinesModuleAnchorSource;
5656

57+
#if CLANG_TIDY_ENABLE_QUERY_BASED_CUSTOM_CHECKS
58+
// This anchor is used to force the linker to link the CustomModule.
59+
extern volatile int CustomModuleAnchorSource;
60+
static int LLVM_ATTRIBUTE_UNUSED CustomModuleAnchorDestination =
61+
CustomModuleAnchorSource;
62+
#endif
63+
5764
// This anchor is used to force the linker to link the DarwinModule.
5865
extern volatile int DarwinModuleAnchorSource;
5966
static int LLVM_ATTRIBUTE_UNUSED DarwinModuleAnchorDestination =

clang-tools-extra/clang-tidy/ClangTidyModule.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ class ClangTidyCheckFactories {
6262
});
6363
}
6464

65+
void eraseCheck(llvm::StringRef CheckName) { Factories.erase(CheckName); }
66+
6567
/// Create instances of checks that are enabled.
6668
std::vector<std::unique_ptr<ClangTidyCheck>>
6769
createChecks(ClangTidyContext *Context) const;

clang-tools-extra/clang-tidy/ClangTidyOptions.cpp

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88

99
#include "ClangTidyOptions.h"
1010
#include "ClangTidyModuleRegistry.h"
11+
#include "clang/Basic/DiagnosticIDs.h"
1112
#include "clang/Basic/LLVM.h"
1213
#include "llvm/ADT/SmallString.h"
14+
#include "llvm/ADT/StringExtras.h"
1315
#include "llvm/Support/Debug.h"
1416
#include "llvm/Support/ErrorOr.h"
1517
#include "llvm/Support/MemoryBufferRef.h"
@@ -129,6 +131,51 @@ void yamlize(IO &IO, ClangTidyOptions::OptionMap &Val, bool,
129131
}
130132
}
131133

134+
namespace {
135+
struct MultiLineString {
136+
std::string &S;
137+
};
138+
} // namespace
139+
140+
template <> struct BlockScalarTraits<MultiLineString> {
141+
static void output(const MultiLineString &S, void *Ctxt, raw_ostream &OS) {
142+
OS << S.S;
143+
}
144+
static StringRef input(StringRef Str, void *Ctxt, MultiLineString &S) {
145+
S.S = Str;
146+
return "";
147+
}
148+
};
149+
150+
template <> struct ScalarEnumerationTraits<clang::DiagnosticIDs::Level> {
151+
static void enumeration(IO &IO, clang::DiagnosticIDs::Level &Level) {
152+
IO.enumCase(Level, "Warning", clang::DiagnosticIDs::Level::Warning);
153+
IO.enumCase(Level, "Note", clang::DiagnosticIDs::Level::Note);
154+
}
155+
};
156+
template <> struct SequenceElementTraits<ClangTidyOptions::CustomCheckDiag> {
157+
static const bool flow = false;
158+
};
159+
template <> struct MappingTraits<ClangTidyOptions::CustomCheckDiag> {
160+
static void mapping(IO &IO, ClangTidyOptions::CustomCheckDiag &D) {
161+
IO.mapRequired("BindName", D.BindName);
162+
MultiLineString MLS{D.Message};
163+
IO.mapRequired("Message", MLS);
164+
IO.mapOptional("Level", D.Level);
165+
}
166+
};
167+
template <> struct SequenceElementTraits<ClangTidyOptions::CustomCheckValue> {
168+
static const bool flow = false;
169+
};
170+
template <> struct MappingTraits<ClangTidyOptions::CustomCheckValue> {
171+
static void mapping(IO &IO, ClangTidyOptions::CustomCheckValue &V) {
172+
IO.mapRequired("Name", V.Name);
173+
MultiLineString MLS{V.Query};
174+
IO.mapRequired("Query", MLS);
175+
IO.mapRequired("Diagnostic", V.Diags);
176+
}
177+
};
178+
132179
struct ChecksVariant {
133180
std::optional<std::string> AsString;
134181
std::optional<std::vector<std::string>> AsVector;
@@ -184,6 +231,7 @@ template <> struct MappingTraits<ClangTidyOptions> {
184231
IO.mapOptional("InheritParentConfig", Options.InheritParentConfig);
185232
IO.mapOptional("UseColor", Options.UseColor);
186233
IO.mapOptional("SystemHeaders", Options.SystemHeaders);
234+
IO.mapOptional("CustomChecks", Options.CustomChecks);
187235
}
188236
};
189237

@@ -245,7 +293,8 @@ ClangTidyOptions &ClangTidyOptions::mergeWith(const ClangTidyOptions &Other,
245293
overrideValue(UseColor, Other.UseColor);
246294
mergeVectors(ExtraArgs, Other.ExtraArgs);
247295
mergeVectors(ExtraArgsBefore, Other.ExtraArgsBefore);
248-
296+
// FIXME: how to handle duplicate names check?
297+
mergeVectors(CustomChecks, Other.CustomChecks);
249298
for (const auto &KeyValue : Other.CheckOptions) {
250299
CheckOptions.insert_or_assign(
251300
KeyValue.getKey(),

clang-tools-extra/clang-tidy/ClangTidyOptions.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H
1010
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H
1111

12+
#include "clang/Basic/DiagnosticIDs.h"
1213
#include "llvm/ADT/IntrusiveRefCntPtr.h"
1314
#include "llvm/ADT/SmallString.h"
1415
#include "llvm/ADT/StringMap.h"
@@ -129,6 +130,19 @@ struct ClangTidyOptions {
129130
/// Key-value mapping used to store check-specific options.
130131
OptionMap CheckOptions;
131132

133+
struct CustomCheckDiag {
134+
std::string BindName;
135+
std::string Message;
136+
std::optional<DiagnosticIDs::Level> Level;
137+
};
138+
struct CustomCheckValue {
139+
std::string Name;
140+
std::string Query;
141+
llvm::SmallVector<CustomCheckDiag> Diags;
142+
};
143+
using CustomCheckValueList = llvm::SmallVector<CustomCheckValue>;
144+
std::optional<CustomCheckValueList> CustomChecks;
145+
132146
using ArgList = std::vector<std::string>;
133147

134148
/// Add extra compilation arguments to the end of the list.

0 commit comments

Comments
 (0)