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