1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | #ifndef LLVM_CLANG_BASIC_PARTIALDIAGNOSTIC_H |
16 | #define LLVM_CLANG_BASIC_PARTIALDIAGNOSTIC_H |
17 | |
18 | #include "clang/Basic/Diagnostic.h" |
19 | #include "clang/Basic/LLVM.h" |
20 | #include "clang/Basic/SourceLocation.h" |
21 | #include "llvm/ADT/SmallVector.h" |
22 | #include "llvm/ADT/StringRef.h" |
23 | #include <cassert> |
24 | #include <cstdint> |
25 | #include <string> |
26 | #include <type_traits> |
27 | #include <utility> |
28 | |
29 | namespace clang { |
30 | |
31 | class DeclContext; |
32 | class IdentifierInfo; |
33 | |
34 | class PartialDiagnostic { |
35 | public: |
36 | enum { |
37 | |
38 | |
39 | |
40 | |
41 | MaxArguments = DiagnosticsEngine::MaxArguments |
42 | }; |
43 | |
44 | struct Storage { |
45 | enum { |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | MaxArguments = PartialDiagnostic::MaxArguments |
52 | }; |
53 | |
54 | |
55 | unsigned char NumDiagArgs = 0; |
56 | |
57 | |
58 | |
59 | unsigned char DiagArgumentsKind[MaxArguments]; |
60 | |
61 | |
62 | |
63 | |
64 | |
65 | |
66 | intptr_t DiagArgumentsVal[MaxArguments]; |
67 | |
68 | |
69 | |
70 | std::string DiagArgumentsStr[MaxArguments]; |
71 | |
72 | |
73 | SmallVector<CharSourceRange, 8> DiagRanges; |
74 | |
75 | |
76 | |
77 | SmallVector<FixItHint, 6> FixItHints; |
78 | |
79 | Storage() = default; |
80 | }; |
81 | |
82 | |
83 | |
84 | class StorageAllocator { |
85 | static const unsigned NumCached = 16; |
86 | Storage Cached[NumCached]; |
87 | Storage *FreeList[NumCached]; |
88 | unsigned NumFreeListEntries; |
89 | |
90 | public: |
91 | StorageAllocator(); |
92 | ~StorageAllocator(); |
93 | |
94 | |
95 | Storage *Allocate() { |
96 | if (NumFreeListEntries == 0) |
97 | return new Storage; |
98 | |
99 | Storage *Result = FreeList[--NumFreeListEntries]; |
100 | Result->NumDiagArgs = 0; |
101 | Result->DiagRanges.clear(); |
102 | Result->FixItHints.clear(); |
103 | return Result; |
104 | } |
105 | |
106 | |
107 | void Deallocate(Storage *S) { |
108 | if (S >= Cached && S <= Cached + NumCached) { |
109 | FreeList[NumFreeListEntries++] = S; |
110 | return; |
111 | } |
112 | |
113 | delete S; |
114 | } |
115 | }; |
116 | |
117 | private: |
118 | |
119 | |
120 | |
121 | |
122 | |
123 | mutable unsigned DiagID = 0; |
124 | |
125 | |
126 | mutable Storage *DiagStorage = nullptr; |
127 | |
128 | |
129 | StorageAllocator *Allocator = nullptr; |
130 | |
131 | |
132 | Storage *getStorage() const { |
133 | if (DiagStorage) |
134 | return DiagStorage; |
135 | |
136 | if (Allocator) |
137 | DiagStorage = Allocator->Allocate(); |
138 | else { |
139 | (~uintptr_t(0))", "/home/seafit/code_projects/clang_source/clang/include/clang/Basic/PartialDiagnostic.h", 139, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(Allocator != reinterpret_cast<StorageAllocator *>(~uintptr_t(0))); |
140 | DiagStorage = new Storage; |
141 | } |
142 | return DiagStorage; |
143 | } |
144 | |
145 | void freeStorage() { |
146 | if (!DiagStorage) |
147 | return; |
148 | |
149 | |
150 | |
151 | |
152 | |
153 | |
154 | |
155 | freeStorageSlow(); |
156 | } |
157 | |
158 | void freeStorageSlow() { |
159 | if (Allocator) |
160 | Allocator->Deallocate(DiagStorage); |
161 | else if (Allocator != reinterpret_cast<StorageAllocator *>(~uintptr_t(0))) |
162 | delete DiagStorage; |
163 | DiagStorage = nullptr; |
164 | } |
165 | |
166 | void AddSourceRange(const CharSourceRange &R) const { |
167 | if (!DiagStorage) |
168 | DiagStorage = getStorage(); |
169 | |
170 | DiagStorage->DiagRanges.push_back(R); |
171 | } |
172 | |
173 | void AddFixItHint(const FixItHint &Hint) const { |
174 | if (Hint.isNull()) |
175 | return; |
176 | |
177 | if (!DiagStorage) |
178 | DiagStorage = getStorage(); |
179 | |
180 | DiagStorage->FixItHints.push_back(Hint); |
181 | } |
182 | |
183 | public: |
184 | struct NullDiagnostic {}; |
185 | |
186 | |
187 | |
188 | PartialDiagnostic(NullDiagnostic) {} |
189 | |
190 | PartialDiagnostic(unsigned DiagID, StorageAllocator &Allocator) |
191 | : DiagID(DiagID), Allocator(&Allocator) {} |
192 | |
193 | PartialDiagnostic(const PartialDiagnostic &Other) |
194 | : DiagID(Other.DiagID), Allocator(Other.Allocator) { |
195 | if (Other.DiagStorage) { |
196 | DiagStorage = getStorage(); |
197 | *DiagStorage = *Other.DiagStorage; |
198 | } |
199 | } |
200 | |
201 | PartialDiagnostic(PartialDiagnostic &&Other) |
202 | : DiagID(Other.DiagID), DiagStorage(Other.DiagStorage), |
203 | Allocator(Other.Allocator) { |
204 | Other.DiagStorage = nullptr; |
205 | } |
206 | |
207 | PartialDiagnostic(const PartialDiagnostic &Other, Storage *DiagStorage) |
208 | : DiagID(Other.DiagID), DiagStorage(DiagStorage), |
209 | Allocator(reinterpret_cast<StorageAllocator *>(~uintptr_t(0))) { |
210 | if (Other.DiagStorage) |
211 | *this->DiagStorage = *Other.DiagStorage; |
212 | } |
213 | |
214 | PartialDiagnostic(const Diagnostic &Other, StorageAllocator &Allocator) |
215 | : DiagID(Other.getID()), Allocator(&Allocator) { |
216 | |
217 | for (unsigned I = 0, N = Other.getNumArgs(); I != N; ++I) { |
218 | if (Other.getArgKind(I) == DiagnosticsEngine::ak_std_string) |
219 | AddString(Other.getArgStdStr(I)); |
220 | else |
221 | AddTaggedVal(Other.getRawArg(I), Other.getArgKind(I)); |
222 | } |
223 | |
224 | |
225 | for (unsigned I = 0, N = Other.getNumRanges(); I != N; ++I) |
226 | AddSourceRange(Other.getRange(I)); |
227 | |
228 | |
229 | for (unsigned I = 0, N = Other.getNumFixItHints(); I != N; ++I) |
230 | AddFixItHint(Other.getFixItHint(I)); |
231 | } |
232 | |
233 | PartialDiagnostic &operator=(const PartialDiagnostic &Other) { |
234 | DiagID = Other.DiagID; |
235 | if (Other.DiagStorage) { |
236 | if (!DiagStorage) |
237 | DiagStorage = getStorage(); |
238 | |
239 | *DiagStorage = *Other.DiagStorage; |
240 | } else { |
241 | freeStorage(); |
242 | } |
243 | |
244 | return *this; |
245 | } |
246 | |
247 | PartialDiagnostic &operator=(PartialDiagnostic &&Other) { |
248 | freeStorage(); |
249 | |
250 | DiagID = Other.DiagID; |
251 | DiagStorage = Other.DiagStorage; |
252 | Allocator = Other.Allocator; |
253 | |
254 | Other.DiagStorage = nullptr; |
255 | return *this; |
256 | } |
257 | |
258 | ~PartialDiagnostic() { |
259 | freeStorage(); |
260 | } |
261 | |
262 | void swap(PartialDiagnostic &PD) { |
263 | std::swap(DiagID, PD.DiagID); |
264 | std::swap(DiagStorage, PD.DiagStorage); |
265 | std::swap(Allocator, PD.Allocator); |
266 | } |
267 | |
268 | unsigned getDiagID() const { return DiagID; } |
269 | |
270 | void AddTaggedVal(intptr_t V, DiagnosticsEngine::ArgumentKind Kind) const { |
271 | if (!DiagStorage) |
272 | DiagStorage = getStorage(); |
273 | |
274 | (0) . __assert_fail ("DiagStorage->NumDiagArgs < Storage..MaxArguments && \"Too many arguments to diagnostic!\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Basic/PartialDiagnostic.h", 275, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(DiagStorage->NumDiagArgs < Storage::MaxArguments && |
275 | (0) . __assert_fail ("DiagStorage->NumDiagArgs < Storage..MaxArguments && \"Too many arguments to diagnostic!\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Basic/PartialDiagnostic.h", 275, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> "Too many arguments to diagnostic!"); |
276 | DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = Kind; |
277 | DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V; |
278 | } |
279 | |
280 | void AddString(StringRef V) const { |
281 | if (!DiagStorage) |
282 | DiagStorage = getStorage(); |
283 | |
284 | (0) . __assert_fail ("DiagStorage->NumDiagArgs < Storage..MaxArguments && \"Too many arguments to diagnostic!\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Basic/PartialDiagnostic.h", 285, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(DiagStorage->NumDiagArgs < Storage::MaxArguments && |
285 | (0) . __assert_fail ("DiagStorage->NumDiagArgs < Storage..MaxArguments && \"Too many arguments to diagnostic!\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Basic/PartialDiagnostic.h", 285, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> "Too many arguments to diagnostic!"); |
286 | DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] |
287 | = DiagnosticsEngine::ak_std_string; |
288 | DiagStorage->DiagArgumentsStr[DiagStorage->NumDiagArgs++] = V; |
289 | } |
290 | |
291 | void Emit(const DiagnosticBuilder &DB) const { |
292 | if (!DiagStorage) |
293 | return; |
294 | |
295 | |
296 | for (unsigned i = 0, e = DiagStorage->NumDiagArgs; i != e; ++i) { |
297 | if ((DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i] |
298 | == DiagnosticsEngine::ak_std_string) |
299 | DB.AddString(DiagStorage->DiagArgumentsStr[i]); |
300 | else |
301 | DB.AddTaggedVal(DiagStorage->DiagArgumentsVal[i], |
302 | (DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i]); |
303 | } |
304 | |
305 | |
306 | for (const CharSourceRange &Range : DiagStorage->DiagRanges) |
307 | DB.AddSourceRange(Range); |
308 | |
309 | |
310 | for (const FixItHint &Fix : DiagStorage->FixItHints) |
311 | DB.AddFixItHint(Fix); |
312 | } |
313 | |
314 | void EmitToString(DiagnosticsEngine &Diags, |
315 | SmallVectorImpl<char> &Buf) const { |
316 | |
317 | |
318 | DiagnosticBuilder DB(Diags.Report(getDiagID())); |
319 | Emit(DB); |
320 | DB.FlushCounts(); |
321 | Diagnostic(&Diags).FormatDiagnostic(Buf); |
322 | DB.Clear(); |
323 | Diags.Clear(); |
324 | } |
325 | |
326 | |
327 | |
328 | void Reset(unsigned DiagID = 0) { |
329 | this->DiagID = DiagID; |
330 | freeStorage(); |
331 | } |
332 | |
333 | bool hasStorage() const { return DiagStorage != nullptr; } |
334 | |
335 | |
336 | StringRef getStringArg(unsigned I) { |
337 | (0) . __assert_fail ("DiagStorage && \"No diagnostic storage?\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Basic/PartialDiagnostic.h", 337, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(DiagStorage && "No diagnostic storage?"); |
338 | (0) . __assert_fail ("I < DiagStorage->NumDiagArgs && \"Not enough diagnostic args\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Basic/PartialDiagnostic.h", 338, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(I < DiagStorage->NumDiagArgs && "Not enough diagnostic args"); |
339 | (0) . __assert_fail ("DiagStorage->DiagArgumentsKind[I] == DiagnosticsEngine..ak_std_string && \"Not a string arg\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Basic/PartialDiagnostic.h", 340, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(DiagStorage->DiagArgumentsKind[I] |
340 | (0) . __assert_fail ("DiagStorage->DiagArgumentsKind[I] == DiagnosticsEngine..ak_std_string && \"Not a string arg\"", "/home/seafit/code_projects/clang_source/clang/include/clang/Basic/PartialDiagnostic.h", 340, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> == DiagnosticsEngine::ak_std_string && "Not a string arg"); |
341 | return DiagStorage->DiagArgumentsStr[I]; |
342 | } |
343 | |
344 | friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, |
345 | unsigned I) { |
346 | PD.AddTaggedVal(I, DiagnosticsEngine::ak_uint); |
347 | return PD; |
348 | } |
349 | |
350 | friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, |
351 | int I) { |
352 | PD.AddTaggedVal(I, DiagnosticsEngine::ak_sint); |
353 | return PD; |
354 | } |
355 | |
356 | friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, |
357 | const char *S) { |
358 | PD.AddTaggedVal(reinterpret_cast<intptr_t>(S), |
359 | DiagnosticsEngine::ak_c_string); |
360 | return PD; |
361 | } |
362 | |
363 | friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, |
364 | StringRef S) { |
365 | |
366 | PD.AddString(S); |
367 | return PD; |
368 | } |
369 | |
370 | friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, |
371 | const IdentifierInfo *II) { |
372 | PD.AddTaggedVal(reinterpret_cast<intptr_t>(II), |
373 | DiagnosticsEngine::ak_identifierinfo); |
374 | return PD; |
375 | } |
376 | |
377 | |
378 | |
379 | |
380 | |
381 | template<typename T> |
382 | friend inline |
383 | typename std::enable_if<std::is_same<T, DeclContext>::value, |
384 | const PartialDiagnostic &>::type |
385 | operator<<(const PartialDiagnostic &PD, T *DC) { |
386 | PD.AddTaggedVal(reinterpret_cast<intptr_t>(DC), |
387 | DiagnosticsEngine::ak_declcontext); |
388 | return PD; |
389 | } |
390 | |
391 | friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, |
392 | SourceRange R) { |
393 | PD.AddSourceRange(CharSourceRange::getTokenRange(R)); |
394 | return PD; |
395 | } |
396 | |
397 | friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, |
398 | const CharSourceRange &R) { |
399 | PD.AddSourceRange(R); |
400 | return PD; |
401 | } |
402 | |
403 | friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, |
404 | const FixItHint &Hint) { |
405 | PD.AddFixItHint(Hint); |
406 | return PD; |
407 | } |
408 | }; |
409 | |
410 | inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, |
411 | const PartialDiagnostic &PD) { |
412 | PD.Emit(DB); |
413 | return DB; |
414 | } |
415 | |
416 | |
417 | |
418 | using PartialDiagnosticAt = std::pair<SourceLocation, PartialDiagnostic>; |
419 | |
420 | } |
421 | |
422 | #endif |
423 | |