1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | #ifndef LLVM_CLANG_SEMA_DELAYEDDIAGNOSTIC_H |
22 | #define LLVM_CLANG_SEMA_DELAYEDDIAGNOSTIC_H |
23 | |
24 | #include "clang/AST/DeclAccessPair.h" |
25 | #include "clang/AST/DeclBase.h" |
26 | #include "clang/AST/DeclCXX.h" |
27 | #include "clang/AST/Type.h" |
28 | #include "clang/Basic/LLVM.h" |
29 | #include "clang/Basic/PartialDiagnostic.h" |
30 | #include "clang/Basic/SourceLocation.h" |
31 | #include "clang/Basic/Specifiers.h" |
32 | #include "clang/Sema/Sema.h" |
33 | #include "llvm/ADT/ArrayRef.h" |
34 | #include "llvm/ADT/SmallVector.h" |
35 | #include "llvm/ADT/StringRef.h" |
36 | #include "llvm/Support/Casting.h" |
37 | #include <cassert> |
38 | #include <cstddef> |
39 | #include <utility> |
40 | |
41 | namespace clang { |
42 | |
43 | class ObjCInterfaceDecl; |
44 | class ObjCPropertyDecl; |
45 | |
46 | namespace sema { |
47 | |
48 | |
49 | |
50 | class AccessedEntity { |
51 | public: |
52 | |
53 | |
54 | enum MemberNonce { Member }; |
55 | |
56 | |
57 | |
58 | enum BaseNonce { Base }; |
59 | |
60 | AccessedEntity(PartialDiagnostic::StorageAllocator &Allocator, |
61 | MemberNonce _, |
62 | CXXRecordDecl *NamingClass, |
63 | DeclAccessPair FoundDecl, |
64 | QualType BaseObjectType) |
65 | : Access(FoundDecl.getAccess()), IsMember(true), |
66 | Target(FoundDecl.getDecl()), NamingClass(NamingClass), |
67 | BaseObjectType(BaseObjectType), Diag(0, Allocator) { |
68 | } |
69 | |
70 | AccessedEntity(PartialDiagnostic::StorageAllocator &Allocator, |
71 | BaseNonce _, |
72 | CXXRecordDecl *BaseClass, |
73 | CXXRecordDecl *DerivedClass, |
74 | AccessSpecifier Access) |
75 | : Access(Access), IsMember(false), Target(BaseClass), |
76 | NamingClass(DerivedClass), Diag(0, Allocator) {} |
77 | |
78 | bool isMemberAccess() const { return IsMember; } |
79 | |
80 | bool isQuiet() const { return Diag.getDiagID() == 0; } |
81 | |
82 | AccessSpecifier getAccess() const { return AccessSpecifier(Access); } |
83 | |
84 | |
85 | NamedDecl *getTargetDecl() const { return Target; } |
86 | CXXRecordDecl *getNamingClass() const { return NamingClass; } |
87 | |
88 | |
89 | CXXRecordDecl *getBaseClass() const { |
90 | assert(!IsMember); return cast<CXXRecordDecl>(Target); |
91 | } |
92 | CXXRecordDecl *getDerivedClass() const { return NamingClass; } |
93 | |
94 | |
95 | |
96 | QualType getBaseObjectType() const { return BaseObjectType; } |
97 | |
98 | |
99 | |
100 | |
101 | |
102 | |
103 | |
104 | void setDiag(const PartialDiagnostic &PDiag) { |
105 | (0) . __assert_fail ("isQuiet() && \"partial diagnostic already defined\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Sema/DelayedDiagnostic.h", 105, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(isQuiet() && "partial diagnostic already defined"); |
106 | Diag = PDiag; |
107 | } |
108 | PartialDiagnostic &setDiag(unsigned DiagID) { |
109 | (0) . __assert_fail ("isQuiet() && \"partial diagnostic already defined\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Sema/DelayedDiagnostic.h", 109, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(isQuiet() && "partial diagnostic already defined"); |
110 | (0) . __assert_fail ("DiagID && \"creating null diagnostic\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Sema/DelayedDiagnostic.h", 110, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(DiagID && "creating null diagnostic"); |
111 | Diag.Reset(DiagID); |
112 | return Diag; |
113 | } |
114 | const PartialDiagnostic &getDiag() const { |
115 | return Diag; |
116 | } |
117 | |
118 | private: |
119 | unsigned Access : 2; |
120 | unsigned IsMember : 1; |
121 | NamedDecl *Target; |
122 | CXXRecordDecl *NamingClass; |
123 | QualType BaseObjectType; |
124 | PartialDiagnostic Diag; |
125 | }; |
126 | |
127 | |
128 | |
129 | class DelayedDiagnostic { |
130 | public: |
131 | enum DDKind : unsigned char { Availability, Access, ForbiddenType }; |
132 | |
133 | DDKind Kind; |
134 | bool Triggered; |
135 | |
136 | SourceLocation Loc; |
137 | |
138 | void Destroy(); |
139 | |
140 | static DelayedDiagnostic makeAvailability(AvailabilityResult AR, |
141 | ArrayRef<SourceLocation> Locs, |
142 | const NamedDecl *ReferringDecl, |
143 | const NamedDecl *OffendingDecl, |
144 | const ObjCInterfaceDecl *UnknownObjCClass, |
145 | const ObjCPropertyDecl *ObjCProperty, |
146 | StringRef Msg, |
147 | bool ObjCPropertyAccess); |
148 | |
149 | static DelayedDiagnostic makeAccess(SourceLocation Loc, |
150 | const AccessedEntity &Entity) { |
151 | DelayedDiagnostic DD; |
152 | DD.Kind = Access; |
153 | DD.Triggered = false; |
154 | DD.Loc = Loc; |
155 | new (&DD.getAccessData()) AccessedEntity(Entity); |
156 | return DD; |
157 | } |
158 | |
159 | static DelayedDiagnostic makeForbiddenType(SourceLocation loc, |
160 | unsigned diagnostic, |
161 | QualType type, |
162 | unsigned argument) { |
163 | DelayedDiagnostic DD; |
164 | DD.Kind = ForbiddenType; |
165 | DD.Triggered = false; |
166 | DD.Loc = loc; |
167 | DD.ForbiddenTypeData.Diagnostic = diagnostic; |
168 | DD.ForbiddenTypeData.OperandType = type.getAsOpaquePtr(); |
169 | DD.ForbiddenTypeData.Argument = argument; |
170 | return DD; |
171 | } |
172 | |
173 | AccessedEntity &getAccessData() { |
174 | (0) . __assert_fail ("Kind == Access && \"Not an access diagnostic.\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Sema/DelayedDiagnostic.h", 174, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(Kind == Access && "Not an access diagnostic."); |
175 | return *reinterpret_cast<AccessedEntity*>(AccessData); |
176 | } |
177 | const AccessedEntity &getAccessData() const { |
178 | (0) . __assert_fail ("Kind == Access && \"Not an access diagnostic.\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Sema/DelayedDiagnostic.h", 178, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(Kind == Access && "Not an access diagnostic."); |
179 | return *reinterpret_cast<const AccessedEntity*>(AccessData); |
180 | } |
181 | |
182 | const NamedDecl *getAvailabilityReferringDecl() const { |
183 | (0) . __assert_fail ("Kind == Availability && \"Not an availability diagnostic.\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Sema/DelayedDiagnostic.h", 183, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(Kind == Availability && "Not an availability diagnostic."); |
184 | return AvailabilityData.ReferringDecl; |
185 | } |
186 | |
187 | const NamedDecl *getAvailabilityOffendingDecl() const { |
188 | return AvailabilityData.OffendingDecl; |
189 | } |
190 | |
191 | StringRef getAvailabilityMessage() const { |
192 | (0) . __assert_fail ("Kind == Availability && \"Not an availability diagnostic.\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Sema/DelayedDiagnostic.h", 192, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(Kind == Availability && "Not an availability diagnostic."); |
193 | return StringRef(AvailabilityData.Message, AvailabilityData.MessageLen); |
194 | } |
195 | |
196 | ArrayRef<SourceLocation> getAvailabilitySelectorLocs() const { |
197 | (0) . __assert_fail ("Kind == Availability && \"Not an availability diagnostic.\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Sema/DelayedDiagnostic.h", 197, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(Kind == Availability && "Not an availability diagnostic."); |
198 | return llvm::makeArrayRef(AvailabilityData.SelectorLocs, |
199 | AvailabilityData.NumSelectorLocs); |
200 | } |
201 | |
202 | AvailabilityResult getAvailabilityResult() const { |
203 | (0) . __assert_fail ("Kind == Availability && \"Not an availability diagnostic.\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Sema/DelayedDiagnostic.h", 203, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(Kind == Availability && "Not an availability diagnostic."); |
204 | return AvailabilityData.AR; |
205 | } |
206 | |
207 | |
208 | |
209 | |
210 | |
211 | unsigned getForbiddenTypeDiagnostic() const { |
212 | (0) . __assert_fail ("Kind == ForbiddenType && \"not a forbidden-type diagnostic\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Sema/DelayedDiagnostic.h", 212, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); |
213 | return ForbiddenTypeData.Diagnostic; |
214 | } |
215 | |
216 | unsigned getForbiddenTypeArgument() const { |
217 | (0) . __assert_fail ("Kind == ForbiddenType && \"not a forbidden-type diagnostic\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Sema/DelayedDiagnostic.h", 217, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); |
218 | return ForbiddenTypeData.Argument; |
219 | } |
220 | |
221 | QualType getForbiddenTypeOperand() const { |
222 | (0) . __assert_fail ("Kind == ForbiddenType && \"not a forbidden-type diagnostic\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Sema/DelayedDiagnostic.h", 222, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); |
223 | return QualType::getFromOpaquePtr(ForbiddenTypeData.OperandType); |
224 | } |
225 | |
226 | const ObjCInterfaceDecl *getUnknownObjCClass() const { |
227 | return AvailabilityData.UnknownObjCClass; |
228 | } |
229 | |
230 | const ObjCPropertyDecl *getObjCProperty() const { |
231 | return AvailabilityData.ObjCProperty; |
232 | } |
233 | |
234 | bool getObjCPropertyAccess() const { |
235 | return AvailabilityData.ObjCPropertyAccess; |
236 | } |
237 | |
238 | private: |
239 | struct AD { |
240 | const NamedDecl *ReferringDecl; |
241 | const NamedDecl *OffendingDecl; |
242 | const ObjCInterfaceDecl *UnknownObjCClass; |
243 | const ObjCPropertyDecl *ObjCProperty; |
244 | const char *Message; |
245 | size_t MessageLen; |
246 | SourceLocation *SelectorLocs; |
247 | size_t NumSelectorLocs; |
248 | AvailabilityResult AR; |
249 | bool ObjCPropertyAccess; |
250 | }; |
251 | |
252 | struct FTD { |
253 | unsigned Diagnostic; |
254 | unsigned Argument; |
255 | void *OperandType; |
256 | }; |
257 | |
258 | union { |
259 | struct AD AvailabilityData; |
260 | struct FTD ForbiddenTypeData; |
261 | |
262 | |
263 | char AccessData[sizeof(AccessedEntity)]; |
264 | }; |
265 | }; |
266 | |
267 | |
268 | class DelayedDiagnosticPool { |
269 | const DelayedDiagnosticPool *Parent; |
270 | SmallVector<DelayedDiagnostic, 4> Diagnostics; |
271 | |
272 | public: |
273 | DelayedDiagnosticPool(const DelayedDiagnosticPool *parent) : Parent(parent) {} |
274 | |
275 | DelayedDiagnosticPool(const DelayedDiagnosticPool &) = delete; |
276 | DelayedDiagnosticPool &operator=(const DelayedDiagnosticPool &) = delete; |
277 | |
278 | DelayedDiagnosticPool(DelayedDiagnosticPool &&Other) |
279 | : Parent(Other.Parent), Diagnostics(std::move(Other.Diagnostics)) { |
280 | Other.Diagnostics.clear(); |
281 | } |
282 | |
283 | DelayedDiagnosticPool &operator=(DelayedDiagnosticPool &&Other) { |
284 | Parent = Other.Parent; |
285 | Diagnostics = std::move(Other.Diagnostics); |
286 | Other.Diagnostics.clear(); |
287 | return *this; |
288 | } |
289 | |
290 | ~DelayedDiagnosticPool() { |
291 | for (SmallVectorImpl<DelayedDiagnostic>::iterator |
292 | i = Diagnostics.begin(), e = Diagnostics.end(); i != e; ++i) |
293 | i->Destroy(); |
294 | } |
295 | |
296 | const DelayedDiagnosticPool *getParent() const { return Parent; } |
297 | |
298 | |
299 | bool empty() const { |
300 | return (Diagnostics.empty() && (!Parent || Parent->empty())); |
301 | } |
302 | |
303 | |
304 | void add(const DelayedDiagnostic &diag) { |
305 | Diagnostics.push_back(diag); |
306 | } |
307 | |
308 | |
309 | void steal(DelayedDiagnosticPool &pool) { |
310 | if (pool.Diagnostics.empty()) return; |
311 | |
312 | if (Diagnostics.empty()) { |
313 | Diagnostics = std::move(pool.Diagnostics); |
314 | } else { |
315 | Diagnostics.append(pool.pool_begin(), pool.pool_end()); |
316 | } |
317 | pool.Diagnostics.clear(); |
318 | } |
319 | |
320 | using pool_iterator = SmallVectorImpl<DelayedDiagnostic>::const_iterator; |
321 | |
322 | pool_iterator pool_begin() const { return Diagnostics.begin(); } |
323 | pool_iterator pool_end() const { return Diagnostics.end(); } |
324 | bool pool_empty() const { return Diagnostics.empty(); } |
325 | }; |
326 | |
327 | } |
328 | |
329 | |
330 | inline void Sema::DelayedDiagnostics::add(const sema::DelayedDiagnostic &diag) { |
331 | (0) . __assert_fail ("shouldDelayDiagnostics() && \"trying to delay without pool\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Sema/DelayedDiagnostic.h", 331, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(shouldDelayDiagnostics() && "trying to delay without pool"); |
332 | CurPool->add(diag); |
333 | } |
334 | |
335 | } |
336 | |
337 | #endif |
338 | |