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