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/AST/DeclCXX.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(ASTContext &Context,
     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, Context.getDiagAllocator()) {
     51   }
     52 
     53   AccessedEntity(ASTContext &Context,
     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, Context.getDiagAllocator()) {
     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                                            StringRef Msg);
    127 
    128   static DelayedDiagnostic makeAccess(SourceLocation Loc,
    129                                       const AccessedEntity &Entity) {
    130     DelayedDiagnostic DD;
    131     DD.Kind = Access;
    132     DD.Triggered = false;
    133     DD.Loc = Loc;
    134     new (&DD.getAccessData()) AccessedEntity(Entity);
    135     return DD;
    136   }
    137 
    138   static DelayedDiagnostic makeForbiddenType(SourceLocation loc,
    139                                              unsigned diagnostic,
    140                                              QualType type,
    141                                              unsigned argument) {
    142     DelayedDiagnostic DD;
    143     DD.Kind = ForbiddenType;
    144     DD.Triggered = false;
    145     DD.Loc = loc;
    146     DD.ForbiddenTypeData.Diagnostic = diagnostic;
    147     DD.ForbiddenTypeData.OperandType = type.getAsOpaquePtr();
    148     DD.ForbiddenTypeData.Argument = argument;
    149     return DD;
    150   }
    151 
    152   AccessedEntity &getAccessData() {
    153     assert(Kind == Access && "Not an access diagnostic.");
    154     return *reinterpret_cast<AccessedEntity*>(AccessData);
    155   }
    156   const AccessedEntity &getAccessData() const {
    157     assert(Kind == Access && "Not an access diagnostic.");
    158     return *reinterpret_cast<const AccessedEntity*>(AccessData);
    159   }
    160 
    161   const NamedDecl *getDeprecationDecl() const {
    162     assert(Kind == Deprecation && "Not a deprecation diagnostic.");
    163     return DeprecationData.Decl;
    164   }
    165 
    166   StringRef getDeprecationMessage() const {
    167     assert(Kind == Deprecation && "Not a deprecation diagnostic.");
    168     return StringRef(DeprecationData.Message,
    169                            DeprecationData.MessageLen);
    170   }
    171 
    172   /// The diagnostic ID to emit.  Used like so:
    173   ///   Diag(diag.Loc, diag.getForbiddenTypeDiagnostic())
    174   ///     << diag.getForbiddenTypeOperand()
    175   ///     << diag.getForbiddenTypeArgument();
    176   unsigned getForbiddenTypeDiagnostic() const {
    177     assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
    178     return ForbiddenTypeData.Diagnostic;
    179   }
    180 
    181   unsigned getForbiddenTypeArgument() const {
    182     assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
    183     return ForbiddenTypeData.Argument;
    184   }
    185 
    186   QualType getForbiddenTypeOperand() const {
    187     assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
    188     return QualType::getFromOpaquePtr(ForbiddenTypeData.OperandType);
    189   }
    190 
    191 private:
    192   union {
    193     /// Deprecation.
    194     struct {
    195       const NamedDecl *Decl;
    196       const char *Message;
    197       size_t MessageLen;
    198     } DeprecationData;
    199 
    200     struct {
    201       unsigned Diagnostic;
    202       unsigned Argument;
    203       void *OperandType;
    204     } ForbiddenTypeData;
    205 
    206     /// Access control.
    207     char AccessData[sizeof(AccessedEntity)];
    208   };
    209 };
    210 
    211 }
    212 }
    213 
    214 #endif
    215