]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/llvm/tools/clang/include/clang/Basic/PartialDiagnostic.h
Copy head to stable/9 as part of 9.0-RELEASE release cycle.
[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   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 = 10
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 = 3 };
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     DiagStorage->FixItHints[DiagStorage->NumFixItHints++]
169       = Hint;
170   }
171   
172 public:
173   PartialDiagnostic(unsigned DiagID, StorageAllocator &Allocator)
174     : DiagID(DiagID), DiagStorage(0), Allocator(&Allocator) { }
175   
176   PartialDiagnostic(const PartialDiagnostic &Other) 
177     : DiagID(Other.DiagID), DiagStorage(0), Allocator(Other.Allocator)
178   {
179     if (Other.DiagStorage) {
180       DiagStorage = getStorage();
181       *DiagStorage = *Other.DiagStorage;
182     }
183   }
184
185   PartialDiagnostic(const PartialDiagnostic &Other, Storage *DiagStorage) 
186     : DiagID(Other.DiagID), DiagStorage(DiagStorage), 
187       Allocator(reinterpret_cast<StorageAllocator *>(~uintptr_t(0)))
188   {
189     if (Other.DiagStorage)
190       *this->DiagStorage = *Other.DiagStorage;
191   }
192   
193   PartialDiagnostic(const DiagnosticInfo &Other, StorageAllocator &Allocator)
194     : DiagID(Other.getID()), DiagStorage(0), Allocator(&Allocator)
195   {
196     // Copy arguments.
197     for (unsigned I = 0, N = Other.getNumArgs(); I != N; ++I) {
198       if (Other.getArgKind(I) == Diagnostic::ak_std_string)
199         AddString(Other.getArgStdStr(I));
200       else
201         AddTaggedVal(Other.getRawArg(I), Other.getArgKind(I));
202     }
203     
204     // Copy source ranges.
205     for (unsigned I = 0, N = Other.getNumRanges(); I != N; ++I)
206       AddSourceRange(Other.getRange(I));
207     
208     // Copy fix-its.
209     for (unsigned I = 0, N = Other.getNumFixItHints(); I != N; ++I)
210       AddFixItHint(Other.getFixItHint(I));
211   }
212   
213   PartialDiagnostic &operator=(const PartialDiagnostic &Other) {
214     DiagID = Other.DiagID;
215     if (Other.DiagStorage) {
216       if (!DiagStorage)
217         DiagStorage = getStorage();
218       
219       *DiagStorage = *Other.DiagStorage;
220     } else {
221       freeStorage();
222     }
223
224     return *this;
225   }
226
227   ~PartialDiagnostic() {
228     freeStorage();
229   }
230
231   unsigned getDiagID() const { return DiagID; }
232
233   void AddTaggedVal(intptr_t V, Diagnostic::ArgumentKind Kind) const {
234     if (!DiagStorage)
235       DiagStorage = getStorage();
236
237     assert(DiagStorage->NumDiagArgs < Storage::MaxArguments &&
238            "Too many arguments to diagnostic!");
239     DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = Kind;
240     DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V;
241   }
242
243   void AddString(llvm::StringRef V) const {
244     if (!DiagStorage)
245       DiagStorage = getStorage();
246     
247     assert(DiagStorage->NumDiagArgs < Storage::MaxArguments &&
248            "Too many arguments to diagnostic!");
249     DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs]
250       = Diagnostic::ak_std_string;
251     DiagStorage->DiagArgumentsStr[DiagStorage->NumDiagArgs++] = V;
252   }
253
254   void Emit(const DiagnosticBuilder &DB) const {
255     if (!DiagStorage)
256       return;
257     
258     // Add all arguments.
259     for (unsigned i = 0, e = DiagStorage->NumDiagArgs; i != e; ++i) {
260       if ((Diagnostic::ArgumentKind)DiagStorage->DiagArgumentsKind[i]
261             == Diagnostic::ak_std_string)
262         DB.AddString(DiagStorage->DiagArgumentsStr[i]);
263       else
264         DB.AddTaggedVal(DiagStorage->DiagArgumentsVal[i],
265                    (Diagnostic::ArgumentKind)DiagStorage->DiagArgumentsKind[i]);
266     }
267     
268     // Add all ranges.
269     for (unsigned i = 0, e = DiagStorage->NumDiagRanges; i != e; ++i)
270       DB.AddSourceRange(DiagStorage->DiagRanges[i]);
271     
272     // Add all fix-its.
273     for (unsigned i = 0, e = DiagStorage->NumFixItHints; i != e; ++i)
274       DB.AddFixItHint(DiagStorage->FixItHints[i]);
275   }
276   
277   /// \brief Clear out this partial diagnostic, giving it a new diagnostic ID
278   /// and removing all of its arguments, ranges, and fix-it hints.
279   void Reset(unsigned DiagID = 0) {
280     this->DiagID = DiagID;
281     freeStorage();
282   }
283   
284   bool hasStorage() const { return DiagStorage != 0; }
285   
286   friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
287                                              unsigned I) {
288     PD.AddTaggedVal(I, Diagnostic::ak_uint);
289     return PD;
290   }
291
292   friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
293                                              int I) {
294     PD.AddTaggedVal(I, Diagnostic::ak_sint);
295     return PD;
296   }
297
298   friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
299                                                     const char *S) {
300     PD.AddTaggedVal(reinterpret_cast<intptr_t>(S), Diagnostic::ak_c_string);
301     return PD;
302   }
303
304   friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
305                                                     llvm::StringRef S) {
306     
307     PD.AddString(S);
308     return PD;
309   }
310   
311   friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
312                                                     const SourceRange &R) {
313     PD.AddSourceRange(CharSourceRange::getTokenRange(R));
314     return PD;
315   }
316
317   friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
318                                                     const CharSourceRange &R) {
319     PD.AddSourceRange(R);
320     return PD;
321   }
322   
323   friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
324                                              const FixItHint &Hint) {
325     PD.AddFixItHint(Hint);
326     return PD;
327   }
328   
329 };
330
331 inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
332                                            const PartialDiagnostic &PD) {
333   PD.Emit(DB);
334   return DB;
335 }
336   
337 /// \brief A partial diagnostic along with the source location where this
338 /// diagnostic occurs.
339 typedef std::pair<SourceLocation, PartialDiagnostic> PartialDiagnosticAt;
340
341 }  // end namespace clang
342 #endif