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