-
Notifications
You must be signed in to change notification settings - Fork 0
/
tool.cpp
109 lines (93 loc) · 4.11 KB
/
tool.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <memory>
#include <functional>
#include <algorithm>
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
// Declares llvm::cl::extrahelp.
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "clang/Tooling/Tooling.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "DisallowGlobals.h"
#include "DisallowNewDelete.h"
#include "DisallowNonAbstract.h"
#include "DisallowCoupling.h"
#include "ResultPrinter.h"
using namespace clang;
using namespace clang::ast_matchers;
using namespace clang::tooling;
using namespace llvm;
using namespace std::placeholders;
// Apply a custom category to all command-line options so that they are the
// only ones displayed.
static llvm::cl::OptionCategory NoGlobalStyleCategory("noglob options");
// CommonOptionsParser declares HelpMessage with a description of the common
// command-line options related to the compilation database and input files.
// It's nice to have this help message in all tools.
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
// A help message for this specific tool can be added afterwards.
static cl::extrahelp MoreHelp
("\nDetect\n"
"- Direct mutation of globals from checked code\n"
"- Uses of bare new and delete operators\n"
"- Non-abstract class or struct types in abstract-only namespaces\n"
"- Coupling to non-abstract classes and structs in coupling-disallwed\n"
" namespaces\n");
static cl::opt<bool> Debug
("debug",
cl::desc("Enable diagnostic output for the tool itself"),
cl::cat(NoGlobalStyleCategory));
static cl::opt<bool> Werror
("Werror",
cl::desc("Promote warnings to errors"),
cl::cat(NoGlobalStyleCategory));
static cl::list<std::string> analyze_paths
("analyze-path",
cl::desc("Path of files to analyze. Files not matching one of these prefixes will be ignored."),
cl::cat(NoGlobalStyleCategory));
static cl::list<std::string> abstract_namespaces
("abstract-namespace",
cl::desc("Namespace designated to contain only abstract classes and structs."),
cl::cat(NoGlobalStyleCategory));
static cl::list<std::string> banned_namespaces
("coupling-banned",
cl::desc("Namespace designated to be banned from coupling. References to classes and structs in this namespace are banned."),
cl::cat(NoGlobalStyleCategory));
int main(int argc, const char **argv) {
CommonOptionsParser OptionsParser(argc, argv, NoGlobalStyleCategory);
ClangTool Tool(OptionsParser.getCompilations(),
OptionsParser.getSourcePathList());
MatchFinder finder;
// Snarf abstract-only namespaces from the environment.
std::vector<std::string> abstract_namespaces_v, banned_namespaces_v;
std::copy(abstract_namespaces.begin(), abstract_namespaces.end(), std::back_inserter(abstract_namespaces_v));
std::copy(banned_namespaces.begin(), banned_namespaces.end(), std::back_inserter(banned_namespaces_v));
std::unique_ptr<RuleCheckerBase> rules[] = {
std::unique_ptr<DisallowNew>(new DisallowNew()),
std::unique_ptr<DisallowDelete>(new DisallowDelete()),
std::unique_ptr<DisallowGlobals>(new DisallowGlobals()),
std::unique_ptr<DisallowNonAbstract>(new DisallowNonAbstract(abstract_namespaces_v)),
std::unique_ptr<DisallowCoupling>(new DisallowCoupling(banned_namespaces_v))
};
size_t rules_size = sizeof(rules) / sizeof(rules[0]);
auto rules_begin = &rules[0];
auto rules_end = &rules[rules_size];
std::vector<std::string> analyze_paths_v;
std::copy(analyze_paths.begin(), analyze_paths.end(), std::back_inserter(analyze_paths_v));
for (size_t i = 0; i < sizeof(rules) / sizeof(rules[0]); ++i) {
auto &rule = rules[i];
rule->setAnalyzePaths(analyze_paths_v);
rule->SetupMatches(finder);
rule->getPrinter().setDebug(Debug.getValue());
}
#ifndef NDEBUG
llvm::DebugFlag = Debug.getValue();
#endif
return Tool.run(newFrontendActionFactory(&finder).get()) ||
(Werror.getValue() &&
std::any_of
(rules_begin, rules_end,
[] (const std::unique_ptr<RuleCheckerBase> &rule) {
return rule->getPrinter().getWarnings();
}));
}