/src/llvm-project/clang/include/clang/AST/DeclFriend.h
Line | Count | Source (jump to first uncovered line) |
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 | 0 | UnsupportedFriend(false), NumTPLists(FriendTypeTPLists.size()) { |
89 | 0 | for (unsigned i = 0; i < NumTPLists; ++i) |
90 | 0 | getTrailingObjects<TemplateParameterList *>()[i] = FriendTypeTPLists[i]; |
91 | 0 | } |
92 | | |
93 | | FriendDecl(EmptyShell Empty, unsigned NumFriendTypeTPLists) |
94 | | : Decl(Decl::Friend, Empty), UnsupportedFriend(false), |
95 | 0 | NumTPLists(NumFriendTypeTPLists) {} |
96 | | |
97 | 0 | FriendDecl *getNextFriend() { |
98 | 0 | if (!NextFriend.isOffset()) |
99 | 0 | return cast_or_null<FriendDecl>(NextFriend.get(nullptr)); |
100 | 0 | return getNextFriendSlowCase(); |
101 | 0 | } |
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, unsigned 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 | 0 | TypeSourceInfo *getFriendType() const { |
123 | 0 | return Friend.dyn_cast<TypeSourceInfo*>(); |
124 | 0 | } |
125 | | |
126 | 0 | unsigned getFriendTypeNumTemplateParameterLists() const { |
127 | 0 | return NumTPLists; |
128 | 0 | } |
129 | | |
130 | 0 | TemplateParameterList *getFriendTypeTemplateParameterList(unsigned N) const { |
131 | 0 | assert(N < NumTPLists); |
132 | 0 | return getTrailingObjects<TemplateParameterList *>()[N]; |
133 | 0 | } |
134 | | |
135 | | /// If this friend declaration doesn't name a type, return the inner |
136 | | /// declaration. |
137 | 0 | NamedDecl *getFriendDecl() const { |
138 | 0 | return Friend.dyn_cast<NamedDecl *>(); |
139 | 0 | } |
140 | | |
141 | | /// Retrieves the location of the 'friend' keyword. |
142 | 0 | SourceLocation getFriendLoc() const { |
143 | 0 | return FriendLoc; |
144 | 0 | } |
145 | | |
146 | | /// Retrieves the source range for the friend declaration. |
147 | 0 | SourceRange getSourceRange() const override LLVM_READONLY { |
148 | 0 | if (NamedDecl *ND = getFriendDecl()) { |
149 | 0 | if (const auto *FD = dyn_cast<FunctionDecl>(ND)) |
150 | 0 | return FD->getSourceRange(); |
151 | 0 | if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(ND)) |
152 | 0 | return FTD->getSourceRange(); |
153 | 0 | if (const auto *CTD = dyn_cast<ClassTemplateDecl>(ND)) |
154 | 0 | return CTD->getSourceRange(); |
155 | 0 | if (const auto *DD = dyn_cast<DeclaratorDecl>(ND)) { |
156 | 0 | if (DD->getOuterLocStart() != DD->getInnerLocStart()) |
157 | 0 | return DD->getSourceRange(); |
158 | 0 | } |
159 | 0 | return SourceRange(getFriendLoc(), ND->getEndLoc()); |
160 | 0 | } |
161 | 0 | else if (TypeSourceInfo *TInfo = getFriendType()) { |
162 | 0 | SourceLocation StartL = |
163 | 0 | (NumTPLists == 0) ? getFriendLoc() |
164 | 0 | : getTrailingObjects<TemplateParameterList *>()[0] |
165 | 0 | ->getTemplateLoc(); |
166 | 0 | return SourceRange(StartL, TInfo->getTypeLoc().getEndLoc()); |
167 | 0 | } |
168 | 0 | else |
169 | 0 | return SourceRange(getFriendLoc(), getLocation()); |
170 | 0 | } |
171 | | |
172 | | /// Determines if this friend kind is unsupported. |
173 | 0 | bool isUnsupportedFriend() const { |
174 | 0 | return UnsupportedFriend; |
175 | 0 | } |
176 | 0 | void setUnsupportedFriend(bool Unsupported) { |
177 | 0 | UnsupportedFriend = Unsupported; |
178 | 0 | } |
179 | | |
180 | | // Implement isa/cast/dyncast/etc. |
181 | 0 | static bool classof(const Decl *D) { return classofKind(D->getKind()); } |
182 | 0 | 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 | 0 | 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 | 0 | reference operator*() const { return Ptr; } |
203 | | |
204 | 0 | friend_iterator &operator++() { |
205 | 0 | assert(Ptr && "attempt to increment past end of friend list"); |
206 | 0 | Ptr = Ptr->getNextFriend(); |
207 | 0 | return *this; |
208 | 0 | } |
209 | | |
210 | 0 | friend_iterator operator++(int) { |
211 | 0 | friend_iterator tmp = *this; |
212 | 0 | ++*this; |
213 | 0 | return tmp; |
214 | 0 | } |
215 | | |
216 | 0 | bool operator==(const friend_iterator &Other) const { |
217 | 0 | return Ptr == Other.Ptr; |
218 | 0 | } |
219 | | |
220 | 0 | bool operator!=(const friend_iterator &Other) const { |
221 | 0 | return Ptr != Other.Ptr; |
222 | 0 | } |
223 | | |
224 | 0 | friend_iterator &operator+=(difference_type N) { |
225 | 0 | assert(N >= 0 && "cannot rewind a CXXRecordDecl::friend_iterator"); |
226 | 0 | while (N--) |
227 | 0 | ++*this; |
228 | 0 | return *this; |
229 | 0 | } |
230 | | |
231 | 0 | friend_iterator operator+(difference_type N) const { |
232 | 0 | friend_iterator tmp = *this; |
233 | 0 | tmp += N; |
234 | 0 | return tmp; |
235 | 0 | } |
236 | | }; |
237 | | |
238 | 0 | inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_begin() const { |
239 | 0 | return friend_iterator(getFirstFriend()); |
240 | 0 | } |
241 | | |
242 | 0 | inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_end() const { |
243 | 0 | return friend_iterator(nullptr); |
244 | 0 | } |
245 | | |
246 | 0 | inline CXXRecordDecl::friend_range CXXRecordDecl::friends() const { |
247 | 0 | return friend_range(friend_begin(), friend_end()); |
248 | 0 | } |
249 | | |
250 | 0 | inline void CXXRecordDecl::pushFriendDecl(FriendDecl *FD) { |
251 | 0 | assert(!FD->NextFriend && "friend already has next friend?"); |
252 | 0 | FD->NextFriend = data().FirstFriend; |
253 | 0 | data().FirstFriend = FD; |
254 | 0 | } |
255 | | |
256 | | } // namespace clang |
257 | | |
258 | | #endif // LLVM_CLANG_AST_DECLFRIEND_H |