Source code

Revision control

Other Tools

1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
#include <algorithm>
6
#include "CustomAttributes.h"
7
#include "plugin.h"
8
#include "clang/Frontend/FrontendPluginRegistry.h"
9
10
/* Having annotations in the AST unexpectedly impacts codegen.
11
* Ideally, we'd avoid having annotations at all, by using an API such as
12
* the one from https://reviews.llvm.org/D31338, and storing the attributes
13
* data separately from the AST on our own. Unfortunately, there is no such
14
* API currently in clang, so we must do without.
15
* We can do something similar, though, where we go through the AST before
16
* running the checks, create a mapping of AST nodes to attributes, and
17
* remove the attributes/annotations from the AST nodes.
18
* Not all declarations can be reached from the decl() AST matcher, though,
19
* so we do our best effort (getting the other declarations we look at in
20
* checks). We emit a warning when checks look at a note that still has
21
* annotations attached (aka, hasn't been seen during our first pass),
22
* so that those don't go unnoticed. (-Werror should then take care of
23
* making that an error)
24
*/
25
26
using namespace clang;
27
using namespace llvm;
28
29
static DenseMap<const Decl*, CustomAttributesSet> AttributesCache;
30
31
static CustomAttributesSet CacheAttributes(const Decl* D)
32
{
33
CustomAttributesSet attrs = {};
34
for (auto Attr : D->specific_attrs<AnnotateAttr>()) {
35
auto annotation = Attr->getAnnotation();
36
#define ATTR(a) \
37
if (annotation == #a) { \
38
attrs.has_ ## a = true; \
39
} else
40
#include "CustomAttributes.inc"
41
#undef ATTR
42
{}
43
}
44
const_cast<Decl*>(D)->dropAttr<AnnotateAttr>();
45
AttributesCache.insert(std::make_pair(D, attrs));
46
return attrs;
47
}
48
49
static void Report(const Decl* D, const char* message)
50
{
51
ASTContext& Context = D->getASTContext();
52
DiagnosticsEngine& Diag = Context.getDiagnostics();
53
unsigned ID = Diag.getDiagnosticIDs()->getCustomDiagID(
54
DiagnosticIDs::Warning, message);
55
Diag.Report(D->getBeginLoc(), ID);
56
}
57
58
CustomAttributesSet GetAttributes(const Decl* D)
59
{
60
CustomAttributesSet attrs = {};
61
if (D->hasAttr<AnnotateAttr>()) {
62
Report(D, "Declaration has unhandled annotations.");
63
attrs = CacheAttributes(D);
64
} else {
65
auto attributes = AttributesCache.find(D);
66
if (attributes != AttributesCache.end()) {
67
attrs = attributes->second;
68
}
69
}
70
return attrs;
71
}
72
73
bool hasCustomAttribute(const clang::Decl* D, CustomAttributes A)
74
{
75
CustomAttributesSet attrs = GetAttributes(D);
76
switch (A) {
77
#define ATTR(a) case a: return attrs.has_ ## a;
78
#include "CustomAttributes.inc"
79
#undef ATTR
80
}
81
return false;
82
}
83
84
class CustomAttributesMatcher : public ast_matchers::MatchFinder::MatchCallback {
85
public:
86
virtual void
87
run(const ast_matchers::MatchFinder::MatchResult &Result) final
88
{
89
if (auto D = Result.Nodes.getNodeAs<Decl>("decl")) {
90
CacheAttributes(D);
91
} else if (auto L = Result.Nodes.getNodeAs<LambdaExpr>("lambda")) {
92
CacheAttributes(L->getCallOperator());
93
CacheAttributes(L->getLambdaClass());
94
}
95
}
96
};
97
98
class CustomAttributesAction : public PluginASTAction {
99
public:
100
ASTConsumerPtr CreateASTConsumer(CompilerInstance &CI,
101
StringRef FileName) override {
102
auto& Context = CI.getASTContext();
103
auto AstMatcher = new (Context.Allocate<MatchFinder>()) MatchFinder();
104
auto Matcher = new (Context.Allocate<CustomAttributesMatcher>()) CustomAttributesMatcher();
105
AstMatcher->addMatcher(decl().bind("decl"), Matcher);
106
AstMatcher->addMatcher(lambdaExpr().bind("lambda"), Matcher);
107
return AstMatcher->newASTConsumer();
108
}
109
110
bool ParseArgs(const CompilerInstance &CI,
111
const std::vector<std::string> &Args) override {
112
return true;
113
}
114
115
ActionType getActionType() override {
116
return AddBeforeMainAction;
117
}
118
};
119
120
static FrontendPluginRegistry::Add<CustomAttributesAction> X(
121
"moz-custom-attributes",
122
"prepare custom attributes for moz-check");