]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/llvm/tools/clang/include/clang/Basic/PartialDiagnostic.h
MFC r234353:
[FreeBSD/stable/9.git] / contrib / llvm / tools / clang / include / clang / Basic / PartialDiagnostic.h
1 //===--- PartialDiagnostic.h - Diagnostic "closures" ------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  This file implements a partial diagnostic that can be emitted anwyhere
11 //  in a DiagnosticBuilder stream.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #ifndef LLVM_CLANG_PARTIALDIAGNOSTIC_H
16 #define LLVM_CLANG_PARTIALDIAGNOSTIC_H
17
18 #include "clang/Basic/Diagnostic.h"
19 #include "clang/Basic/SourceLocation.h"
20 #include "llvm/ADT/STLExtras.h"
21 #include "llvm/Support/DataTypes.h"
22 #include <cassert>
23
24 namespace clang {
25
26 class PartialDiagnostic {
27 public:
28   enum {
29       // The MaxArguments and MaxFixItHints member enum values from
30       // DiagnosticsEngine are private but DiagnosticsEngine declares
31       // PartialDiagnostic a friend.  These enum values are redeclared
32       // here so that the nested Storage class below can access them.
33       MaxArguments = DiagnosticsEngine::MaxArguments
34   };
35
36   struct Storage {
37     Storage() : NumDiagArgs(0), NumDiagRanges(0) { }
38
39     enum {
40         /// MaxArguments - The maximum number of arguments we can hold. We
41         /// currently only support up to 10 arguments (%0-%9).
42         /// A single diagnostic with more than that almost certainly has to
43         /// be simplified anyway.
44         MaxArguments = PartialDiagnostic::MaxArguments
45     };
46
47     /// NumDiagArgs - This contains the number of entries in Arguments.
48     unsigned char NumDiagArgs;
49
50     /// NumDiagRanges - This is the number of ranges in the DiagRanges array.
51     unsigned char NumDiagRanges;
52
53     /// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum
54     /// values, with one for each argument.  This specifies whether the argument
55     /// is in DiagArgumentsStr or in DiagArguments.
56     unsigned char DiagArgumentsKind[MaxArguments];
57
58     /// DiagArgumentsVal - The values for the various substitution positions.
59     /// This is used when the argument is not an std::string. The specific value
60     /// is mangled into an intptr_t and the interpretation depends on exactly
61     /// what sort of argument kind it is.
62     intptr_t DiagArgumentsVal[MaxArguments];
63
64     /// \brief The values for the various substitution positions that have
65     /// string arguments.
66     std::string DiagArgumentsStr[MaxArguments];
67
68     /// DiagRanges - The list of ranges added to this diagnostic.  It currently
69     /// only support 10 ranges, could easily be extended if needed.
70     CharSourceRange DiagRanges[10];
71
72     /// FixItHints - If valid, provides a hint with some code
73     /// to insert, remove, or modify at a particular position.
74     SmallVector<FixItHint, 6>  FixItHints;
75   };
76
77   /// \brief An allocator for Storage objects, which uses a small cache to
78   /// objects, used to reduce malloc()/free() traffic for partial diagnostics.
79   class StorageAllocator {
80     static const unsigned NumCached = 16;
81     Storage Cached[NumCached];
82     Storage *FreeList[NumCached];
83     unsigned NumFreeListEntries;
84
85   public:
86     StorageAllocator();
87     ~StorageAllocator();
88
89     /// \brief Allocate new storage.
90     Storage *Allocate() {
91       if (NumFreeListEntries == 0)
92         return new Storage;
93
94       Storage *Result = FreeList[--NumFreeListEntries];
95       Result->NumDiagArgs = 0;
96       Result->NumDiagRanges = 0;
97       Result->FixItHints.clear();
98       return Result;
99     }
100
101     /// \brief Free the given storage object.
102     void Deallocate(Storage *S) {
103       if (S >= Cached && S <= Cached + NumCached) {
104         FreeList[NumFreeListEntries++] = S;
105         return;
106       }
107
108       delete S;
109     }
110   };
111
112 private:
113   // NOTE: Sema assumes that PartialDiagnostic is location-invariant
114   // in the sense that its bits can be safely memcpy'ed and destructed
115   // in the new location.
116
117   /// DiagID - The diagnostic ID.
118   mutable unsigned DiagID;
119
120   /// DiagStorage - Storage for args and ranges.
121   mutable Storage *DiagStorage;
122
123   /// \brief Allocator used to allocate storage for this diagnostic.
124   StorageAllocator *Allocator;
125
126   /// \brief Retrieve storage for this particular diagnostic.
127   Storage *getStorage() const {
128     if (DiagStorage)
129       return DiagStorage;
130
131     if (Allocator)
132       DiagStorage = Allocator->Allocate();
133     else {
134       assert(Allocator != reinterpret_cast<StorageAllocator *>(~uintptr_t(0)));
135       DiagStorage = new Storage;
136     }
137     return DiagStorage;
138   }
139
140   void freeStorage() {
141     if (!DiagStorage)
142       return;
143
144     // The hot path for PartialDiagnostic is when we just used it to wrap an ID
145     // (typically so we have the flexibility of passing a more complex
146     // diagnostic into the callee, but that does not commonly occur).
147     //
148     // Split this out into a slow function for silly compilers (*cough*) which
149     // can't do decent partial inlining.
150     freeStorageSlow();
151   }
152
153   void freeStorageSlow() {
154     if (Allocator)
155       Allocator->Deallocate(DiagStorage);
156     else if (Allocator != reinterpret_cast<StorageAllocator *>(~uintptr_t(0)))
157       delete DiagStorage;
158     DiagStorage = 0;
159   }
160
161   void AddSourceRange(const CharSourceRange &R) const {
162     if (!DiagStorage)
163       DiagStorage = getStorage();
164
165     assert(DiagStorage->NumDiagRanges <
166            llvm::array_lengthof(DiagStorage->DiagRanges) &&
167            "Too many arguments to diagnostic!");
168     DiagStorage->DiagRanges[DiagStorage->NumDiagRanges++] = R;
169   }
170
171   void AddFixItHint(const FixItHint &Hint) const {
172     if (Hint.isNull())
173       return;
174
175     if (!DiagStorage)
176       DiagStorage = getStorage();
177
178     DiagStorage->FixItHints.push_back(Hint);
179   }
180
181 public:
182   PartialDiagnostic(unsigned DiagID, StorageAllocator &Allocator)
183     : DiagID(DiagID), DiagStorage(0), Allocator(&Allocator) { }
184
185   PartialDiagnostic(const PartialDiagnostic &Other)
186     : DiagID(Other.DiagID), DiagStorage(0), Allocator(Other.Allocator)
187   {
188     if (Other.DiagStorage) {
189       DiagStorage = getStorage();
190       *DiagStorage = *Other.DiagStorage;
191     }
192   }
193
194   PartialDiagnostic(const PartialDiagnostic &Other, Storage *DiagStorage)
195     : DiagID(Other.DiagID), DiagStorage(DiagStorage),
196       Allocator(reinterpret_cast<StorageAllocator *>(~uintptr_t(0)))
197   {
198     if (Other.DiagStorage)
199       *this->DiagStorage = *Other.DiagStorage;
200   }
201
202   PartialDiagnostic(const Diagnostic &Other, StorageAllocator &Allocator)
203     : DiagID(Other.getID()), DiagStorage(0), Allocator(&Allocator)
204   {
205     // Copy arguments.
206     for (unsigned I = 0, N = Other.getNumArgs(); I != N; ++I) {
207       if (Other.getArgKind(I) == DiagnosticsEngine::ak_std_string)
208         AddString(Other.getArgStdStr(I));
209       else
210         AddTaggedVal(Other.getRawArg(I), Other.getArgKind(I));
211     }
212
213     // Copy source ranges.
214     for (unsigned I = 0, N = Other.getNumRanges(); I != N; ++I)
215       AddSourceRange(Other.getRange(I));
216
217     // Copy fix-its.
218     for (unsigned I = 0, N = Other.getNumFixItHints(); I != N; ++I)
219       AddFixItHint(Other.getFixItHint(I));
220   }
221
222   PartialDiagnostic &operator=(const PartialDiagnostic &Other) {
223     DiagID = Other.DiagID;
224     if (Other.DiagStorage) {
225       if (!DiagStorage)
226         DiagStorage = getStorage();
227
228       *DiagStorage = *Other.DiagStorage;
229     } else {
230       freeStorage();
231     }
232
233     return *this;
234   }
235
236   ~PartialDiagnostic() {
237     freeStorage();
238   }
239
240   unsigned getDiagID() const { return DiagID; }
241
242   void AddTaggedVal(intptr_t V, DiagnosticsEngine::ArgumentKind Kind) const {
243     if (!DiagStorage)
244       DiagStorage = getStorage();
245
246     assert(DiagStorage->NumDiagArgs < Storage::MaxArguments &&
247            "Too many arguments to diagnostic!");
248     DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = Kind;
249     DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V;
250   }
251
252   void AddString(StringRef V) const {
253     if (!DiagStorage)
254       DiagStorage = getStorage();
255
256     assert(DiagStorage->NumDiagArgs < Storage::MaxArguments &&
257            "Too many arguments to diagnostic!");
258     DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs]
259       = DiagnosticsEngine::ak_std_string;
260     DiagStorage->DiagArgumentsStr[DiagStorage->NumDiagArgs++] = V;
261   }
262
263   void Emit(const DiagnosticBuilder &DB) const {
264     if (!DiagStorage)
265       return;
266
267     // Add all arguments.
268     for (unsigned i = 0, e = DiagStorage->NumDiagArgs; i != e; ++i) {
269       if ((DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i]
270             == DiagnosticsEngine::ak_std_string)
271         DB.AddString(DiagStorage->DiagArgumentsStr[i]);
272       else
273         DB.AddTaggedVal(DiagStorage->DiagArgumentsVal[i],
274             (DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i]);
275     }
276
277     // Add all ranges.
278     for (unsigned i = 0, e = DiagStorage->NumDiagRanges; i != e; ++i)
279       DB.AddSourceRange(DiagStorage->DiagRanges[i]);
280
281     // Add all fix-its.
282     for (unsigned i = 0, e = DiagStorage->FixItHints.size(); i != e; ++i)
283       DB.AddFixItHint(DiagStorage->FixItHints[i]);
284   }
285
286   /// \brief Clear out this partial diagnostic, giving it a new diagnostic ID
287   /// and removing all of its arguments, ranges, and fix-it hints.
288   void Reset(unsigned DiagID = 0) {
289     this->DiagID = DiagID;
290     freeStorage();
291   }
292
293   bool hasStorage() const { return DiagStorage != 0; }
294
295   friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
296                                              unsigned I) {
297     PD.AddTaggedVal(I, DiagnosticsEngine::ak_uint);
298     return PD;
299   }
300
301   friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
302                                              int I) {
303     PD.AddTaggedVal(I, DiagnosticsEngine::ak_sint);
304     return PD;
305   }
306
307   friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
308                                                     const char *S) {
309     PD.AddTaggedVal(reinterpret_cast<intptr_t>(S),
310                     DiagnosticsEngine::ak_c_string);
311     return PD;
312   }
313
314   friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
315                                                     StringRef S) {
316
317     PD.AddString(S);
318     return PD;
319   }
320
321   friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
322                                                     const SourceRange &R) {
323     PD.AddSourceRange(CharSourceRange::getTokenRange(R));
324     return PD;
325   }
326
327   friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
328                                                     const CharSourceRange &R) {
329     PD.AddSourceRange(R);
330     return PD;
331   }
332
333   friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
334                                              const FixItHint &Hint) {
335     PD.AddFixItHint(Hint);
336     return PD;
337   }
338
339 };
340
341 inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
342                                            const PartialDiagnostic &PD) {
343   PD.Emit(DB);
344   return DB;
345 }
346
347 /// \brief A partial diagnostic along with the source location where this
348 /// diagnostic occurs.
349 typedef std::pair<SourceLocation, PartialDiagnostic> PartialDiagnosticAt;
350
351 }  // end namespace clang
352 #endif