DelayedDiagnostic.h revision 651f13cea278ec967336033dd032faef0e9fc2ec
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_DELAYED_DIAGNOSTIC_H 23#define LLVM_CLANG_SEMA_DELAYED_DIAGNOSTIC_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 { Deprecation, Unavailable, Access, ForbiddenType }; 117 118 unsigned char Kind; // actually a DDKind 119 bool Triggered; 120 121 SourceLocation Loc; 122 123 void Destroy(); 124 125 static DelayedDiagnostic makeAvailability(Sema::AvailabilityDiagnostic AD, 126 SourceLocation Loc, 127 const NamedDecl *D, 128 const ObjCInterfaceDecl *UnknownObjCClass, 129 const ObjCPropertyDecl *ObjCProperty, 130 StringRef Msg); 131 132 133 static DelayedDiagnostic makeAccess(SourceLocation Loc, 134 const AccessedEntity &Entity) { 135 DelayedDiagnostic DD; 136 DD.Kind = Access; 137 DD.Triggered = false; 138 DD.Loc = Loc; 139 new (&DD.getAccessData()) AccessedEntity(Entity); 140 return DD; 141 } 142 143 static DelayedDiagnostic makeForbiddenType(SourceLocation loc, 144 unsigned diagnostic, 145 QualType type, 146 unsigned argument) { 147 DelayedDiagnostic DD; 148 DD.Kind = ForbiddenType; 149 DD.Triggered = false; 150 DD.Loc = loc; 151 DD.ForbiddenTypeData.Diagnostic = diagnostic; 152 DD.ForbiddenTypeData.OperandType = type.getAsOpaquePtr(); 153 DD.ForbiddenTypeData.Argument = argument; 154 return DD; 155 } 156 157 AccessedEntity &getAccessData() { 158 assert(Kind == Access && "Not an access diagnostic."); 159 return *reinterpret_cast<AccessedEntity*>(AccessData); 160 } 161 const AccessedEntity &getAccessData() const { 162 assert(Kind == Access && "Not an access diagnostic."); 163 return *reinterpret_cast<const AccessedEntity*>(AccessData); 164 } 165 166 const NamedDecl *getDeprecationDecl() const { 167 assert((Kind == Deprecation || Kind == Unavailable) && 168 "Not a deprecation diagnostic."); 169 return DeprecationData.Decl; 170 } 171 172 StringRef getDeprecationMessage() const { 173 assert((Kind == Deprecation || Kind == Unavailable) && 174 "Not a deprecation diagnostic."); 175 return StringRef(DeprecationData.Message, 176 DeprecationData.MessageLen); 177 } 178 179 /// The diagnostic ID to emit. Used like so: 180 /// Diag(diag.Loc, diag.getForbiddenTypeDiagnostic()) 181 /// << diag.getForbiddenTypeOperand() 182 /// << diag.getForbiddenTypeArgument(); 183 unsigned getForbiddenTypeDiagnostic() const { 184 assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); 185 return ForbiddenTypeData.Diagnostic; 186 } 187 188 unsigned getForbiddenTypeArgument() const { 189 assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); 190 return ForbiddenTypeData.Argument; 191 } 192 193 QualType getForbiddenTypeOperand() const { 194 assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); 195 return QualType::getFromOpaquePtr(ForbiddenTypeData.OperandType); 196 } 197 198 const ObjCInterfaceDecl *getUnknownObjCClass() const { 199 return DeprecationData.UnknownObjCClass; 200 } 201 202 const ObjCPropertyDecl *getObjCProperty() const { 203 return DeprecationData.ObjCProperty; 204 } 205 206private: 207 208 struct DD { 209 const NamedDecl *Decl; 210 const ObjCInterfaceDecl *UnknownObjCClass; 211 const ObjCPropertyDecl *ObjCProperty; 212 const char *Message; 213 size_t MessageLen; 214 }; 215 216 struct FTD { 217 unsigned Diagnostic; 218 unsigned Argument; 219 void *OperandType; 220 }; 221 222 union { 223 /// Deprecation 224 struct DD DeprecationData; 225 struct FTD ForbiddenTypeData; 226 227 /// Access control. 228 char AccessData[sizeof(AccessedEntity)]; 229 }; 230}; 231 232/// \brief A collection of diagnostics which were delayed. 233class DelayedDiagnosticPool { 234 const DelayedDiagnosticPool *Parent; 235 SmallVector<DelayedDiagnostic, 4> Diagnostics; 236 237 DelayedDiagnosticPool(const DelayedDiagnosticPool &) LLVM_DELETED_FUNCTION; 238 void operator=(const DelayedDiagnosticPool &) LLVM_DELETED_FUNCTION; 239public: 240 DelayedDiagnosticPool(const DelayedDiagnosticPool *parent) : Parent(parent) {} 241 ~DelayedDiagnosticPool() { 242 for (SmallVectorImpl<DelayedDiagnostic>::iterator 243 i = Diagnostics.begin(), e = Diagnostics.end(); i != e; ++i) 244 i->Destroy(); 245 } 246 247 const DelayedDiagnosticPool *getParent() const { return Parent; } 248 249 /// Does this pool, or any of its ancestors, contain any diagnostics? 250 bool empty() const { 251 return (Diagnostics.empty() && (Parent == NULL || Parent->empty())); 252 } 253 254 /// Add a diagnostic to this pool. 255 void add(const DelayedDiagnostic &diag) { 256 Diagnostics.push_back(diag); 257 } 258 259 /// Steal the diagnostics from the given pool. 260 void steal(DelayedDiagnosticPool &pool) { 261 if (pool.Diagnostics.empty()) return; 262 263 if (Diagnostics.empty()) { 264 Diagnostics = std::move(pool.Diagnostics); 265 } else { 266 Diagnostics.append(pool.pool_begin(), pool.pool_end()); 267 } 268 pool.Diagnostics.clear(); 269 } 270 271 typedef SmallVectorImpl<DelayedDiagnostic>::const_iterator pool_iterator; 272 pool_iterator pool_begin() const { return Diagnostics.begin(); } 273 pool_iterator pool_end() const { return Diagnostics.end(); } 274 bool pool_empty() const { return Diagnostics.empty(); } 275}; 276 277} 278 279/// Add a diagnostic to the current delay pool. 280inline void Sema::DelayedDiagnostics::add(const sema::DelayedDiagnostic &diag) { 281 assert(shouldDelayDiagnostics() && "trying to delay without pool"); 282 CurPool->add(diag); 283} 284 285 286} 287 288#endif 289