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