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