1212795Sdim//===--- DelayedDiagnostic.h - Delayed declarator diagnostics ---*- C++ -*-===//
2212795Sdim//
3212795Sdim//                     The LLVM Compiler Infrastructure
4212795Sdim//
5212795Sdim// This file is distributed under the University of Illinois Open Source
6212795Sdim// License. See LICENSE.TXT for details.
7212795Sdim//
8212795Sdim//===----------------------------------------------------------------------===//
9212795Sdim//
10212795Sdim// This file defines the DelayedDiagnostic class, which is used to
11212795Sdim// record diagnostics that are being conditionally produced during
12212795Sdim// declarator parsing.  Certain kinds of diagnostics --- notably
13212795Sdim// deprecation and access control --- are suppressed based on
14212795Sdim// semantic properties of the parsed declaration that aren't known
15212795Sdim// until it is fully parsed.
16212795Sdim//
17212795Sdim// This file also defines AccessedEntity.
18212795Sdim//
19212795Sdim//===----------------------------------------------------------------------===//
20212795Sdim
21212795Sdim#ifndef LLVM_CLANG_SEMA_DELAYED_DIAGNOSTIC_H
22212795Sdim#define LLVM_CLANG_SEMA_DELAYED_DIAGNOSTIC_H
23212795Sdim
24239462Sdim#include "clang/Sema/Sema.h"
25212795Sdim
26212795Sdimnamespace clang {
27212795Sdimnamespace sema {
28212795Sdim
29212795Sdim/// A declaration being accessed, together with information about how
30212795Sdim/// it was accessed.
31212795Sdimclass AccessedEntity {
32212795Sdimpublic:
33212795Sdim  /// A member declaration found through lookup.  The target is the
34212795Sdim  /// member.
35212795Sdim  enum MemberNonce { Member };
36212795Sdim
37212795Sdim  /// A hierarchy (base-to-derived or derived-to-base) conversion.
38212795Sdim  /// The target is the base class.
39212795Sdim  enum BaseNonce { Base };
40212795Sdim
41212795Sdim  bool isMemberAccess() const { return IsMember; }
42212795Sdim
43239462Sdim  AccessedEntity(PartialDiagnostic::StorageAllocator &Allocator,
44212795Sdim                 MemberNonce _,
45212795Sdim                 CXXRecordDecl *NamingClass,
46212795Sdim                 DeclAccessPair FoundDecl,
47212795Sdim                 QualType BaseObjectType)
48212795Sdim    : Access(FoundDecl.getAccess()), IsMember(true),
49212795Sdim      Target(FoundDecl.getDecl()), NamingClass(NamingClass),
50239462Sdim      BaseObjectType(BaseObjectType), Diag(0, Allocator) {
51212795Sdim  }
52212795Sdim
53239462Sdim  AccessedEntity(PartialDiagnostic::StorageAllocator &Allocator,
54212795Sdim                 BaseNonce _,
55212795Sdim                 CXXRecordDecl *BaseClass,
56212795Sdim                 CXXRecordDecl *DerivedClass,
57212795Sdim                 AccessSpecifier Access)
58212795Sdim    : Access(Access), IsMember(false),
59212795Sdim      Target(BaseClass),
60212795Sdim      NamingClass(DerivedClass),
61239462Sdim      Diag(0, Allocator) {
62212795Sdim  }
63212795Sdim
64212795Sdim  bool isQuiet() const { return Diag.getDiagID() == 0; }
65212795Sdim
66212795Sdim  AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
67212795Sdim
68212795Sdim  // These apply to member decls...
69212795Sdim  NamedDecl *getTargetDecl() const { return Target; }
70212795Sdim  CXXRecordDecl *getNamingClass() const { return NamingClass; }
71212795Sdim
72212795Sdim  // ...and these apply to hierarchy conversions.
73212795Sdim  CXXRecordDecl *getBaseClass() const {
74212795Sdim    assert(!IsMember); return cast<CXXRecordDecl>(Target);
75212795Sdim  }
76212795Sdim  CXXRecordDecl *getDerivedClass() const { return NamingClass; }
77212795Sdim
78212795Sdim  /// Retrieves the base object type, important when accessing
79212795Sdim  /// an instance member.
80212795Sdim  QualType getBaseObjectType() const { return BaseObjectType; }
81212795Sdim
82212795Sdim  /// Sets a diagnostic to be performed.  The diagnostic is given
83212795Sdim  /// four (additional) arguments:
84212795Sdim  ///   %0 - 0 if the entity was private, 1 if protected
85212795Sdim  ///   %1 - the DeclarationName of the entity
86212795Sdim  ///   %2 - the TypeDecl type of the naming class
87212795Sdim  ///   %3 - the TypeDecl type of the declaring class
88212795Sdim  void setDiag(const PartialDiagnostic &PDiag) {
89212795Sdim    assert(isQuiet() && "partial diagnostic already defined");
90212795Sdim    Diag = PDiag;
91212795Sdim  }
92212795Sdim  PartialDiagnostic &setDiag(unsigned DiagID) {
93212795Sdim    assert(isQuiet() && "partial diagnostic already defined");
94212795Sdim    assert(DiagID && "creating null diagnostic");
95212795Sdim    Diag.Reset(DiagID);
96212795Sdim    return Diag;
97212795Sdim  }
98212795Sdim  const PartialDiagnostic &getDiag() const {
99212795Sdim    return Diag;
100212795Sdim  }
101212795Sdim
102212795Sdimprivate:
103212795Sdim  unsigned Access : 2;
104218893Sdim  unsigned IsMember : 1;
105212795Sdim  NamedDecl *Target;
106212795Sdim  CXXRecordDecl *NamingClass;
107212795Sdim  QualType BaseObjectType;
108212795Sdim  PartialDiagnostic Diag;
109212795Sdim};
110212795Sdim
111212795Sdim/// A diagnostic message which has been conditionally emitted pending
112212795Sdim/// the complete parsing of the current declaration.
113212795Sdimclass DelayedDiagnostic {
114212795Sdimpublic:
115224145Sdim  enum DDKind { Deprecation, Access, ForbiddenType };
116212795Sdim
117212795Sdim  unsigned char Kind; // actually a DDKind
118212795Sdim  bool Triggered;
119212795Sdim
120212795Sdim  SourceLocation Loc;
121212795Sdim
122221345Sdim  void Destroy();
123212795Sdim
124212795Sdim  static DelayedDiagnostic makeDeprecation(SourceLocation Loc,
125234353Sdim           const NamedDecl *D,
126234353Sdim           const ObjCInterfaceDecl *UnknownObjCClass,
127243830Sdim           const ObjCPropertyDecl  *ObjCProperty,
128234353Sdim           StringRef Msg);
129212795Sdim
130212795Sdim  static DelayedDiagnostic makeAccess(SourceLocation Loc,
131212795Sdim                                      const AccessedEntity &Entity) {
132212795Sdim    DelayedDiagnostic DD;
133212795Sdim    DD.Kind = Access;
134212795Sdim    DD.Triggered = false;
135212795Sdim    DD.Loc = Loc;
136212795Sdim    new (&DD.getAccessData()) AccessedEntity(Entity);
137212795Sdim    return DD;
138212795Sdim  }
139212795Sdim
140224145Sdim  static DelayedDiagnostic makeForbiddenType(SourceLocation loc,
141224145Sdim                                             unsigned diagnostic,
142224145Sdim                                             QualType type,
143224145Sdim                                             unsigned argument) {
144224145Sdim    DelayedDiagnostic DD;
145224145Sdim    DD.Kind = ForbiddenType;
146224145Sdim    DD.Triggered = false;
147224145Sdim    DD.Loc = loc;
148224145Sdim    DD.ForbiddenTypeData.Diagnostic = diagnostic;
149224145Sdim    DD.ForbiddenTypeData.OperandType = type.getAsOpaquePtr();
150224145Sdim    DD.ForbiddenTypeData.Argument = argument;
151224145Sdim    return DD;
152224145Sdim  }
153224145Sdim
154212795Sdim  AccessedEntity &getAccessData() {
155218893Sdim    assert(Kind == Access && "Not an access diagnostic.");
156212795Sdim    return *reinterpret_cast<AccessedEntity*>(AccessData);
157212795Sdim  }
158212795Sdim  const AccessedEntity &getAccessData() const {
159218893Sdim    assert(Kind == Access && "Not an access diagnostic.");
160212795Sdim    return *reinterpret_cast<const AccessedEntity*>(AccessData);
161212795Sdim  }
162218893Sdim
163218893Sdim  const NamedDecl *getDeprecationDecl() const {
164218893Sdim    assert(Kind == Deprecation && "Not a deprecation diagnostic.");
165218893Sdim    return DeprecationData.Decl;
166218893Sdim  }
167218893Sdim
168226633Sdim  StringRef getDeprecationMessage() const {
169218893Sdim    assert(Kind == Deprecation && "Not a deprecation diagnostic.");
170226633Sdim    return StringRef(DeprecationData.Message,
171218893Sdim                           DeprecationData.MessageLen);
172218893Sdim  }
173218893Sdim
174224145Sdim  /// The diagnostic ID to emit.  Used like so:
175224145Sdim  ///   Diag(diag.Loc, diag.getForbiddenTypeDiagnostic())
176224145Sdim  ///     << diag.getForbiddenTypeOperand()
177224145Sdim  ///     << diag.getForbiddenTypeArgument();
178224145Sdim  unsigned getForbiddenTypeDiagnostic() const {
179224145Sdim    assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
180224145Sdim    return ForbiddenTypeData.Diagnostic;
181224145Sdim  }
182224145Sdim
183224145Sdim  unsigned getForbiddenTypeArgument() const {
184224145Sdim    assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
185224145Sdim    return ForbiddenTypeData.Argument;
186224145Sdim  }
187224145Sdim
188224145Sdim  QualType getForbiddenTypeOperand() const {
189224145Sdim    assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
190224145Sdim    return QualType::getFromOpaquePtr(ForbiddenTypeData.OperandType);
191224145Sdim  }
192234353Sdim
193234353Sdim  const ObjCInterfaceDecl *getUnknownObjCClass() const {
194234353Sdim    return DeprecationData.UnknownObjCClass;
195234353Sdim  }
196224145Sdim
197243830Sdim  const ObjCPropertyDecl *getObjCProperty() const {
198243830Sdim    return DeprecationData.ObjCProperty;
199243830Sdim  }
200243830Sdim
201218893Sdimprivate:
202249423Sdim
203249423Sdim  struct DD {
204249423Sdim    const NamedDecl *Decl;
205249423Sdim    const ObjCInterfaceDecl *UnknownObjCClass;
206249423Sdim    const ObjCPropertyDecl  *ObjCProperty;
207249423Sdim    const char *Message;
208249423Sdim    size_t MessageLen;
209249423Sdim  };
210249423Sdim
211249423Sdim  struct FTD {
212249423Sdim    unsigned Diagnostic;
213249423Sdim    unsigned Argument;
214249423Sdim    void *OperandType;
215249423Sdim  };
216249423Sdim
217218893Sdim  union {
218249423Sdim    /// Deprecation
219249423Sdim    struct DD DeprecationData;
220249423Sdim    struct FTD ForbiddenTypeData;
221218893Sdim
222218893Sdim    /// Access control.
223218893Sdim    char AccessData[sizeof(AccessedEntity)];
224218893Sdim  };
225212795Sdim};
226212795Sdim
227239462Sdim/// DelayedDiagnosticPool - A collection of diagnostics which were
228239462Sdim/// delayed.
229239462Sdimclass DelayedDiagnosticPool {
230239462Sdim  const DelayedDiagnosticPool *Parent;
231249423Sdim  SmallVector<DelayedDiagnostic, 4> Diagnostics;
232239462Sdim
233243830Sdim  DelayedDiagnosticPool(const DelayedDiagnosticPool &) LLVM_DELETED_FUNCTION;
234243830Sdim  void operator=(const DelayedDiagnosticPool &) LLVM_DELETED_FUNCTION;
235239462Sdimpublic:
236239462Sdim  DelayedDiagnosticPool(const DelayedDiagnosticPool *parent) : Parent(parent) {}
237239462Sdim  ~DelayedDiagnosticPool() {
238249423Sdim    for (SmallVectorImpl<DelayedDiagnostic>::iterator
239239462Sdim           i = Diagnostics.begin(), e = Diagnostics.end(); i != e; ++i)
240239462Sdim      i->Destroy();
241239462Sdim  }
242239462Sdim
243239462Sdim  const DelayedDiagnosticPool *getParent() const { return Parent; }
244239462Sdim
245239462Sdim  /// Does this pool, or any of its ancestors, contain any diagnostics?
246239462Sdim  bool empty() const {
247239462Sdim    return (Diagnostics.empty() && (Parent == NULL || Parent->empty()));
248239462Sdim  }
249239462Sdim
250239462Sdim  /// Add a diagnostic to this pool.
251239462Sdim  void add(const DelayedDiagnostic &diag) {
252239462Sdim    Diagnostics.push_back(diag);
253239462Sdim  }
254239462Sdim
255239462Sdim  /// Steal the diagnostics from the given pool.
256239462Sdim  void steal(DelayedDiagnosticPool &pool) {
257239462Sdim    if (pool.Diagnostics.empty()) return;
258239462Sdim
259239462Sdim    if (Diagnostics.empty()) {
260239462Sdim      Diagnostics = llvm_move(pool.Diagnostics);
261239462Sdim    } else {
262239462Sdim      Diagnostics.append(pool.pool_begin(), pool.pool_end());
263239462Sdim    }
264239462Sdim    pool.Diagnostics.clear();
265239462Sdim  }
266239462Sdim
267249423Sdim  typedef SmallVectorImpl<DelayedDiagnostic>::const_iterator pool_iterator;
268239462Sdim  pool_iterator pool_begin() const { return Diagnostics.begin(); }
269239462Sdim  pool_iterator pool_end() const { return Diagnostics.end(); }
270239462Sdim  bool pool_empty() const { return Diagnostics.empty(); }
271239462Sdim};
272239462Sdim
273212795Sdim}
274239462Sdim
275239462Sdim/// Add a diagnostic to the current delay pool.
276239462Sdiminline void Sema::DelayedDiagnostics::add(const sema::DelayedDiagnostic &diag) {
277239462Sdim  assert(shouldDelayDiagnostics() && "trying to delay without pool");
278239462Sdim  CurPool->add(diag);
279212795Sdim}
280212795Sdim
281239462Sdim
282239462Sdim}
283239462Sdim
284212795Sdim#endif
285