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