Bug 1839316: part 5) Guard the "fetchpriority" attribute behind a pref. r=kershaw...
[gecko.git] / build / clang-plugin / ScopeChecker.cpp
blob962c252105b8a808609275a486cd6362f736879c
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 "ScopeChecker.h"
6 #include "CustomMatchers.h"
8 void ScopeChecker::registerMatchers(MatchFinder *AstMatcher) {
9 AstMatcher->addMatcher(varDecl().bind("node"), this);
10 AstMatcher->addMatcher(cxxNewExpr().bind("node"), this);
11 AstMatcher->addMatcher(
12 materializeTemporaryExpr(
13 unless(hasDescendant(cxxConstructExpr(allowsTemporary()))))
14 .bind("node"),
15 this);
16 AstMatcher->addMatcher(
17 callExpr(callee(functionDecl(heapAllocator()))).bind("node"), this);
20 // These enum variants determine whether an allocation has occured in the code.
21 enum AllocationVariety {
22 AV_None,
23 AV_Global,
24 AV_Automatic,
25 AV_Temporary,
26 AV_Heap,
29 // XXX Currently the Decl* in the AutomaticTemporaryMap is unused, but it
30 // probably will be used at some point in the future, in order to produce better
31 // error messages.
32 typedef DenseMap<const MaterializeTemporaryExpr *, const Decl *>
33 AutomaticTemporaryMap;
34 AutomaticTemporaryMap AutomaticTemporaries;
36 void ScopeChecker::check(const MatchFinder::MatchResult &Result) {
37 // There are a variety of different reasons why something could be allocated
38 AllocationVariety Variety = AV_None;
39 SourceLocation Loc;
40 QualType T;
41 bool IsStaticLocal = false;
43 if (const ParmVarDecl *D = Result.Nodes.getNodeAs<ParmVarDecl>("node")) {
44 if (D->hasUnparsedDefaultArg() || D->hasUninstantiatedDefaultArg()) {
45 return;
47 if (const Expr *Default = D->getDefaultArg()) {
48 if (const MaterializeTemporaryExpr *E =
49 dyn_cast<MaterializeTemporaryExpr>(Default)) {
50 // We have just found a ParmVarDecl which has, as its default argument,
51 // a MaterializeTemporaryExpr. We mark that MaterializeTemporaryExpr as
52 // automatic, by adding it to the AutomaticTemporaryMap.
53 // Reporting on this type will occur when the MaterializeTemporaryExpr
54 // is matched against.
55 AutomaticTemporaries[E] = D;
58 return;
61 // Determine the type of allocation which we detected
62 if (const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>("node")) {
63 if (D->hasGlobalStorage()) {
64 Variety = AV_Global;
65 } else {
66 Variety = AV_Automatic;
68 T = D->getType();
69 Loc = D->getBeginLoc();
70 IsStaticLocal = D->isStaticLocal();
71 } else if (const CXXNewExpr *E = Result.Nodes.getNodeAs<CXXNewExpr>("node")) {
72 // New allocates things on the heap.
73 // We don't consider placement new to do anything, as it doesn't actually
74 // allocate the storage, and thus gives us no useful information.
75 if (!isPlacementNew(E)) {
76 Variety = AV_Heap;
77 T = E->getAllocatedType();
78 Loc = E->getBeginLoc();
80 } else if (const MaterializeTemporaryExpr *E =
81 Result.Nodes.getNodeAs<MaterializeTemporaryExpr>("node")) {
82 // Temporaries can actually have varying storage durations, due to temporary
83 // lifetime extension. We consider the allocation variety of this temporary
84 // to be the same as the allocation variety of its lifetime.
86 // XXX We maybe should mark these lifetimes as being due to a temporary
87 // which has had its lifetime extended, to improve the error messages.
88 switch (E->getStorageDuration()) {
89 case SD_FullExpression: {
90 // Check if this temporary is allocated as a default argument!
91 // if it is, we want to pretend that it is automatic.
92 AutomaticTemporaryMap::iterator AutomaticTemporary =
93 AutomaticTemporaries.find(E);
94 if (AutomaticTemporary != AutomaticTemporaries.end()) {
95 Variety = AV_Automatic;
96 } else {
97 Variety = AV_Temporary;
99 } break;
100 case SD_Automatic:
101 Variety = AV_Automatic;
102 break;
103 case SD_Thread:
104 case SD_Static:
105 Variety = AV_Global;
106 break;
107 case SD_Dynamic:
108 assert(false && "I don't think that this ever should occur...");
109 Variety = AV_Heap;
110 break;
112 T = E->getType().getUnqualifiedType();
113 Loc = E->getBeginLoc();
114 } else if (const CallExpr *E = Result.Nodes.getNodeAs<CallExpr>("node")) {
115 T = E->getType()->getPointeeType();
116 if (!T.isNull()) {
117 // This will always allocate on the heap, as the heapAllocator() check
118 // was made in the matcher
119 Variety = AV_Heap;
120 Loc = E->getBeginLoc();
124 // Error messages for incorrect allocations.
125 const char *Stack = "variable of type %0 only valid on the stack";
126 const char *Global = "variable of type %0 only valid as global";
127 const char *Heap = "variable of type %0 only valid on the heap";
128 const char *NonHeap = "variable of type %0 is not valid on the heap";
129 const char *NonTemporary = "variable of type %0 is not valid in a temporary";
130 const char *Temporary = "variable of type %0 is only valid as a temporary";
131 const char *StaticLocal = "variable of type %0 is only valid as a static "
132 "local";
134 const char *StackNote =
135 "value incorrectly allocated in an automatic variable";
136 const char *GlobalNote = "value incorrectly allocated in a global variable";
137 const char *HeapNote = "value incorrectly allocated on the heap";
138 const char *TemporaryNote = "value incorrectly allocated in a temporary";
140 // Report errors depending on the annotations on the input types.
141 switch (Variety) {
142 case AV_None:
143 return;
145 case AV_Global:
146 StackClass.reportErrorIfPresent(*this, T, Loc, Stack, GlobalNote);
147 HeapClass.reportErrorIfPresent(*this, T, Loc, Heap, GlobalNote);
148 TemporaryClass.reportErrorIfPresent(*this, T, Loc, Temporary, GlobalNote);
149 if (!IsStaticLocal) {
150 StaticLocalClass.reportErrorIfPresent(*this, T, Loc, StaticLocal,
151 GlobalNote);
153 break;
155 case AV_Automatic:
156 GlobalClass.reportErrorIfPresent(*this, T, Loc, Global, StackNote);
157 HeapClass.reportErrorIfPresent(*this, T, Loc, Heap, StackNote);
158 TemporaryClass.reportErrorIfPresent(*this, T, Loc, Temporary, StackNote);
159 StaticLocalClass.reportErrorIfPresent(*this, T, Loc, StaticLocal,
160 StackNote);
161 break;
163 case AV_Temporary:
164 GlobalClass.reportErrorIfPresent(*this, T, Loc, Global, TemporaryNote);
165 HeapClass.reportErrorIfPresent(*this, T, Loc, Heap, TemporaryNote);
166 NonTemporaryClass.reportErrorIfPresent(*this, T, Loc, NonTemporary,
167 TemporaryNote);
168 StaticLocalClass.reportErrorIfPresent(*this, T, Loc, StaticLocal,
169 TemporaryNote);
170 break;
172 case AV_Heap:
173 GlobalClass.reportErrorIfPresent(*this, T, Loc, Global, HeapNote);
174 StackClass.reportErrorIfPresent(*this, T, Loc, Stack, HeapNote);
175 NonHeapClass.reportErrorIfPresent(*this, T, Loc, NonHeap, HeapNote);
176 TemporaryClass.reportErrorIfPresent(*this, T, Loc, Temporary, HeapNote);
177 StaticLocalClass.reportErrorIfPresent(*this, T, Loc, StaticLocal, HeapNote);
178 break;