Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/include/clang/Sema/DelayedDiagnostic.h
Line
Count
Source (jump to first uncovered line)
1
//===- DelayedDiagnostic.h - Delayed declarator diagnostics -----*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
/// \file
10
/// Defines the classes clang::DelayedDiagnostic and
11
/// clang::AccessedEntity.
12
///
13
/// DelayedDiangostic is used to record diagnostics that are being
14
/// conditionally produced during declarator parsing.  Certain kinds of
15
/// diagnostics -- notably deprecation and access control -- are suppressed
16
/// based on semantic properties of the parsed declaration that aren't known
17
/// until it is fully parsed.
18
//
19
//===----------------------------------------------------------------------===//
20
21
#ifndef LLVM_CLANG_SEMA_DELAYEDDIAGNOSTIC_H
22
#define LLVM_CLANG_SEMA_DELAYEDDIAGNOSTIC_H
23
24
#include "clang/AST/DeclAccessPair.h"
25
#include "clang/AST/DeclBase.h"
26
#include "clang/AST/DeclCXX.h"
27
#include "clang/AST/Type.h"
28
#include "clang/Basic/LLVM.h"
29
#include "clang/Basic/PartialDiagnostic.h"
30
#include "clang/Basic/SourceLocation.h"
31
#include "clang/Basic/Specifiers.h"
32
#include "clang/Sema/Sema.h"
33
#include "llvm/ADT/ArrayRef.h"
34
#include "llvm/ADT/SmallVector.h"
35
#include "llvm/ADT/StringRef.h"
36
#include "llvm/Support/Casting.h"
37
#include <cassert>
38
#include <cstddef>
39
#include <utility>
40
41
namespace clang {
42
43
class ObjCInterfaceDecl;
44
class ObjCPropertyDecl;
45
46
namespace sema {
47
48
/// A declaration being accessed, together with information about how
49
/// it was accessed.
50
class AccessedEntity {
51
public:
52
  /// A member declaration found through lookup.  The target is the
53
  /// member.
54
  enum MemberNonce { Member };
55
56
  /// A hierarchy (base-to-derived or derived-to-base) conversion.
57
  /// The target is the base class.
58
  enum BaseNonce { Base };
59
60
  AccessedEntity(PartialDiagnostic::StorageAllocator &Allocator,
61
                 MemberNonce _,
62
                 CXXRecordDecl *NamingClass,
63
                 DeclAccessPair FoundDecl,
64
                 QualType BaseObjectType)
65
      : Access(FoundDecl.getAccess()), IsMember(true),
66
        Target(FoundDecl.getDecl()), NamingClass(NamingClass),
67
1.95M
        BaseObjectType(BaseObjectType), Diag(0, Allocator) {
68
1.95M
  }
69
70
  AccessedEntity(PartialDiagnostic::StorageAllocator &Allocator,
71
                 BaseNonce _,
72
                 CXXRecordDecl *BaseClass,
73
                 CXXRecordDecl *DerivedClass,
74
                 AccessSpecifier Access)
75
      : Access(Access), IsMember(false), Target(BaseClass),
76
42.2k
        NamingClass(DerivedClass), Diag(0, Allocator) {}
77
78
5.31M
  bool isMemberAccess() const { return IsMember; }
79
80
10.2k
  bool isQuiet() const { return Diag.getDiagID() == 0; }
81
82
3.98M
  AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
83
84
  // These apply to member decls...
85
4.15M
  NamedDecl *getTargetDecl() const { return Target; }
86
2.00M
  CXXRecordDecl *getNamingClass() const { return NamingClass; }
87
88
  // ...and these apply to hierarchy conversions.
89
42.2k
  CXXRecordDecl *getBaseClass() const {
90
42.2k
    assert(!IsMember); return cast<CXXRecordDecl>(Target);
91
42.2k
  }
92
0
  CXXRecordDecl *getDerivedClass() const { return NamingClass; }
93
94
  /// Retrieves the base object type, important when accessing
95
  /// an instance member.
96
2.64M
  QualType getBaseObjectType() const { return BaseObjectType; }
97
98
  /// Sets a diagnostic to be performed.  The diagnostic is given
99
  /// four (additional) arguments:
100
  ///   %0 - 0 if the entity was private, 1 if protected
101
  ///   %1 - the DeclarationName of the entity
102
  ///   %2 - the TypeDecl type of the naming class
103
  ///   %3 - the TypeDecl type of the declaring class
104
110k
  void setDiag(const PartialDiagnostic &PDiag) {
105
110k
    assert(isQuiet() && "partial diagnostic already defined");
106
110k
    Diag = PDiag;
107
110k
  }
108
1.88M
  PartialDiagnostic &setDiag(unsigned DiagID) {
109
1.88M
    assert(isQuiet() && "partial diagnostic already defined");
110
1.88M
    assert(DiagID && "creating null diagnostic");
111
1.88M
    Diag.Reset(DiagID);
112
1.88M
    return Diag;
113
1.88M
  }
114
2.84k
  const PartialDiagnostic &getDiag() const {
115
2.84k
    return Diag;
116
2.84k
  }
117
118
private:
119
  unsigned Access : 2;
120
  unsigned IsMember : 1;
121
  NamedDecl *Target;
122
  CXXRecordDecl *NamingClass;
123
  QualType BaseObjectType;
124
  PartialDiagnostic Diag;
125
};
126
127
/// A diagnostic message which has been conditionally emitted pending
128
/// the complete parsing of the current declaration.
129
class DelayedDiagnostic {
130
public:
131
  enum DDKind : unsigned char { Availability, Access, ForbiddenType };
132
133
  DDKind Kind;
134
  bool Triggered;
135
136
  SourceLocation Loc;
137
138
  void Destroy();
139
140
  static DelayedDiagnostic makeAvailability(AvailabilityResult AR,
141
                                            ArrayRef<SourceLocation> Locs,
142
                                            const NamedDecl *ReferringDecl,
143
                                            const NamedDecl *OffendingDecl,
144
                                            const ObjCInterfaceDecl *UnknownObjCClass,
145
                                            const ObjCPropertyDecl  *ObjCProperty,
146
                                            StringRef Msg,
147
                                            bool ObjCPropertyAccess);
148
149
  static DelayedDiagnostic makeAccess(SourceLocation Loc,
150
530k
                                      const AccessedEntity &Entity) {
151
530k
    DelayedDiagnostic DD;
152
530k
    DD.Kind = Access;
153
530k
    DD.Triggered = false;
154
530k
    DD.Loc = Loc;
155
530k
    new (&DD.getAccessData()) AccessedEntity(Entity);
156
530k
    return DD;
157
530k
  }
158
159
  static DelayedDiagnostic makeForbiddenType(SourceLocation loc,
160
                                             unsigned diagnostic,
161
                                             QualType type,
162
75
                                             unsigned argument) {
163
75
    DelayedDiagnostic DD;
164
75
    DD.Kind = ForbiddenType;
165
75
    DD.Triggered = false;
166
75
    DD.Loc = loc;
167
75
    DD.ForbiddenTypeData.Diagnostic = diagnostic;
168
75
    DD.ForbiddenTypeData.OperandType = type.getAsOpaquePtr();
169
75
    DD.ForbiddenTypeData.Argument = argument;
170
75
    return DD;
171
75
  }
172
173
1.58M
  AccessedEntity &getAccessData() {
174
1.58M
    assert(Kind == Access && "Not an access diagnostic.");
175
1.58M
    return *reinterpret_cast<AccessedEntity*>(AccessData);
176
1.58M
  }
177
0
  const AccessedEntity &getAccessData() const {
178
0
    assert(Kind == Access && "Not an access diagnostic.");
179
0
    return *reinterpret_cast<const AccessedEntity*>(AccessData);
180
0
  }
181
182
21.9k
  const NamedDecl *getAvailabilityReferringDecl() const {
183
21.9k
    assert(Kind == Availability && "Not an availability diagnostic.");
184
21.9k
    return AvailabilityData.ReferringDecl;
185
21.9k
  }
186
187
21.9k
  const NamedDecl *getAvailabilityOffendingDecl() const {
188
21.9k
    return AvailabilityData.OffendingDecl;
189
21.9k
  }
190
191
21.9k
  StringRef getAvailabilityMessage() const {
192
21.9k
    assert(Kind == Availability && "Not an availability diagnostic.");
193
21.9k
    return StringRef(AvailabilityData.Message, AvailabilityData.MessageLen);
194
21.9k
  }
195
196
21.9k
  ArrayRef<SourceLocation> getAvailabilitySelectorLocs() const {
197
21.9k
    assert(Kind == Availability && "Not an availability diagnostic.");
198
21.9k
    return llvm::makeArrayRef(AvailabilityData.SelectorLocs,
199
21.9k
                              AvailabilityData.NumSelectorLocs);
200
21.9k
  }
201
202
21.9k
  AvailabilityResult getAvailabilityResult() const {
203
21.9k
    assert(Kind == Availability && "Not an availability diagnostic.");
204
21.9k
    return AvailabilityData.AR;
205
21.9k
  }
206
207
  /// The diagnostic ID to emit.  Used like so:
208
  ///   Diag(diag.Loc, diag.getForbiddenTypeDiagnostic())
209
  ///     << diag.getForbiddenTypeOperand()
210
  ///     << diag.getForbiddenTypeArgument();
211
82
  unsigned getForbiddenTypeDiagnostic() const {
212
82
    assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
213
82
    return ForbiddenTypeData.Diagnostic;
214
82
  }
215
216
9
  unsigned getForbiddenTypeArgument() const {
217
9
    assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
218
9
    return ForbiddenTypeData.Argument;
219
9
  }
220
221
9
  QualType getForbiddenTypeOperand() const {
222
9
    assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
223
9
    return QualType::getFromOpaquePtr(ForbiddenTypeData.OperandType);
224
9
  }
225
226
21.9k
  const ObjCInterfaceDecl *getUnknownObjCClass() const {
227
21.9k
    return AvailabilityData.UnknownObjCClass;
228
21.9k
  }
229
230
21.9k
  const ObjCPropertyDecl *getObjCProperty() const {
231
21.9k
    return AvailabilityData.ObjCProperty;
232
21.9k
  }
233
234
0
  bool getObjCPropertyAccess() const {
235
0
    return AvailabilityData.ObjCPropertyAccess;
236
0
  }
237
238
private:
239
  struct AD {
240
    const NamedDecl *ReferringDecl;
241
    const NamedDecl *OffendingDecl;
242
    const ObjCInterfaceDecl *UnknownObjCClass;
243
    const ObjCPropertyDecl  *ObjCProperty;
244
    const char *Message;
245
    size_t MessageLen;
246
    SourceLocation *SelectorLocs;
247
    size_t NumSelectorLocs;
248
    AvailabilityResult AR;
249
    bool ObjCPropertyAccess;
250
  };
251
252
  struct FTD {
253
    unsigned Diagnostic;
254
    unsigned Argument;
255
    void *OperandType;
256
  };
257
258
  union {
259
    struct AD AvailabilityData;
260
    struct FTD ForbiddenTypeData;
261
262
    /// Access control.
263
    char AccessData[sizeof(AccessedEntity)];
264
  };
265
};
266
267
/// A collection of diagnostics which were delayed.
268
class DelayedDiagnosticPool {
269
  const DelayedDiagnosticPool *Parent;
270
  SmallVector<DelayedDiagnostic, 4> Diagnostics;
271
272
public:
273
29.0M
  DelayedDiagnosticPool(const DelayedDiagnosticPool *parent) : Parent(parent) {}
274
275
  DelayedDiagnosticPool(const DelayedDiagnosticPool &) = delete;
276
  DelayedDiagnosticPool &operator=(const DelayedDiagnosticPool &) = delete;
277
278
  DelayedDiagnosticPool(DelayedDiagnosticPool &&Other)
279
174k
      : Parent(Other.Parent), Diagnostics(std::move(Other.Diagnostics)) {
280
174k
    Other.Diagnostics.clear();
281
174k
  }
282
283
0
  DelayedDiagnosticPool &operator=(DelayedDiagnosticPool &&Other) {
284
0
    Parent = Other.Parent;
285
0
    Diagnostics = std::move(Other.Diagnostics);
286
0
    Other.Diagnostics.clear();
287
0
    return *this;
288
0
  }
289
290
29.1M
  ~DelayedDiagnosticPool() {
291
29.1M
    for (SmallVectorImpl<DelayedDiagnostic>::iterator
292
29.7M
           i = Diagnostics.begin(), e = Diagnostics.end(); i != e; 
++i552k
)
293
552k
      i->Destroy();
294
29.1M
  }
295
296
27.1M
  const DelayedDiagnosticPool *getParent() const { return Parent; }
297
298
  /// Does this pool, or any of its ancestors, contain any diagnostics?
299
0
  bool empty() const {
300
0
    return (Diagnostics.empty() && (!Parent || Parent->empty()));
301
0
  }
302
303
  /// Add a diagnostic to this pool.
304
552k
  void add(const DelayedDiagnostic &diag) {
305
552k
    Diagnostics.push_back(diag);
306
552k
  }
307
308
  /// Steal the diagnostics from the given pool.
309
1.38M
  void steal(DelayedDiagnosticPool &pool) {
310
1.38M
    if (pool.Diagnostics.empty()) 
return1.36M
;
311
12.1k
312
12.1k
    if (Diagnostics.empty()) {
313
12.1k
      Diagnostics = std::move(pool.Diagnostics);
314
12.1k
    } else {
315
0
      Diagnostics.append(pool.pool_begin(), pool.pool_end());
316
0
    }
317
12.1k
    pool.Diagnostics.clear();
318
12.1k
  }
319
320
  using pool_iterator = SmallVectorImpl<DelayedDiagnostic>::const_iterator;
321
322
25.7M
  pool_iterator pool_begin() const { return Diagnostics.begin(); }
323
25.7M
  pool_iterator pool_end() const { return Diagnostics.end(); }
324
369k
  bool pool_empty() const { return Diagnostics.empty(); }
325
};
326
327
} // namespace clang
328
329
/// Add a diagnostic to the current delay pool.
330
552k
inline void Sema::DelayedDiagnostics::add(const sema::DelayedDiagnostic &diag) {
331
552k
  assert(shouldDelayDiagnostics() && "trying to delay without pool");
332
552k
  CurPool->add(diag);
333
552k
}
334
335
} // namespace clang
336
337
#endif // LLVM_CLANG_SEMA_DELAYEDDIAGNOSTIC_H