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/. */
5 #include "CustomAttributes.h"
7 #include "clang/Frontend/FrontendPluginRegistry.h"
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)
26 using namespace clang
;
29 static DenseMap
<const Decl
*, CustomAttributesSet
> AttributesCache
;
31 static CustomAttributesSet
CacheAttributes(const Decl
*D
) {
32 CustomAttributesSet attrs
= {};
33 for (auto Attr
: D
->specific_attrs
<AnnotateAttr
>()) {
34 auto annotation
= Attr
->getAnnotation();
36 if (annotation == #a) { \
37 attrs.has_##a = true; \
39 #include "CustomAttributes.inc"
40 #include "external/CustomAttributes.inc"
44 const_cast<Decl
*>(D
)->dropAttr
<AnnotateAttr
>();
45 AttributesCache
.insert(std::make_pair(D
, attrs
));
50 static void Report(const Decl
*D
, const char *message
) {
51 ASTContext
&Context
= D
->getASTContext();
52 DiagnosticsEngine
&Diag
= Context
.getDiagnostics();
54 Diag
.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Warning
, message
);
55 Diag
.Report(D
->getBeginLoc(), ID
);
58 class CustomAttributesMatcher
59 : public ast_matchers::MatchFinder::MatchCallback
{
61 void run(const ast_matchers::MatchFinder::MatchResult
&Result
) final
{
62 if (auto D
= Result
.Nodes
.getNodeAs
<Decl
>("decl")) {
64 } else if (auto L
= Result
.Nodes
.getNodeAs
<LambdaExpr
>("lambda")) {
65 CacheAttributes(L
->getCallOperator());
66 CacheAttributes(L
->getLambdaClass());
71 class CustomAttributesAction
: public PluginASTAction
{
73 ASTConsumerPtr
CreateASTConsumer(CompilerInstance
&CI
,
74 StringRef FileName
) override
{
75 auto &Context
= CI
.getASTContext();
76 auto AstMatcher
= new (Context
.Allocate
<MatchFinder
>()) MatchFinder();
77 auto Matcher
= new (Context
.Allocate
<CustomAttributesMatcher
>())
78 CustomAttributesMatcher();
79 AstMatcher
->addMatcher(decl().bind("decl"), Matcher
);
80 AstMatcher
->addMatcher(lambdaExpr().bind("lambda"), Matcher
);
81 return AstMatcher
->newASTConsumer();
84 bool ParseArgs(const CompilerInstance
&CI
,
85 const std::vector
<std::string
> &Args
) override
{
89 ActionType
getActionType() override
{ return AddBeforeMainAction
; }
92 static FrontendPluginRegistry::Add
<CustomAttributesAction
>
93 X("moz-custom-attributes", "prepare custom attributes for moz-check");
96 CustomAttributesSet
GetAttributes(const Decl
*D
) {
97 CustomAttributesSet attrs
= {};
98 if (D
->hasAttr
<AnnotateAttr
>()) {
99 // If we are not in clang-tidy env push warnings, most likely we are in the
100 // build environment and this should have been done in AstMatcher -
101 // CustomAttributesMatcher
103 Report(D
, "Declaration has unhandled annotations.");
105 attrs
= CacheAttributes(D
);
107 auto attributes
= AttributesCache
.find(D
);
108 if (attributes
!= AttributesCache
.end()) {
109 attrs
= attributes
->second
;
115 bool hasCustomAttribute(const clang::Decl
*D
, CustomAttributes A
) {
116 CustomAttributesSet attrs
= GetAttributes(D
);
120 return attrs.has_##a;
121 #include "CustomAttributes.inc"
122 #include "external/CustomAttributes.inc"