Home | History | Annotate | Line # | Download | only in AST
      1 //==- DependentDiagnostic.h - Dependently-generated diagnostics --*- C++ -*-==//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 //  This file defines interfaces for diagnostics which may or may
     10 //  fire based on how a template is instantiated.
     11 //
     12 //  At the moment, the only consumer of this interface is access
     13 //  control.
     14 //
     15 //===----------------------------------------------------------------------===//
     16 
     17 #ifndef LLVM_CLANG_AST_DEPENDENTDIAGNOSTIC_H
     18 #define LLVM_CLANG_AST_DEPENDENTDIAGNOSTIC_H
     19 
     20 #include "clang/AST/DeclBase.h"
     21 #include "clang/AST/DeclContextInternals.h"
     22 #include "clang/AST/Type.h"
     23 #include "clang/Basic/PartialDiagnostic.h"
     24 #include "clang/Basic/SourceLocation.h"
     25 #include "clang/Basic/Specifiers.h"
     26 #include <cassert>
     27 #include <iterator>
     28 
     29 namespace clang {
     30 
     31 class ASTContext;
     32 class CXXRecordDecl;
     33 class NamedDecl;
     34 
     35 /// A dependently-generated diagnostic.
     36 class DependentDiagnostic {
     37 public:
     38   enum AccessNonce { Access = 0 };
     39 
     40   static DependentDiagnostic *Create(ASTContext &Context,
     41                                      DeclContext *Parent,
     42                                      AccessNonce _,
     43                                      SourceLocation Loc,
     44                                      bool IsMemberAccess,
     45                                      AccessSpecifier AS,
     46                                      NamedDecl *TargetDecl,
     47                                      CXXRecordDecl *NamingClass,
     48                                      QualType BaseObjectType,
     49                                      const PartialDiagnostic &PDiag) {
     50     DependentDiagnostic *DD = Create(Context, Parent, PDiag);
     51     DD->AccessData.Loc = Loc;
     52     DD->AccessData.IsMember = IsMemberAccess;
     53     DD->AccessData.Access = AS;
     54     DD->AccessData.TargetDecl = TargetDecl;
     55     DD->AccessData.NamingClass = NamingClass;
     56     DD->AccessData.BaseObjectType = BaseObjectType.getAsOpaquePtr();
     57     return DD;
     58   }
     59 
     60   unsigned getKind() const {
     61     return Access;
     62   }
     63 
     64   bool isAccessToMember() const {
     65     assert(getKind() == Access);
     66     return AccessData.IsMember;
     67   }
     68 
     69   AccessSpecifier getAccess() const {
     70     assert(getKind() == Access);
     71     return AccessSpecifier(AccessData.Access);
     72   }
     73 
     74   SourceLocation getAccessLoc() const {
     75     assert(getKind() == Access);
     76     return AccessData.Loc;
     77   }
     78 
     79   NamedDecl *getAccessTarget() const {
     80     assert(getKind() == Access);
     81     return AccessData.TargetDecl;
     82   }
     83 
     84   NamedDecl *getAccessNamingClass() const {
     85     assert(getKind() == Access);
     86     return AccessData.NamingClass;
     87   }
     88 
     89   QualType getAccessBaseObjectType() const {
     90     assert(getKind() == Access);
     91     return QualType::getFromOpaquePtr(AccessData.BaseObjectType);
     92   }
     93 
     94   const PartialDiagnostic &getDiagnostic() const {
     95     return Diag;
     96   }
     97 
     98 private:
     99   friend class DeclContext::ddiag_iterator;
    100   friend class DependentStoredDeclsMap;
    101 
    102   DependentDiagnostic(const PartialDiagnostic &PDiag,
    103                       DiagnosticStorage *Storage)
    104       : Diag(PDiag, Storage) {}
    105 
    106   static DependentDiagnostic *Create(ASTContext &Context,
    107                                      DeclContext *Parent,
    108                                      const PartialDiagnostic &PDiag);
    109 
    110   DependentDiagnostic *NextDiagnostic;
    111 
    112   PartialDiagnostic Diag;
    113 
    114   struct {
    115     SourceLocation Loc;
    116     unsigned Access : 2;
    117     unsigned IsMember : 1;
    118     NamedDecl *TargetDecl;
    119     CXXRecordDecl *NamingClass;
    120     void *BaseObjectType;
    121   } AccessData;
    122 };
    123 
    124 /// An iterator over the dependent diagnostics in a dependent context.
    125 class DeclContext::ddiag_iterator {
    126 public:
    127   ddiag_iterator() = default;
    128   explicit ddiag_iterator(DependentDiagnostic *Ptr) : Ptr(Ptr) {}
    129 
    130   using value_type = DependentDiagnostic *;
    131   using reference = DependentDiagnostic *;
    132   using pointer = DependentDiagnostic *;
    133   using difference_type = int;
    134   using iterator_category = std::forward_iterator_tag;
    135 
    136   reference operator*() const { return Ptr; }
    137 
    138   ddiag_iterator &operator++() {
    139     assert(Ptr && "attempt to increment past end of diag list");
    140     Ptr = Ptr->NextDiagnostic;
    141     return *this;
    142   }
    143 
    144   ddiag_iterator operator++(int) {
    145     ddiag_iterator tmp = *this;
    146     ++*this;
    147     return tmp;
    148   }
    149 
    150   bool operator==(ddiag_iterator Other) const {
    151     return Ptr == Other.Ptr;
    152   }
    153 
    154   bool operator!=(ddiag_iterator Other) const {
    155     return Ptr != Other.Ptr;
    156   }
    157 
    158   ddiag_iterator &operator+=(difference_type N) {
    159     assert(N >= 0 && "cannot rewind a DeclContext::ddiag_iterator");
    160     while (N--)
    161       ++*this;
    162     return *this;
    163   }
    164 
    165   ddiag_iterator operator+(difference_type N) const {
    166     ddiag_iterator tmp = *this;
    167     tmp += N;
    168     return tmp;
    169   }
    170 
    171 private:
    172   DependentDiagnostic *Ptr = nullptr;
    173 };
    174 
    175 inline DeclContext::ddiag_range DeclContext::ddiags() const {
    176   assert(isDependentContext()
    177          && "cannot iterate dependent diagnostics of non-dependent context");
    178   const DependentStoredDeclsMap *Map
    179     = static_cast<DependentStoredDeclsMap*>(getPrimaryContext()->getLookupPtr());
    180 
    181   if (!Map)
    182     // Return an empty range using the always-end default constructor.
    183     return ddiag_range(ddiag_iterator(), ddiag_iterator());
    184 
    185   return ddiag_range(ddiag_iterator(Map->FirstDiagnostic), ddiag_iterator());
    186 }
    187 
    188 } // namespace clang
    189 
    190 #endif // LLVM_CLANG_AST_DEPENDENTDIAGNOSTIC_H
    191