1 | //===- DeclFriend.h - Classes for C++ friend declarations -------*- 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 the section of the AST representing C++ friend |
10 | // declarations. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_CLANG_AST_DECLFRIEND_H |
15 | #define LLVM_CLANG_AST_DECLFRIEND_H |
16 | |
17 | #include "clang/AST/Decl.h" |
18 | #include "clang/AST/DeclBase.h" |
19 | #include "clang/AST/DeclCXX.h" |
20 | #include "clang/AST/DeclTemplate.h" |
21 | #include "clang/AST/ExternalASTSource.h" |
22 | #include "clang/AST/TypeLoc.h" |
23 | #include "clang/Basic/LLVM.h" |
24 | #include "clang/Basic/SourceLocation.h" |
25 | #include "llvm/ADT/ArrayRef.h" |
26 | #include "llvm/ADT/PointerUnion.h" |
27 | #include "llvm/Support/Casting.h" |
28 | #include "llvm/Support/Compiler.h" |
29 | #include "llvm/Support/TrailingObjects.h" |
30 | #include <cassert> |
31 | #include <iterator> |
32 | |
33 | namespace clang { |
34 | |
35 | class ASTContext; |
36 | |
37 | /// FriendDecl - Represents the declaration of a friend entity, |
38 | /// which can be a function, a type, or a templated function or type. |
39 | /// For example: |
40 | /// |
41 | /// @code |
42 | /// template <typename T> class A { |
43 | /// friend int foo(T); |
44 | /// friend class B; |
45 | /// friend T; // only in C++0x |
46 | /// template <typename U> friend class C; |
47 | /// template <typename U> friend A& operator+=(A&, const U&) { ... } |
48 | /// }; |
49 | /// @endcode |
50 | /// |
51 | /// The semantic context of a friend decl is its declaring class. |
52 | class FriendDecl final |
53 | : public Decl, |
54 | private llvm::TrailingObjects<FriendDecl, TemplateParameterList *> { |
55 | virtual void anchor(); |
56 | |
57 | public: |
58 | using FriendUnion = llvm::PointerUnion<NamedDecl *, TypeSourceInfo *>; |
59 | |
60 | private: |
61 | friend class CXXRecordDecl; |
62 | friend class CXXRecordDecl::friend_iterator; |
63 | |
64 | // The declaration that's a friend of this class. |
65 | FriendUnion Friend; |
66 | |
67 | // A pointer to the next friend in the sequence. |
68 | LazyDeclPtr NextFriend; |
69 | |
70 | // Location of the 'friend' specifier. |
71 | SourceLocation FriendLoc; |
72 | |
73 | /// True if this 'friend' declaration is unsupported. Eventually we |
74 | /// will support every possible friend declaration, but for now we |
75 | /// silently ignore some and set this flag to authorize all access. |
76 | LLVM_PREFERRED_TYPE(bool) |
77 | unsigned UnsupportedFriend : 1; |
78 | |
79 | // The number of "outer" template parameter lists in non-templatic |
80 | // (currently unsupported) friend type declarations, such as |
81 | // template <class T> friend class A<T>::B; |
82 | unsigned NumTPLists : 31; |
83 | |
84 | FriendDecl(DeclContext *DC, SourceLocation L, FriendUnion Friend, |
85 | SourceLocation FriendL, |
86 | ArrayRef<TemplateParameterList *> FriendTypeTPLists) |
87 | : Decl(Decl::Friend, DC, L), Friend(Friend), FriendLoc(FriendL), |
88 | UnsupportedFriend(false), NumTPLists(FriendTypeTPLists.size()) { |
89 | for (unsigned i = 0; i < NumTPLists; ++i) |
90 | getTrailingObjects<TemplateParameterList *>()[i] = FriendTypeTPLists[i]; |
91 | } |
92 | |
93 | FriendDecl(EmptyShell Empty, unsigned NumFriendTypeTPLists) |
94 | : Decl(Decl::Friend, Empty), UnsupportedFriend(false), |
95 | NumTPLists(NumFriendTypeTPLists) {} |
96 | |
97 | FriendDecl *getNextFriend() { |
98 | if (!NextFriend.isOffset()) |
99 | return cast_or_null<FriendDecl>(Val: NextFriend.get(Source: nullptr)); |
100 | return getNextFriendSlowCase(); |
101 | } |
102 | |
103 | FriendDecl *getNextFriendSlowCase(); |
104 | |
105 | public: |
106 | friend class ASTDeclReader; |
107 | friend class ASTDeclWriter; |
108 | friend class ASTNodeImporter; |
109 | friend TrailingObjects; |
110 | |
111 | static FriendDecl * |
112 | Create(ASTContext &C, DeclContext *DC, SourceLocation L, FriendUnion Friend_, |
113 | SourceLocation FriendL, |
114 | ArrayRef<TemplateParameterList *> FriendTypeTPLists = std::nullopt); |
115 | static FriendDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, |
116 | unsigned FriendTypeNumTPLists); |
117 | |
118 | /// If this friend declaration names an (untemplated but possibly |
119 | /// dependent) type, return the type; otherwise return null. This |
120 | /// is used for elaborated-type-specifiers and, in C++0x, for |
121 | /// arbitrary friend type declarations. |
122 | TypeSourceInfo *getFriendType() const { |
123 | return Friend.dyn_cast<TypeSourceInfo*>(); |
124 | } |
125 | |
126 | unsigned getFriendTypeNumTemplateParameterLists() const { |
127 | return NumTPLists; |
128 | } |
129 | |
130 | TemplateParameterList *getFriendTypeTemplateParameterList(unsigned N) const { |
131 | assert(N < NumTPLists); |
132 | return getTrailingObjects<TemplateParameterList *>()[N]; |
133 | } |
134 | |
135 | /// If this friend declaration doesn't name a type, return the inner |
136 | /// declaration. |
137 | NamedDecl *getFriendDecl() const { |
138 | return Friend.dyn_cast<NamedDecl *>(); |
139 | } |
140 | |
141 | /// Retrieves the location of the 'friend' keyword. |
142 | SourceLocation getFriendLoc() const { |
143 | return FriendLoc; |
144 | } |
145 | |
146 | /// Retrieves the source range for the friend declaration. |
147 | SourceRange getSourceRange() const override LLVM_READONLY { |
148 | if (NamedDecl *ND = getFriendDecl()) { |
149 | if (const auto *FD = dyn_cast<FunctionDecl>(Val: ND)) |
150 | return FD->getSourceRange(); |
151 | if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(Val: ND)) |
152 | return FTD->getSourceRange(); |
153 | if (const auto *CTD = dyn_cast<ClassTemplateDecl>(Val: ND)) |
154 | return CTD->getSourceRange(); |
155 | if (const auto *DD = dyn_cast<DeclaratorDecl>(Val: ND)) { |
156 | if (DD->getOuterLocStart() != DD->getInnerLocStart()) |
157 | return DD->getSourceRange(); |
158 | } |
159 | return SourceRange(getFriendLoc(), ND->getEndLoc()); |
160 | } |
161 | else if (TypeSourceInfo *TInfo = getFriendType()) { |
162 | SourceLocation StartL = |
163 | (NumTPLists == 0) ? getFriendLoc() |
164 | : getTrailingObjects<TemplateParameterList *>()[0] |
165 | ->getTemplateLoc(); |
166 | return SourceRange(StartL, TInfo->getTypeLoc().getEndLoc()); |
167 | } |
168 | else |
169 | return SourceRange(getFriendLoc(), getLocation()); |
170 | } |
171 | |
172 | /// Determines if this friend kind is unsupported. |
173 | bool isUnsupportedFriend() const { |
174 | return UnsupportedFriend; |
175 | } |
176 | void setUnsupportedFriend(bool Unsupported) { |
177 | UnsupportedFriend = Unsupported; |
178 | } |
179 | |
180 | // Implement isa/cast/dyncast/etc. |
181 | static bool classof(const Decl *D) { return classofKind(K: D->getKind()); } |
182 | static bool classofKind(Kind K) { return K == Decl::Friend; } |
183 | }; |
184 | |
185 | /// An iterator over the friend declarations of a class. |
186 | class CXXRecordDecl::friend_iterator { |
187 | friend class CXXRecordDecl; |
188 | |
189 | FriendDecl *Ptr; |
190 | |
191 | explicit friend_iterator(FriendDecl *Ptr) : Ptr(Ptr) {} |
192 | |
193 | public: |
194 | friend_iterator() = default; |
195 | |
196 | using value_type = FriendDecl *; |
197 | using reference = FriendDecl *; |
198 | using pointer = FriendDecl *; |
199 | using difference_type = int; |
200 | using iterator_category = std::forward_iterator_tag; |
201 | |
202 | reference operator*() const { return Ptr; } |
203 | |
204 | friend_iterator &operator++() { |
205 | assert(Ptr && "attempt to increment past end of friend list" ); |
206 | Ptr = Ptr->getNextFriend(); |
207 | return *this; |
208 | } |
209 | |
210 | friend_iterator operator++(int) { |
211 | friend_iterator tmp = *this; |
212 | ++*this; |
213 | return tmp; |
214 | } |
215 | |
216 | bool operator==(const friend_iterator &Other) const { |
217 | return Ptr == Other.Ptr; |
218 | } |
219 | |
220 | bool operator!=(const friend_iterator &Other) const { |
221 | return Ptr != Other.Ptr; |
222 | } |
223 | |
224 | friend_iterator &operator+=(difference_type N) { |
225 | assert(N >= 0 && "cannot rewind a CXXRecordDecl::friend_iterator" ); |
226 | while (N--) |
227 | ++*this; |
228 | return *this; |
229 | } |
230 | |
231 | friend_iterator operator+(difference_type N) const { |
232 | friend_iterator tmp = *this; |
233 | tmp += N; |
234 | return tmp; |
235 | } |
236 | }; |
237 | |
238 | inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_begin() const { |
239 | return friend_iterator(getFirstFriend()); |
240 | } |
241 | |
242 | inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_end() const { |
243 | return friend_iterator(nullptr); |
244 | } |
245 | |
246 | inline CXXRecordDecl::friend_range CXXRecordDecl::friends() const { |
247 | return friend_range(friend_begin(), friend_end()); |
248 | } |
249 | |
250 | inline void CXXRecordDecl::pushFriendDecl(FriendDecl *FD) { |
251 | assert(!FD->NextFriend && "friend already has next friend?" ); |
252 | FD->NextFriend = data().FirstFriend; |
253 | data().FirstFriend = FD; |
254 | } |
255 | |
256 | } // namespace clang |
257 | |
258 | #endif // LLVM_CLANG_AST_DECLFRIEND_H |
259 | |