Coverage Report

Created: 2020-11-24 06:42

/Users/buildslave/jenkins/workspace/coverage/llvm-project/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::DiagStorageAllocator &Allocator,
61
                 MemberNonce _, CXXRecordDecl *NamingClass,
62
                 DeclAccessPair FoundDecl, QualType BaseObjectType)
63
      : Access(FoundDecl.getAccess()), IsMember(true),
64
        Target(FoundDecl.getDecl()), NamingClass(NamingClass),
65
913k
        BaseObjectType(BaseObjectType), Diag(0, Allocator) {}
66
67
  AccessedEntity(PartialDiagnostic::DiagStorageAllocator &Allocator,
68
                 BaseNonce _, CXXRecordDecl *BaseClass,
69
                 CXXRecordDecl *DerivedClass, AccessSpecifier Access)
70
      : Access(Access), IsMember(false), Target(BaseClass),
71
15.4k
        NamingClass(DerivedClass), Diag(0, Allocator) {}
72
73
2.58M
  bool isMemberAccess() const { return IsMember; }
74
75
935k
  bool isQuiet() const { return Diag.getDiagID() == 0; }
76
77
2.75M
  AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
78
79
  // These apply to member decls...
80
1.91M
  NamedDecl *getTargetDecl() const { return Target; }
81
919k
  CXXRecordDecl *getNamingClass() const { return NamingClass; }
82
83
  // ...and these apply to hierarchy conversions.
84
15.5k
  CXXRecordDecl *getBaseClass() const {
85
15.5k
    assert(!IsMember); return cast<CXXRecordDecl>(Target);
86
15.5k
  }
87
0
  CXXRecordDecl *getDerivedClass() const { return NamingClass; }
88
89
  /// Retrieves the base object type, important when accessing
90
  /// an instance member.
91
1.20M
  QualType getBaseObjectType() const { return BaseObjectType; }
92
93
  /// Sets a diagnostic to be performed.  The diagnostic is given
94
  /// four (additional) arguments:
95
  ///   %0 - 0 if the entity was private, 1 if protected
96
  ///   %1 - the DeclarationName of the entity
97
  ///   %2 - the TypeDecl type of the naming class
98
  ///   %3 - the TypeDecl type of the declaring class
99
72.2k
  void setDiag(const PartialDiagnostic &PDiag) {
100
72.2k
    assert(isQuiet() && "partial diagnostic already defined");
101
72.2k
    Diag = PDiag;
102
72.2k
  }
103
854k
  PartialDiagnostic &setDiag(unsigned DiagID) {
104
854k
    assert(isQuiet() && "partial diagnostic already defined");
105
854k
    assert(DiagID && "creating null diagnostic");
106
854k
    Diag.Reset(DiagID);
107
854k
    return Diag;
108
854k
  }
109
4.88k
  const PartialDiagnostic &getDiag() const {
110
4.88k
    return Diag;
111
4.88k
  }
112
113
private:
114
  unsigned Access : 2;
115
  unsigned IsMember : 1;
116
  NamedDecl *Target;
117
  CXXRecordDecl *NamingClass;
118
  QualType BaseObjectType;
119
  PartialDiagnostic Diag;
120
};
121
122
/// A diagnostic message which has been conditionally emitted pending
123
/// the complete parsing of the current declaration.
124
class DelayedDiagnostic {
125
public:
126
  enum DDKind : unsigned char { Availability, Access, ForbiddenType };
127
128
  DDKind Kind;
129
  bool Triggered;
130
131
  SourceLocation Loc;
132
133
  void Destroy();
134
135
  static DelayedDiagnostic makeAvailability(AvailabilityResult AR,
136
                                            ArrayRef<SourceLocation> Locs,
137
                                            const NamedDecl *ReferringDecl,
138
                                            const NamedDecl *OffendingDecl,
139
                                            const ObjCInterfaceDecl *UnknownObjCClass,
140
                                            const ObjCPropertyDecl  *ObjCProperty,
141
                                            StringRef Msg,
142
                                            bool ObjCPropertyAccess);
143
144
  static DelayedDiagnostic makeAccess(SourceLocation Loc,
145
254k
                                      const AccessedEntity &Entity) {
146
254k
    DelayedDiagnostic DD;
147
254k
    DD.Kind = Access;
148
254k
    DD.Triggered = false;
149
254k
    DD.Loc = Loc;
150
254k
    new (&DD.getAccessData()) AccessedEntity(Entity);
151
254k
    return DD;
152
254k
  }
153
154
  static DelayedDiagnostic makeForbiddenType(SourceLocation loc,
155
                                             unsigned diagnostic,
156
                                             QualType type,
157
61
                                             unsigned argument) {
158
61
    DelayedDiagnostic DD;
159
61
    DD.Kind = ForbiddenType;
160
61
    DD.Triggered = false;
161
61
    DD.Loc = loc;
162
61
    DD.ForbiddenTypeData.Diagnostic = diagnostic;
163
61
    DD.ForbiddenTypeData.OperandType = type.getAsOpaquePtr();
164
61
    DD.ForbiddenTypeData.Argument = argument;
165
61
    return DD;
166
61
  }
167
168
748k
  AccessedEntity &getAccessData() {
169
748k
    assert(Kind == Access && "Not an access diagnostic.");
170
748k
    return *reinterpret_cast<AccessedEntity*>(AccessData);
171
748k
  }
172
0
  const AccessedEntity &getAccessData() const {
173
0
    assert(Kind == Access && "Not an access diagnostic.");
174
0
    return *reinterpret_cast<const AccessedEntity*>(AccessData);
175
0
  }
176
177
339k
  const NamedDecl *getAvailabilityReferringDecl() const {
178
339k
    assert(Kind == Availability && "Not an availability diagnostic.");
179
339k
    return AvailabilityData.ReferringDecl;
180
339k
  }
181
182
339k
  const NamedDecl *getAvailabilityOffendingDecl() const {
183
339k
    return AvailabilityData.OffendingDecl;
184
339k
  }
185
186
339k
  StringRef getAvailabilityMessage() const {
187
339k
    assert(Kind == Availability && "Not an availability diagnostic.");
188
339k
    return StringRef(AvailabilityData.Message, AvailabilityData.MessageLen);
189
339k
  }
190
191
339k
  ArrayRef<SourceLocation> getAvailabilitySelectorLocs() const {
192
339k
    assert(Kind == Availability && "Not an availability diagnostic.");
193
339k
    return llvm::makeArrayRef(AvailabilityData.SelectorLocs,
194
339k
                              AvailabilityData.NumSelectorLocs);
195
339k
  }
196
197
339k
  AvailabilityResult getAvailabilityResult() const {
198
339k
    assert(Kind == Availability && "Not an availability diagnostic.");
199
339k
    return AvailabilityData.AR;
200
339k
  }
201
202
  /// The diagnostic ID to emit.  Used like so:
203
  ///   Diag(diag.Loc, diag.getForbiddenTypeDiagnostic())
204
  ///     << diag.getForbiddenTypeOperand()
205
  ///     << diag.getForbiddenTypeArgument();
206
67
  unsigned getForbiddenTypeDiagnostic() const {
207
67
    assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
208
67
    return ForbiddenTypeData.Diagnostic;
209
67
  }
210
211
9
  unsigned getForbiddenTypeArgument() const {
212
9
    assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
213
9
    return ForbiddenTypeData.Argument;
214
9
  }
215
216
9
  QualType getForbiddenTypeOperand() const {
217
9
    assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
218
9
    return QualType::getFromOpaquePtr(ForbiddenTypeData.OperandType);
219
9
  }
220
221
339k
  const ObjCInterfaceDecl *getUnknownObjCClass() const {
222
339k
    return AvailabilityData.UnknownObjCClass;
223
339k
  }
224
225
339k
  const ObjCPropertyDecl *getObjCProperty() const {
226
339k
    return AvailabilityData.ObjCProperty;
227
339k
  }
228
229
0
  bool getObjCPropertyAccess() const {
230
0
    return AvailabilityData.ObjCPropertyAccess;
231
0
  }
232
233
private:
234
  struct AD {
235
    const NamedDecl *ReferringDecl;
236
    const NamedDecl *OffendingDecl;
237
    const ObjCInterfaceDecl *UnknownObjCClass;
238
    const ObjCPropertyDecl  *ObjCProperty;
239
    const char *Message;
240
    size_t MessageLen;
241
    SourceLocation *SelectorLocs;
242
    size_t NumSelectorLocs;
243
    AvailabilityResult AR;
244
    bool ObjCPropertyAccess;
245
  };
246
247
  struct FTD {
248
    unsigned Diagnostic;
249
    unsigned Argument;
250
    void *OperandType;
251
  };
252
253
  union {
254
    struct AD AvailabilityData;
255
    struct FTD ForbiddenTypeData;
256
257
    /// Access control.
258
    char AccessData[sizeof(AccessedEntity)];
259
  };
260
};
261
262
/// A collection of diagnostics which were delayed.
263
class DelayedDiagnosticPool {
264
  const DelayedDiagnosticPool *Parent;
265
  SmallVector<DelayedDiagnostic, 4> Diagnostics;
266
267
public:
268
61.7M
  DelayedDiagnosticPool(const DelayedDiagnosticPool *parent) : Parent(parent) {}
269
270
  DelayedDiagnosticPool(const DelayedDiagnosticPool &) = delete;
271
  DelayedDiagnosticPool &operator=(const DelayedDiagnosticPool &) = delete;
272
273
  DelayedDiagnosticPool(DelayedDiagnosticPool &&Other)
274
1.38M
      : Parent(Other.Parent), Diagnostics(std::move(Other.Diagnostics)) {
275
1.38M
    Other.Diagnostics.clear();
276
1.38M
  }
277
278
0
  DelayedDiagnosticPool &operator=(DelayedDiagnosticPool &&Other) {
279
0
    Parent = Other.Parent;
280
0
    Diagnostics = std::move(Other.Diagnostics);
281
0
    Other.Diagnostics.clear();
282
0
    return *this;
283
0
  }
284
285
63.0M
  ~DelayedDiagnosticPool() {
286
63.0M
    for (SmallVectorImpl<DelayedDiagnostic>::iterator
287
63.6M
           i = Diagnostics.begin(), e = Diagnostics.end(); i != e; 
++i594k
)
288
594k
      i->Destroy();
289
63.0M
  }
290
291
54.2M
  const DelayedDiagnosticPool *getParent() const { return Parent; }
292
293
  /// Does this pool, or any of its ancestors, contain any diagnostics?
294
0
  bool empty() const {
295
0
    return (Diagnostics.empty() && (!Parent || Parent->empty()));
296
0
  }
297
298
  /// Add a diagnostic to this pool.
299
594k
  void add(const DelayedDiagnostic &diag) {
300
594k
    Diagnostics.push_back(diag);
301
594k
  }
302
303
  /// Steal the diagnostics from the given pool.
304
1.15M
  void steal(DelayedDiagnosticPool &pool) {
305
1.15M
    if (pool.Diagnostics.empty()) 
return1.13M
;
306
307
17.9k
    if (Diagnostics.empty()) {
308
17.9k
      Diagnostics = std::move(pool.Diagnostics);
309
0
    } else {
310
0
      Diagnostics.append(pool.pool_begin(), pool.pool_end());
311
0
    }
312
17.9k
    pool.Diagnostics.clear();
313
17.9k
  }
314
315
  using pool_iterator = SmallVectorImpl<DelayedDiagnostic>::const_iterator;
316
317
53.1M
  pool_iterator pool_begin() const { return Diagnostics.begin(); }
318
53.1M
  pool_iterator pool_end() const { return Diagnostics.end(); }
319
9.85M
  bool pool_empty() const { return Diagnostics.empty(); }
320
};
321
322
} // namespace clang
323
324
/// Add a diagnostic to the current delay pool.
325
594k
inline void Sema::DelayedDiagnostics::add(const sema::DelayedDiagnostic &diag) {
326
594k
  assert(shouldDelayDiagnostics() && "trying to delay without pool");
327
594k
  CurPool->add(diag);
328
594k
}
329
330
} // namespace clang
331
332
#endif // LLVM_CLANG_SEMA_DELAYEDDIAGNOSTIC_H