clang API Documentation
00001 //===--- DelayedDiagnostic.h - Delayed declarator diagnostics ---*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 /// 00010 /// \file 00011 /// \brief Defines the classes clang::DelayedDiagnostic and 00012 /// clang::AccessedEntity. 00013 /// 00014 /// DelayedDiangostic is used to record diagnostics that are being 00015 /// conditionally produced during declarator parsing. Certain kinds of 00016 /// diagnostics -- notably deprecation and access control -- are suppressed 00017 /// based on semantic properties of the parsed declaration that aren't known 00018 /// until it is fully parsed. 00019 /// 00020 //===----------------------------------------------------------------------===// 00021 00022 #ifndef LLVM_CLANG_SEMA_DELAYEDDIAGNOSTIC_H 00023 #define LLVM_CLANG_SEMA_DELAYEDDIAGNOSTIC_H 00024 00025 #include "clang/Sema/Sema.h" 00026 00027 namespace clang { 00028 namespace sema { 00029 00030 /// A declaration being accessed, together with information about how 00031 /// it was accessed. 00032 class AccessedEntity { 00033 public: 00034 /// A member declaration found through lookup. The target is the 00035 /// member. 00036 enum MemberNonce { Member }; 00037 00038 /// A hierarchy (base-to-derived or derived-to-base) conversion. 00039 /// The target is the base class. 00040 enum BaseNonce { Base }; 00041 00042 bool isMemberAccess() const { return IsMember; } 00043 00044 AccessedEntity(PartialDiagnostic::StorageAllocator &Allocator, 00045 MemberNonce _, 00046 CXXRecordDecl *NamingClass, 00047 DeclAccessPair FoundDecl, 00048 QualType BaseObjectType) 00049 : Access(FoundDecl.getAccess()), IsMember(true), 00050 Target(FoundDecl.getDecl()), NamingClass(NamingClass), 00051 BaseObjectType(BaseObjectType), Diag(0, Allocator) { 00052 } 00053 00054 AccessedEntity(PartialDiagnostic::StorageAllocator &Allocator, 00055 BaseNonce _, 00056 CXXRecordDecl *BaseClass, 00057 CXXRecordDecl *DerivedClass, 00058 AccessSpecifier Access) 00059 : Access(Access), IsMember(false), 00060 Target(BaseClass), 00061 NamingClass(DerivedClass), 00062 Diag(0, Allocator) { 00063 } 00064 00065 bool isQuiet() const { return Diag.getDiagID() == 0; } 00066 00067 AccessSpecifier getAccess() const { return AccessSpecifier(Access); } 00068 00069 // These apply to member decls... 00070 NamedDecl *getTargetDecl() const { return Target; } 00071 CXXRecordDecl *getNamingClass() const { return NamingClass; } 00072 00073 // ...and these apply to hierarchy conversions. 00074 CXXRecordDecl *getBaseClass() const { 00075 assert(!IsMember); return cast<CXXRecordDecl>(Target); 00076 } 00077 CXXRecordDecl *getDerivedClass() const { return NamingClass; } 00078 00079 /// Retrieves the base object type, important when accessing 00080 /// an instance member. 00081 QualType getBaseObjectType() const { return BaseObjectType; } 00082 00083 /// Sets a diagnostic to be performed. The diagnostic is given 00084 /// four (additional) arguments: 00085 /// %0 - 0 if the entity was private, 1 if protected 00086 /// %1 - the DeclarationName of the entity 00087 /// %2 - the TypeDecl type of the naming class 00088 /// %3 - the TypeDecl type of the declaring class 00089 void setDiag(const PartialDiagnostic &PDiag) { 00090 assert(isQuiet() && "partial diagnostic already defined"); 00091 Diag = PDiag; 00092 } 00093 PartialDiagnostic &setDiag(unsigned DiagID) { 00094 assert(isQuiet() && "partial diagnostic already defined"); 00095 assert(DiagID && "creating null diagnostic"); 00096 Diag.Reset(DiagID); 00097 return Diag; 00098 } 00099 const PartialDiagnostic &getDiag() const { 00100 return Diag; 00101 } 00102 00103 private: 00104 unsigned Access : 2; 00105 unsigned IsMember : 1; 00106 NamedDecl *Target; 00107 CXXRecordDecl *NamingClass; 00108 QualType BaseObjectType; 00109 PartialDiagnostic Diag; 00110 }; 00111 00112 /// A diagnostic message which has been conditionally emitted pending 00113 /// the complete parsing of the current declaration. 00114 class DelayedDiagnostic { 00115 public: 00116 enum DDKind { Deprecation, Unavailable, Access, ForbiddenType }; 00117 00118 unsigned char Kind; // actually a DDKind 00119 bool Triggered; 00120 00121 SourceLocation Loc; 00122 00123 void Destroy(); 00124 00125 static DelayedDiagnostic makeAvailability(Sema::AvailabilityDiagnostic AD, 00126 SourceLocation Loc, 00127 const NamedDecl *D, 00128 const ObjCInterfaceDecl *UnknownObjCClass, 00129 const ObjCPropertyDecl *ObjCProperty, 00130 StringRef Msg, 00131 bool ObjCPropertyAccess); 00132 00133 00134 static DelayedDiagnostic makeAccess(SourceLocation Loc, 00135 const AccessedEntity &Entity) { 00136 DelayedDiagnostic DD; 00137 DD.Kind = Access; 00138 DD.Triggered = false; 00139 DD.Loc = Loc; 00140 new (&DD.getAccessData()) AccessedEntity(Entity); 00141 return DD; 00142 } 00143 00144 static DelayedDiagnostic makeForbiddenType(SourceLocation loc, 00145 unsigned diagnostic, 00146 QualType type, 00147 unsigned argument) { 00148 DelayedDiagnostic DD; 00149 DD.Kind = ForbiddenType; 00150 DD.Triggered = false; 00151 DD.Loc = loc; 00152 DD.ForbiddenTypeData.Diagnostic = diagnostic; 00153 DD.ForbiddenTypeData.OperandType = type.getAsOpaquePtr(); 00154 DD.ForbiddenTypeData.Argument = argument; 00155 return DD; 00156 } 00157 00158 AccessedEntity &getAccessData() { 00159 assert(Kind == Access && "Not an access diagnostic."); 00160 return *reinterpret_cast<AccessedEntity*>(AccessData); 00161 } 00162 const AccessedEntity &getAccessData() const { 00163 assert(Kind == Access && "Not an access diagnostic."); 00164 return *reinterpret_cast<const AccessedEntity*>(AccessData); 00165 } 00166 00167 const NamedDecl *getDeprecationDecl() const { 00168 assert((Kind == Deprecation || Kind == Unavailable) && 00169 "Not a deprecation diagnostic."); 00170 return DeprecationData.Decl; 00171 } 00172 00173 StringRef getDeprecationMessage() const { 00174 assert((Kind == Deprecation || Kind == Unavailable) && 00175 "Not a deprecation diagnostic."); 00176 return StringRef(DeprecationData.Message, 00177 DeprecationData.MessageLen); 00178 } 00179 00180 /// The diagnostic ID to emit. Used like so: 00181 /// Diag(diag.Loc, diag.getForbiddenTypeDiagnostic()) 00182 /// << diag.getForbiddenTypeOperand() 00183 /// << diag.getForbiddenTypeArgument(); 00184 unsigned getForbiddenTypeDiagnostic() const { 00185 assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); 00186 return ForbiddenTypeData.Diagnostic; 00187 } 00188 00189 unsigned getForbiddenTypeArgument() const { 00190 assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); 00191 return ForbiddenTypeData.Argument; 00192 } 00193 00194 QualType getForbiddenTypeOperand() const { 00195 assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); 00196 return QualType::getFromOpaquePtr(ForbiddenTypeData.OperandType); 00197 } 00198 00199 const ObjCInterfaceDecl *getUnknownObjCClass() const { 00200 return DeprecationData.UnknownObjCClass; 00201 } 00202 00203 const ObjCPropertyDecl *getObjCProperty() const { 00204 return DeprecationData.ObjCProperty; 00205 } 00206 00207 bool getObjCPropertyAccess() const { 00208 return DeprecationData.ObjCPropertyAccess; 00209 } 00210 00211 private: 00212 00213 struct DD { 00214 const NamedDecl *Decl; 00215 const ObjCInterfaceDecl *UnknownObjCClass; 00216 const ObjCPropertyDecl *ObjCProperty; 00217 const char *Message; 00218 size_t MessageLen; 00219 bool ObjCPropertyAccess; 00220 }; 00221 00222 struct FTD { 00223 unsigned Diagnostic; 00224 unsigned Argument; 00225 void *OperandType; 00226 }; 00227 00228 union { 00229 /// Deprecation 00230 struct DD DeprecationData; 00231 struct FTD ForbiddenTypeData; 00232 00233 /// Access control. 00234 char AccessData[sizeof(AccessedEntity)]; 00235 }; 00236 }; 00237 00238 /// \brief A collection of diagnostics which were delayed. 00239 class DelayedDiagnosticPool { 00240 const DelayedDiagnosticPool *Parent; 00241 SmallVector<DelayedDiagnostic, 4> Diagnostics; 00242 00243 DelayedDiagnosticPool(const DelayedDiagnosticPool &) LLVM_DELETED_FUNCTION; 00244 void operator=(const DelayedDiagnosticPool &) LLVM_DELETED_FUNCTION; 00245 public: 00246 DelayedDiagnosticPool(const DelayedDiagnosticPool *parent) : Parent(parent) {} 00247 ~DelayedDiagnosticPool() { 00248 for (SmallVectorImpl<DelayedDiagnostic>::iterator 00249 i = Diagnostics.begin(), e = Diagnostics.end(); i != e; ++i) 00250 i->Destroy(); 00251 } 00252 00253 const DelayedDiagnosticPool *getParent() const { return Parent; } 00254 00255 /// Does this pool, or any of its ancestors, contain any diagnostics? 00256 bool empty() const { 00257 return (Diagnostics.empty() && (!Parent || Parent->empty())); 00258 } 00259 00260 /// Add a diagnostic to this pool. 00261 void add(const DelayedDiagnostic &diag) { 00262 Diagnostics.push_back(diag); 00263 } 00264 00265 /// Steal the diagnostics from the given pool. 00266 void steal(DelayedDiagnosticPool &pool) { 00267 if (pool.Diagnostics.empty()) return; 00268 00269 if (Diagnostics.empty()) { 00270 Diagnostics = std::move(pool.Diagnostics); 00271 } else { 00272 Diagnostics.append(pool.pool_begin(), pool.pool_end()); 00273 } 00274 pool.Diagnostics.clear(); 00275 } 00276 00277 typedef SmallVectorImpl<DelayedDiagnostic>::const_iterator pool_iterator; 00278 pool_iterator pool_begin() const { return Diagnostics.begin(); } 00279 pool_iterator pool_end() const { return Diagnostics.end(); } 00280 bool pool_empty() const { return Diagnostics.empty(); } 00281 }; 00282 00283 } 00284 00285 /// Add a diagnostic to the current delay pool. 00286 inline void Sema::DelayedDiagnostics::add(const sema::DelayedDiagnostic &diag) { 00287 assert(shouldDelayDiagnostics() && "trying to delay without pool"); 00288 CurPool->add(diag); 00289 } 00290 00291 00292 } 00293 00294 #endif