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