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 
Create(ASTContext & Context,DeclContext * Parent,AccessNonce _,SourceLocation Loc,bool IsMemberAccess,AccessSpecifier AS,NamedDecl * TargetDecl,CXXRecordDecl * NamingClass,QualType BaseObjectType,const PartialDiagnostic & PDiag)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 
getKind()60   unsigned getKind() const {
61     return Access;
62   }
63 
isAccessToMember()64   bool isAccessToMember() const {
65     assert(getKind() == Access);
66     return AccessData.IsMember;
67   }
68 
getAccess()69   AccessSpecifier getAccess() const {
70     assert(getKind() == Access);
71     return AccessSpecifier(AccessData.Access);
72   }
73 
getAccessLoc()74   SourceLocation getAccessLoc() const {
75     assert(getKind() == Access);
76     return AccessData.Loc;
77   }
78 
getAccessTarget()79   NamedDecl *getAccessTarget() const {
80     assert(getKind() == Access);
81     return AccessData.TargetDecl;
82   }
83 
getAccessNamingClass()84   NamedDecl *getAccessNamingClass() const {
85     assert(getKind() == Access);
86     return AccessData.NamingClass;
87   }
88 
getAccessBaseObjectType()89   QualType getAccessBaseObjectType() const {
90     assert(getKind() == Access);
91     return QualType::getFromOpaquePtr(AccessData.BaseObjectType);
92   }
93 
getDiagnostic()94   const PartialDiagnostic &getDiagnostic() const {
95     return Diag;
96   }
97 
98 private:
99   friend class DeclContext::ddiag_iterator;
100   friend class DependentStoredDeclsMap;
101 
DependentDiagnostic(const PartialDiagnostic & PDiag,DiagnosticStorage * Storage)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     LLVM_PREFERRED_TYPE(AccessSpecifier)
117     unsigned Access : 2;
118     LLVM_PREFERRED_TYPE(bool)
119     unsigned IsMember : 1;
120     NamedDecl *TargetDecl;
121     CXXRecordDecl *NamingClass;
122     void *BaseObjectType;
123   } AccessData;
124 };
125 
126 /// An iterator over the dependent diagnostics in a dependent context.
127 class DeclContext::ddiag_iterator {
128 public:
129   ddiag_iterator() = default;
ddiag_iterator(DependentDiagnostic * Ptr)130   explicit ddiag_iterator(DependentDiagnostic *Ptr) : Ptr(Ptr) {}
131 
132   using value_type = DependentDiagnostic *;
133   using reference = DependentDiagnostic *;
134   using pointer = DependentDiagnostic *;
135   using difference_type = int;
136   using iterator_category = std::forward_iterator_tag;
137 
138   reference operator*() const { return Ptr; }
139 
140   ddiag_iterator &operator++() {
141     assert(Ptr && "attempt to increment past end of diag list");
142     Ptr = Ptr->NextDiagnostic;
143     return *this;
144   }
145 
146   ddiag_iterator operator++(int) {
147     ddiag_iterator tmp = *this;
148     ++*this;
149     return tmp;
150   }
151 
152   bool operator==(ddiag_iterator Other) const {
153     return Ptr == Other.Ptr;
154   }
155 
156   bool operator!=(ddiag_iterator Other) const {
157     return Ptr != Other.Ptr;
158   }
159 
160   ddiag_iterator &operator+=(difference_type N) {
161     assert(N >= 0 && "cannot rewind a DeclContext::ddiag_iterator");
162     while (N--)
163       ++*this;
164     return *this;
165   }
166 
167   ddiag_iterator operator+(difference_type N) const {
168     ddiag_iterator tmp = *this;
169     tmp += N;
170     return tmp;
171   }
172 
173 private:
174   DependentDiagnostic *Ptr = nullptr;
175 };
176 
ddiags()177 inline DeclContext::ddiag_range DeclContext::ddiags() const {
178   assert(isDependentContext()
179          && "cannot iterate dependent diagnostics of non-dependent context");
180   const DependentStoredDeclsMap *Map
181     = static_cast<DependentStoredDeclsMap*>(getPrimaryContext()->getLookupPtr());
182 
183   if (!Map)
184     // Return an empty range using the always-end default constructor.
185     return ddiag_range(ddiag_iterator(), ddiag_iterator());
186 
187   return ddiag_range(ddiag_iterator(Map->FirstDiagnostic), ddiag_iterator());
188 }
189 
190 } // namespace clang
191 
192 #endif // LLVM_CLANG_AST_DEPENDENTDIAGNOSTIC_H
193