Coverage Report

Created: 2017-10-03 07:32

/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/tools/clang/include/clang/Basic/PartialDiagnostic.h
Line
Count
Source (jump to first uncovered line)
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
/// \file
11
/// \brief Implements a partial diagnostic that can be emitted anwyhere
12
/// in a DiagnosticBuilder stream.
13
///
14
//===----------------------------------------------------------------------===//
15
16
#ifndef LLVM_CLANG_BASIC_PARTIALDIAGNOSTIC_H
17
#define LLVM_CLANG_BASIC_PARTIALDIAGNOSTIC_H
18
19
#include "clang/Basic/Diagnostic.h"
20
#include "clang/Basic/SourceLocation.h"
21
#include "llvm/ADT/STLExtras.h"
22
#include "llvm/Support/Compiler.h"
23
#include "llvm/Support/DataTypes.h"
24
#include <cassert>
25
26
namespace clang {
27
28
class PartialDiagnostic {
29
public:
30
  enum {
31
      // The MaxArguments and MaxFixItHints member enum values from
32
      // DiagnosticsEngine are private but DiagnosticsEngine declares
33
      // PartialDiagnostic a friend.  These enum values are redeclared
34
      // here so that the nested Storage class below can access them.
35
      MaxArguments = DiagnosticsEngine::MaxArguments
36
  };
37
38
  struct Storage {
39
513k
    Storage() : NumDiagArgs(0) { }
40
41
    enum {
42
        /// \brief The maximum number of arguments we can hold. We
43
        /// currently only support up to 10 arguments (%0-%9).
44
        ///
45
        /// A single diagnostic with more than that almost certainly has to
46
        /// be simplified anyway.
47
        MaxArguments = PartialDiagnostic::MaxArguments
48
    };
49
50
    /// \brief The number of entries in Arguments.
51
    unsigned char NumDiagArgs;
52
53
    /// \brief Specifies for each argument whether it is in DiagArgumentsStr
54
    /// or in DiagArguments.
55
    unsigned char DiagArgumentsKind[MaxArguments];
56
57
    /// \brief The values for the various substitution positions.
58
    ///
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
    /// \brief The list of ranges added to this diagnostic.
69
    SmallVector<CharSourceRange, 8> DiagRanges;
70
71
    /// \brief If valid, provides a hint with some code to insert, remove, or
72
    /// modify at a particular position.
73
    SmallVector<FixItHint, 6>  FixItHints;
74
  };
75
76
  /// \brief An allocator for Storage objects, which uses a small cache to
77
  /// objects, used to reduce malloc()/free() traffic for partial diagnostics.
78
  class StorageAllocator {
79
    static const unsigned NumCached = 16;
80
    Storage Cached[NumCached];
81
    Storage *FreeList[NumCached];
82
    unsigned NumFreeListEntries;
83
84
  public:
85
    StorageAllocator();
86
    ~StorageAllocator();
87
88
    /// \brief Allocate new storage.
89
632k
    Storage *Allocate() {
90
632k
      if (NumFreeListEntries == 0)
91
38.5k
        return new Storage;
92
632k
93
593k
      Storage *Result = FreeList[--NumFreeListEntries];
94
593k
      Result->NumDiagArgs = 0;
95
593k
      Result->DiagRanges.clear();
96
593k
      Result->FixItHints.clear();
97
593k
      return Result;
98
632k
    }
99
100
    /// \brief Free the given storage object.
101
612k
    void Deallocate(Storage *S) {
102
612k
      if (
S >= Cached && 612k
S <= Cached + NumCached601k
) {
103
592k
        FreeList[NumFreeListEntries++] = S;
104
592k
        return;
105
592k
      }
106
612k
107
19.7k
      delete S;
108
19.7k
    }
109
  };
110
111
private:
112
  // NOTE: Sema assumes that PartialDiagnostic is location-invariant
113
  // in the sense that its bits can be safely memcpy'ed and destructed
114
  // in the new location.
115
116
  /// \brief The diagnostic ID.
117
  mutable unsigned DiagID;
118
119
  /// \brief Storage for args and ranges.
120
  mutable Storage *DiagStorage;
121
122
  /// \brief Allocator used to allocate storage for this diagnostic.
123
  StorageAllocator *Allocator;
124
125
  /// \brief Retrieve storage for this particular diagnostic.
126
632k
  Storage *getStorage() const {
127
632k
    if (DiagStorage)
128
0
      return DiagStorage;
129
632k
130
632k
    
if (632k
Allocator632k
)
131
632k
      DiagStorage = Allocator->Allocate();
132
0
    else {
133
0
      assert(Allocator != reinterpret_cast<StorageAllocator *>(~uintptr_t(0)));
134
0
      DiagStorage = new Storage;
135
0
    }
136
632k
    return DiagStorage;
137
632k
  }
138
139
3.07M
  void freeStorage() {
140
3.07M
    if (!DiagStorage)
141
2.46M
      return;
142
3.07M
143
3.07M
    // The hot path for PartialDiagnostic is when we just used it to wrap an ID
144
3.07M
    // (typically so we have the flexibility of passing a more complex
145
3.07M
    // diagnostic into the callee, but that does not commonly occur).
146
3.07M
    //
147
3.07M
    // Split this out into a slow function for silly compilers (*cough*) which
148
3.07M
    // can't do decent partial inlining.
149
612k
    freeStorageSlow();
150
612k
  }
151
152
612k
  void freeStorageSlow() {
153
612k
    if (Allocator)
154
612k
      Allocator->Deallocate(DiagStorage);
155
0
    else 
if (0
Allocator != reinterpret_cast<StorageAllocator *>(~uintptr_t(0))0
)
156
0
      delete DiagStorage;
157
612k
    DiagStorage = nullptr;
158
612k
  }
159
160
99.3k
  void AddSourceRange(const CharSourceRange &R) const {
161
99.3k
    if (!DiagStorage)
162
3.76k
      DiagStorage = getStorage();
163
99.3k
164
99.3k
    DiagStorage->DiagRanges.push_back(R);
165
99.3k
  }
166
167
21.1k
  void AddFixItHint(const FixItHint &Hint) const {
168
21.1k
    if (Hint.isNull())
169
20.9k
      return;
170
21.1k
171
210
    
if (210
!DiagStorage210
)
172
63
      DiagStorage = getStorage();
173
21.1k
174
21.1k
    DiagStorage->FixItHints.push_back(Hint);
175
21.1k
  }
176
177
public:
178
  struct NullDiagnostic {};
179
  /// \brief Create a null partial diagnostic, which cannot carry a payload,
180
  /// and only exists to be swapped with a real partial diagnostic.
181
  PartialDiagnostic(NullDiagnostic)
182
1.03k
    : DiagID(0), DiagStorage(nullptr), Allocator(nullptr) { }
183
184
  PartialDiagnostic(unsigned DiagID, StorageAllocator &Allocator)
185
1.50M
    : DiagID(DiagID), DiagStorage(nullptr), Allocator(&Allocator) { }
186
187
  PartialDiagnostic(const PartialDiagnostic &Other)
188
    : DiagID(Other.DiagID), DiagStorage(nullptr), Allocator(Other.Allocator)
189
728k
  {
190
728k
    if (
Other.DiagStorage728k
) {
191
63.0k
      DiagStorage = getStorage();
192
63.0k
      *DiagStorage = *Other.DiagStorage;
193
63.0k
    }
194
728k
  }
195
196
  PartialDiagnostic(PartialDiagnostic &&Other)
197
    : DiagID(Other.DiagID), DiagStorage(Other.DiagStorage),
198
476k
      Allocator(Other.Allocator) {
199
476k
    Other.DiagStorage = nullptr;
200
476k
  }
201
202
  PartialDiagnostic(const PartialDiagnostic &Other, Storage *DiagStorage)
203
    : DiagID(Other.DiagID), DiagStorage(DiagStorage),
204
      Allocator(reinterpret_cast<StorageAllocator *>(~uintptr_t(0)))
205
43
  {
206
43
    if (Other.DiagStorage)
207
2
      *this->DiagStorage = *Other.DiagStorage;
208
43
  }
209
210
  PartialDiagnostic(const Diagnostic &Other, StorageAllocator &Allocator)
211
    : DiagID(Other.getID()), DiagStorage(nullptr), Allocator(&Allocator)
212
3.01k
  {
213
3.01k
    // Copy arguments.
214
6.08k
    for (unsigned I = 0, N = Other.getNumArgs(); 
I != N6.08k
;
++I3.07k
) {
215
3.07k
      if (Other.getArgKind(I) == DiagnosticsEngine::ak_std_string)
216
196
        AddString(Other.getArgStdStr(I));
217
3.07k
      else
218
2.88k
        AddTaggedVal(Other.getRawArg(I), Other.getArgKind(I));
219
3.07k
    }
220
3.01k
221
3.01k
    // Copy source ranges.
222
4.46k
    for (unsigned I = 0, N = Other.getNumRanges(); 
I != N4.46k
;
++I1.45k
)
223
1.45k
      AddSourceRange(Other.getRange(I));
224
3.01k
225
3.01k
    // Copy fix-its.
226
3.06k
    for (unsigned I = 0, N = Other.getNumFixItHints(); 
I != N3.06k
;
++I52
)
227
52
      AddFixItHint(Other.getFixItHint(I));
228
3.01k
  }
229
230
8.75k
  PartialDiagnostic &operator=(const PartialDiagnostic &Other) {
231
8.75k
    DiagID = Other.DiagID;
232
8.75k
    if (
Other.DiagStorage8.75k
) {
233
5.33k
      if (!DiagStorage)
234
5.33k
        DiagStorage = getStorage();
235
5.33k
236
5.33k
      *DiagStorage = *Other.DiagStorage;
237
8.75k
    } else {
238
3.42k
      freeStorage();
239
3.42k
    }
240
8.75k
241
8.75k
    return *this;
242
8.75k
  }
243
244
5.41k
  PartialDiagnostic &operator=(PartialDiagnostic &&Other) {
245
5.41k
    freeStorage();
246
5.41k
247
5.41k
    DiagID = Other.DiagID;
248
5.41k
    DiagStorage = Other.DiagStorage;
249
5.41k
    Allocator = Other.Allocator;
250
5.41k
251
5.41k
    Other.DiagStorage = nullptr;
252
5.41k
    return *this;
253
5.41k
  }
254
255
2.69M
  ~PartialDiagnostic() {
256
2.69M
    freeStorage();
257
2.69M
  }
258
259
1.03k
  void swap(PartialDiagnostic &PD) {
260
1.03k
    std::swap(DiagID, PD.DiagID);
261
1.03k
    std::swap(DiagStorage, PD.DiagStorage);
262
1.03k
    std::swap(Allocator, PD.Allocator);
263
1.03k
  }
264
265
66.0k
  unsigned getDiagID() const { return DiagID; }
266
267
704k
  void AddTaggedVal(intptr_t V, DiagnosticsEngine::ArgumentKind Kind) const {
268
704k
    if (!DiagStorage)
269
537k
      DiagStorage = getStorage();
270
704k
271
704k
    assert(DiagStorage->NumDiagArgs < Storage::MaxArguments &&
272
704k
           "Too many arguments to diagnostic!");
273
704k
    DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = Kind;
274
704k
    DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V;
275
704k
  }
276
277
51.8k
  void AddString(StringRef V) const {
278
51.8k
    if (!DiagStorage)
279
22.5k
      DiagStorage = getStorage();
280
51.8k
281
51.8k
    assert(DiagStorage->NumDiagArgs < Storage::MaxArguments &&
282
51.8k
           "Too many arguments to diagnostic!");
283
51.8k
    DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs]
284
51.8k
      = DiagnosticsEngine::ak_std_string;
285
51.8k
    DiagStorage->DiagArgumentsStr[DiagStorage->NumDiagArgs++] = V;
286
51.8k
  }
287
288
60.0k
  void Emit(const DiagnosticBuilder &DB) const {
289
60.0k
    if (!DiagStorage)
290
3.32k
      return;
291
60.0k
292
60.0k
    // Add all arguments.
293
222k
    
for (unsigned i = 0, e = DiagStorage->NumDiagArgs; 56.7k
i != e222k
;
++i165k
) {
294
165k
      if ((DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i]
295
165k
            == DiagnosticsEngine::ak_std_string)
296
14.8k
        DB.AddString(DiagStorage->DiagArgumentsStr[i]);
297
165k
      else
298
150k
        DB.AddTaggedVal(DiagStorage->DiagArgumentsVal[i],
299
150k
            (DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i]);
300
165k
    }
301
56.7k
302
56.7k
    // Add all ranges.
303
56.7k
    for (const CharSourceRange &Range : DiagStorage->DiagRanges)
304
66.2k
      DB.AddSourceRange(Range);
305
56.7k
306
56.7k
    // Add all fix-its.
307
56.7k
    for (const FixItHint &Fix : DiagStorage->FixItHints)
308
177
      DB.AddFixItHint(Fix);
309
60.0k
  }
310
311
  void EmitToString(DiagnosticsEngine &Diags,
312
167
                    SmallVectorImpl<char> &Buf) const {
313
167
    // FIXME: It should be possible to render a diagnostic to a string without
314
167
    //        messing with the state of the diagnostics engine.
315
167
    DiagnosticBuilder DB(Diags.Report(getDiagID()));
316
167
    Emit(DB);
317
167
    DB.FlushCounts();
318
167
    Diagnostic(&Diags).FormatDiagnostic(Buf);
319
167
    DB.Clear();
320
167
    Diags.Clear();
321
167
  }
322
323
  /// \brief Clear out this partial diagnostic, giving it a new diagnostic ID
324
  /// and removing all of its arguments, ranges, and fix-it hints.
325
375k
  void Reset(unsigned DiagID = 0) {
326
375k
    this->DiagID = DiagID;
327
375k
    freeStorage();
328
375k
  }
329
330
43
  bool hasStorage() const { return DiagStorage != nullptr; }
331
332
  /// Retrieve the string argument at the given index.
333
16
  StringRef getStringArg(unsigned I) {
334
16
    assert(DiagStorage && "No diagnostic storage?");
335
16
    assert(I < DiagStorage->NumDiagArgs && "Not enough diagnostic args");
336
16
    assert(DiagStorage->DiagArgumentsKind[I]
337
16
             == DiagnosticsEngine::ak_std_string && "Not a string arg");
338
16
    return DiagStorage->DiagArgumentsStr[I];
339
16
  }
340
341
  friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
342
42.4k
                                             unsigned I) {
343
42.4k
    PD.AddTaggedVal(I, DiagnosticsEngine::ak_uint);
344
42.4k
    return PD;
345
42.4k
  }
346
347
  friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
348
222k
                                             int I) {
349
222k
    PD.AddTaggedVal(I, DiagnosticsEngine::ak_sint);
350
222k
    return PD;
351
222k
  }
352
353
  friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
354
712
                                                    const char *S) {
355
712
    PD.AddTaggedVal(reinterpret_cast<intptr_t>(S),
356
712
                    DiagnosticsEngine::ak_c_string);
357
712
    return PD;
358
712
  }
359
360
  friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
361
51.6k
                                                    StringRef S) {
362
51.6k
363
51.6k
    PD.AddString(S);
364
51.6k
    return PD;
365
51.6k
  }
366
367
  friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
368
386
                                                    const IdentifierInfo *II) {
369
386
    PD.AddTaggedVal(reinterpret_cast<intptr_t>(II),
370
386
                    DiagnosticsEngine::ak_identifierinfo);
371
386
    return PD;
372
386
  }
373
374
  // Adds a DeclContext to the diagnostic. The enable_if template magic is here
375
  // so that we only match those arguments that are (statically) DeclContexts;
376
  // other arguments that derive from DeclContext (e.g., RecordDecls) will not
377
  // match.
378
  template<typename T>
379
  friend inline
380
  typename std::enable_if<std::is_same<T, DeclContext>::value,
381
                          const PartialDiagnostic &>::type
382
268
  operator<<(const PartialDiagnostic &PD, T *DC) {
383
268
    PD.AddTaggedVal(reinterpret_cast<intptr_t>(DC),
384
268
                    DiagnosticsEngine::ak_declcontext);
385
268
    return PD;
386
268
  }
387
388
  friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
389
97.5k
                                                    SourceRange R) {
390
97.5k
    PD.AddSourceRange(CharSourceRange::getTokenRange(R));
391
97.5k
    return PD;
392
97.5k
  }
393
394
  friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
395
355
                                                    const CharSourceRange &R) {
396
355
    PD.AddSourceRange(R);
397
355
    return PD;
398
355
  }
399
400
  friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
401
21.1k
                                             const FixItHint &Hint) {
402
21.1k
    PD.AddFixItHint(Hint);
403
21.1k
    return PD;
404
21.1k
  }
405
406
};
407
408
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
409
0
                                           const PartialDiagnostic &PD) {
410
0
  PD.Emit(DB);
411
0
  return DB;
412
0
}
413
414
/// \brief A partial diagnostic along with the source location where this
415
/// diagnostic occurs.
416
typedef std::pair<SourceLocation, PartialDiagnostic> PartialDiagnosticAt;
417
418
}  // end namespace clang
419
#endif