Skip to content

Commit dba8a8c

Browse files
committed
wip
1 parent db6b315 commit dba8a8c

File tree

10 files changed

+114
-35
lines changed

10 files changed

+114
-35
lines changed

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ LLVM_INSTANTIATE_REGISTRY(clang::tidy::ClangTidyModuleRegistry)
5858
namespace clang::tidy {
5959

6060
namespace custom {
61-
extern void setOptions(ClangTidyOptions const &O);
61+
extern void registerCustomChecks(ClangTidyOptions const &O,
62+
ClangTidyCheckFactories &Factories);
6263
} // namespace custom
6364

6465
namespace {
@@ -350,7 +351,7 @@ ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
350351
IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS)
351352
: Context(Context), OverlayFS(std::move(OverlayFS)),
352353
CheckFactories(new ClangTidyCheckFactories) {
353-
custom::setOptions(Context.getOptions());
354+
custom::registerCustomChecks(Context.getOptions(), *CheckFactories);
354355
for (ClangTidyModuleRegistry::entry E : ClangTidyModuleRegistry::entries()) {
355356
std::unique_ptr<ClangTidyModule> Module = E.instantiate();
356357
Module->addCheckFactories(*CheckFactories);
@@ -421,7 +422,7 @@ ClangTidyASTConsumerFactory::createASTConsumer(
421422
.getCurrentWorkingDirectory();
422423
if (WorkingDir)
423424
Context.setCurrentBuildDirectory(WorkingDir.get());
424-
425+
custom::registerCustomChecks(Context.getOptions(), *CheckFactories);
425426
std::vector<std::unique_ptr<ClangTidyCheck>> Checks =
426427
CheckFactories->createChecksForLanguage(&Context);
427428

@@ -664,7 +665,7 @@ getAllChecksAndOptions(bool AllowEnablingAnalyzerAlphaCheckers) {
664665
std::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(), Opts),
665666
AllowEnablingAnalyzerAlphaCheckers);
666667
ClangTidyCheckFactories Factories;
667-
custom::setOptions(Context.getOptions());
668+
custom::registerCustomChecks(Context.getOptions(), Factories);
668669
for (const ClangTidyModuleRegistry::entry &Module :
669670
ClangTidyModuleRegistry::entries()) {
670671
Module.instantiate()->addCheckFactories(Factories);

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 erase(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/custom/CustomTidyModule.cpp

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,40 @@
33
#include "../ClangTidyModuleRegistry.h"
44
#include "../ClangTidyOptions.h"
55
#include "QueryCheck.h"
6+
#include "llvm/ADT/SmallSet.h"
7+
#include "llvm/ADT/SmallString.h"
8+
#include "llvm/ADT/StringRef.h"
69
#include <memory>
710

811
namespace clang::tidy {
912
namespace custom {
1013

11-
// FIXME: could be clearer to add parameter of addCheckFactories to pass
12-
// Options?
13-
static ClangTidyOptions const *Options = nullptr;
14-
extern void setOptions(ClangTidyOptions const &O) { Options = &O; }
15-
1614
class CustomModule : public ClangTidyModule {
1715
public:
18-
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
19-
if (Options == nullptr || !Options->CustomChecks.has_value() ||
20-
Options->CustomChecks->empty())
21-
return;
22-
for (const ClangTidyOptions::CustomCheckValue &V :
23-
Options->CustomChecks.value()) {
24-
CheckFactories.registerCheckFactory(
25-
// add custom- prefix to avoid conflicts with builtin checks
26-
"custom-" + V.Name,
27-
[&V](llvm::StringRef Name, ClangTidyContext *Context) {
28-
return std::make_unique<custom::QueryCheck>(Name, V, Context);
29-
});
30-
}
31-
}
16+
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {}
3217
};
3318

19+
// FIXME: could be clearer to add parameter of addCheckFactories to pass
20+
// Options?
21+
extern void registerCustomChecks(ClangTidyOptions const &Options,
22+
ClangTidyCheckFactories &Factories) {
23+
static llvm::SmallSet<llvm::SmallString<32>, 8> CustomCheckNames{};
24+
if (!Options.CustomChecks.has_value() || Options.CustomChecks->empty())
25+
return;
26+
for (llvm::SmallString<32> const &Name : CustomCheckNames)
27+
Factories.erase(Name);
28+
for (const ClangTidyOptions::CustomCheckValue &V :
29+
Options.CustomChecks.value()) {
30+
llvm::SmallString<32> Name = llvm::StringRef{"custom-" + V.Name};
31+
Factories.registerCheckFactory(
32+
// add custom- prefix to avoid conflicts with builtin checks
33+
Name, [&V](llvm::StringRef Name, ClangTidyContext *Context) {
34+
return std::make_unique<custom::QueryCheck>(Name, V, Context);
35+
});
36+
CustomCheckNames.insert(std::move(Name));
37+
}
38+
}
39+
3440
} // namespace custom
3541

3642
// Register the AlteraTidyModule using this statically initialized variable.

clang-tools-extra/clang-tidy/custom/QueryCheck.cpp

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99
#include "QueryCheck.h"
1010
#include "../../clang-query/Query.h"
1111
#include "../../clang-query/QueryParser.h"
12+
#include "clang/ASTMatchers/ASTMatchers.h"
1213
#include "clang/ASTMatchers/Dynamic/VariantValue.h"
1314
#include "clang/Basic/DiagnosticIDs.h"
1415
#include "llvm/ADT/SmallVector.h"
1516
#include "llvm/ADT/StringRef.h"
17+
#include <string>
1618

1719
using namespace clang::ast_matchers;
1820

@@ -23,9 +25,16 @@ QueryCheck::QueryCheck(llvm::StringRef Name,
2325
ClangTidyContext *Context)
2426
: ClangTidyCheck(Name, Context) {
2527
for (const ClangTidyOptions::CustomCheckDiag &D : V.Diags) {
26-
auto It = Diags.try_emplace(D.BindName, llvm::SmallVector<Diag>{}).first;
27-
It->second.emplace_back(
28-
Diag{D.Message, D.Level.value_or(DiagnosticIDs::Warning)});
28+
auto DiagnosticIdIt =
29+
Diags
30+
.try_emplace(D.Level.value_or(DiagnosticIDs::Warning),
31+
llvm::StringMap<llvm::SmallVector<std::string>>{})
32+
.first;
33+
auto DiagMessageIt =
34+
DiagnosticIdIt->getSecond()
35+
.try_emplace(D.BindName, llvm::SmallVector<std::string>{})
36+
.first;
37+
DiagMessageIt->second.emplace_back(D.Message);
2938
}
3039

3140
clang::query::QuerySession QS({});
@@ -71,10 +80,23 @@ void QueryCheck::registerMatchers(MatchFinder *Finder) {
7180
}
7281

7382
void QueryCheck::check(const MatchFinder::MatchResult &Result) {
83+
auto Emit = [this](DiagMaps const &DiagMaps, std::string const &BindName,
84+
DynTypedNode const &Node, DiagnosticIDs::Level Level) {
85+
if (!DiagMaps.contains(Level))
86+
return;
87+
auto &DiagMap = DiagMaps.at(Level);
88+
if (!DiagMap.contains(BindName))
89+
return;
90+
for (const std::string &Message : DiagMap.at(BindName)) {
91+
diag(Node.getSourceRange().getBegin(), Message, Level);
92+
}
93+
};
94+
for (auto &[Name, Node] : Result.Nodes.getMap())
95+
Emit(Diags, Name, Node, DiagnosticIDs::Error);
7496
for (auto &[Name, Node] : Result.Nodes.getMap())
75-
if (Diags.contains(Name))
76-
for (const Diag &D : Diags[Name])
77-
diag(D.Message, D.Level) << Node.getSourceRange();
97+
Emit(Diags, Name, Node, DiagnosticIDs::Warning);
98+
// place Note last, otherwise it will not be emitted
99+
for (auto &[Name, Node] : Result.Nodes.getMap())
100+
Emit(Diags, Name, Node, DiagnosticIDs::Note);
78101
}
79-
80102
} // namespace clang::tidy::custom

clang-tools-extra/clang-tidy/custom/QueryCheck.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
#include "../ClangTidyCheck.h"
1313
#include "clang/ASTMatchers/Dynamic/VariantValue.h"
14+
#include "clang/Basic/DiagnosticIDs.h"
15+
#include "llvm/ADT/DenseMap.h"
1416
#include "llvm/ADT/SmallVector.h"
1517
#include "llvm/ADT/StringMap.h"
1618

@@ -29,11 +31,10 @@ class QueryCheck : public ClangTidyCheck {
2931

3032
private:
3133
llvm::SmallVector<ast_matchers::dynamic::DynTypedMatcher> Matchers{};
32-
struct Diag {
33-
std::string Message;
34-
DiagnosticIDs::Level Level;
35-
};
36-
llvm::StringMap<llvm::SmallVector<Diag>> Diags{};
34+
using DiagMaps =
35+
llvm::DenseMap<DiagnosticIDs::Level,
36+
llvm::StringMap<llvm::SmallVector<std::string>>>;
37+
DiagMaps Diags;
3738
};
3839

3940
} // namespace clang::tidy::custom
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
CustomeChecks:
2+
- Name: test-diag-level
3+
Query: |
4+
match varDecl(
5+
hasType(asString("long")),
6+
hasTypeLoc(typeLoc().bind("long"))
7+
).bind("decl")
8+
Diagnostic:
9+
- BindName: long
10+
Message: use 'int' instead of 'long'
11+
Level: Warning
12+
- BindName: decl
13+
Message: declaration of 'long'
14+
Level: Note
15+
- Name: test-let-bind
16+
Query: |
17+
let expr varDecl(isStaticStorageClass()).bind("vd")
18+
match expr
19+
Diagnostic:
20+
- BindName: vd
21+
Message: find static variable
22+
Level: Warning
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CustomeChecks:
2+
- Name: test-let-bind
3+
Query: |
4+
let expr varDecl(isStaticStorageClass()).bind("vd")
5+
match expr
6+
set output print
7+
Diagnostic:
8+
- BindName: vd
9+
Message: find static variable
10+
Level: Warning
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// RUN: %check_clang_tidy %s custom-* %t --config-file=%S/Inputs/incorrect-clang-tidy.yml
2+
3+
// CHECK-MESSAGES: warning: unsupported querry kind [clang-tidy-config]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// RUN: %check_clang_tidy %s custom-test-let-bind %t --config-file=%S/Inputs/clang-tidy.yml
2+
3+
extern long E;
4+
static int S;
5+
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: find static variable [custom-test-let-bind]
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// RUN: %check_clang_tidy %s custom-* %t --config-file=%S/Inputs/clang-tidy.yml
2+
3+
extern long E;
4+
// CHECK-MESSAGES: [[@LINE-1]]:8: warning: use 'int' instead of 'long' [custom-test-diag-level]
5+
// CHECK-MESSAGES: [[@LINE-2]]:1: note: declaration of 'long'
6+
static int S;
7+
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: find static variable [custom-test-let-bind]

0 commit comments

Comments
 (0)