Home | History | Annotate | Download | only in Sema
      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 // This file defines the DelayedDiagnostic class, which is used to
     11 // record diagnostics that are being conditionally produced during
     12 // declarator parsing.  Certain kinds of diagnostics --- notably
     13 // deprecation and access control --- are suppressed based on
     14 // semantic properties of the parsed declaration that aren't known
     15 // until it is fully parsed.
     16 //
     17 // This file also defines AccessedEntity.
     18 //
     19 //===----------------------------------------------------------------------===//
     20 
     21 #ifndef LLVM_CLANG_SEMA_DELAYED_DIAGNOSTIC_H
     22 #define LLVM_CLANG_SEMA_DELAYED_DIAGNOSTIC_H
     23 
     24 #include "clang/Sema/Sema.h"
     25 
     26 namespace clang {
     27 namespace sema {
     28 
     29 /// A declaration being accessed, together with information about how
     30 /// it was accessed.
     31 class AccessedEntity {
     32 public:
     33   /// A member declaration found through lookup.  The target is the
     34   /// member.
     35   enum MemberNonce { Member };
     36 
     37   /// A hierarchy (base-to-derived or derived-to-base) conversion.
     38   /// The target is the base class.
     39   enum BaseNonce { Base };
     40 
     41   bool isMemberAccess() const { return IsMember; }
     42 
     43   AccessedEntity(PartialDiagnostic::StorageAllocator &Allocator,
     44                  MemberNonce _,
     45                  CXXRecordDecl *NamingClass,
     46                  DeclAccessPair FoundDecl,
     47                  QualType BaseObjectType)
     48     : Access(FoundDecl.getAccess()), IsMember(true),
     49       Target(FoundDecl.getDecl()), NamingClass(NamingClass),
     50       BaseObjectType(BaseObjectType), Diag(0, Allocator) {
     51   }
     52 
     53   AccessedEntity(PartialDiagnostic::StorageAllocator &Allocator,
     54                  BaseNonce _,
     55                  CXXRecordDecl *BaseClass,
     56                  CXXRecordDecl *DerivedClass,
     57                  AccessSpecifier Access)
     58     : Access(Access), IsMember(false),
     59       Target(BaseClass),
     60       NamingClass(DerivedClass),
     61       Diag(0, Allocator) {
     62   }
     63 
     64   bool isQuiet() const { return Diag.getDiagID() == 0; }
     65 
     66   AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
     67 
     68   // These apply to member decls...
     69   NamedDecl *getTargetDecl() const { return Target; }
     70   CXXRecordDecl *getNamingClass() const { return NamingClass; }
     71 
     72   // ...and these apply to hierarchy conversions.
     73   CXXRecordDecl *getBaseClass() const {
     74     assert(!IsMember); return cast<CXXRecordDecl>(Target);
     75   }
     76   CXXRecordDecl *getDerivedClass() const { return NamingClass; }
     77 
     78   /// Retrieves the base object type, important when accessing
     79   /// an instance member.
     80   QualType getBaseObjectType() const { return BaseObjectType; }
     81 
     82   /// Sets a diagnostic to be performed.  The diagnostic is given
     83   /// four (additional) arguments:
     84   ///   %0 - 0 if the entity was private, 1 if protected
     85   ///   %1 - the DeclarationName of the entity
     86   ///   %2 - the TypeDecl type of the naming class
     87   ///   %3 - the TypeDecl type of the declaring class
     88   void setDiag(const PartialDiagnostic &PDiag) {
     89     assert(isQuiet() && "partial diagnostic already defined");
     90     Diag = PDiag;
     91   }
     92   PartialDiagnostic &setDiag(unsigned DiagID) {
     93     assert(isQuiet() && "partial diagnostic already defined");
     94     assert(DiagID && "creating null diagnostic");
     95     Diag.Reset(DiagID);
     96     return Diag;
     97   }
     98   const PartialDiagnostic &getDiag() const {
     99     return Diag;
    100   }
    101 
    102 private:
    103   unsigned Access : 2;
    104   unsigned IsMember : 1;
    105   NamedDecl *Target;
    106   CXXRecordDecl *NamingClass;
    107   QualType BaseObjectType;
    108   PartialDiagnostic Diag;
    109 };
    110 
    111 /// A diagnostic message which has been conditionally emitted pending
    112 /// the complete parsing of the current declaration.
    113 class DelayedDiagnostic {
    114 public:
    115   enum DDKind { Deprecation, Access, ForbiddenType };
    116 
    117   unsigned char Kind; // actually a DDKind
    118   bool Triggered;
    119 
    120   SourceLocation Loc;
    121 
    122   void Destroy();
    123 
    124   static DelayedDiagnostic makeDeprecation(SourceLocation Loc,
    125            const NamedDecl *D,
    126            const ObjCInterfaceDecl *UnknownObjCClass,
    127            const ObjCPropertyDecl  *ObjCProperty,
    128            StringRef Msg);
    129 
    130   static DelayedDiagnostic makeAccess(SourceLocation Loc,
    131                                       const AccessedEntity &Entity) {
    132     DelayedDiagnostic DD;
    133     DD.Kind = Access;
    134     DD.Triggered = false;
    135     DD.Loc = Loc;
    136     new (&DD.getAccessData()) AccessedEntity(Entity);
    137     return DD;
    138   }
    139 
    140   static DelayedDiagnostic makeForbiddenType(SourceLocation loc,
    141                                              unsigned diagnostic,
    142                                              QualType type,
    143                                              unsigned argument) {
    144     DelayedDiagnostic DD;
    145     DD.Kind = ForbiddenType;
    146     DD.Triggered = false;
    147     DD.Loc = loc;
    148     DD.ForbiddenTypeData.Diagnostic = diagnostic;
    149     DD.ForbiddenTypeData.OperandType = type.getAsOpaquePtr();
    150     DD.ForbiddenTypeData.Argument = argument;
    151     return DD;
    152   }
    153 
    154   AccessedEntity &getAccessData() {
    155     assert(Kind == Access && "Not an access diagnostic.");
    156     return *reinterpret_cast<AccessedEntity*>(AccessData);
    157   }
    158   const AccessedEntity &getAccessData() const {
    159     assert(Kind == Access && "Not an access diagnostic.");
    160     return *reinterpret_cast<const AccessedEntity*>(AccessData);
    161   }
    162 
    163   const NamedDecl *getDeprecationDecl() const {
    164     assert(Kind == Deprecation && "Not a deprecation diagnostic.");
    165     return DeprecationData.Decl;
    166   }
    167 
    168   StringRef getDeprecationMessage() const {
    169     assert(Kind == Deprecation && "Not a deprecation diagnostic.");
    170     return StringRef(DeprecationData.Message,
    171                            DeprecationData.MessageLen);
    172   }
    173 
    174   /// The diagnostic ID to emit.  Used like so:
    175   ///   Diag(diag.Loc, diag.getForbiddenTypeDiagnostic())
    176   ///     << diag.getForbiddenTypeOperand()
    177   ///     << diag.getForbiddenTypeArgument();
    178   unsigned getForbiddenTypeDiagnostic() const {
    179     assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
    180     return ForbiddenTypeData.Diagnostic;
    181   }
    182 
    183   unsigned getForbiddenTypeArgument() const {
    184     assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
    185     return ForbiddenTypeData.Argument;
    186   }
    187 
    188   QualType getForbiddenTypeOperand() const {
    189     assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
    190     return QualType::getFromOpaquePtr(ForbiddenTypeData.OperandType);
    191   }
    192 
    193   const ObjCInterfaceDecl *getUnknownObjCClass() const {
    194     return DeprecationData.UnknownObjCClass;
    195   }
    196 
    197   const ObjCPropertyDecl *getObjCProperty() const {
    198     return DeprecationData.ObjCProperty;
    199   }
    200 
    201 private:
    202 
    203   struct DD {
    204     const NamedDecl *Decl;
    205     const ObjCInterfaceDecl *UnknownObjCClass;
    206     const ObjCPropertyDecl  *ObjCProperty;
    207     const char *Message;
    208     size_t MessageLen;
    209   };
    210 
    211   struct FTD {
    212     unsigned Diagnostic;
    213     unsigned Argument;
    214     void *OperandType;
    215   };
    216 
    217   union {
    218     /// Deprecation
    219     struct DD DeprecationData;
    220     struct FTD ForbiddenTypeData;
    221 
    222     /// Access control.
    223     char AccessData[sizeof(AccessedEntity)];
    224   };
    225 };
    226 
    227 /// DelayedDiagnosticPool - A collection of diagnostics which were
    228 /// delayed.
    229 class 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;
    235 public:
    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.
    276 inline 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