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