-
Notifications
You must be signed in to change notification settings - Fork 10.5k
/
Copy pathAccessRequests.cpp
336 lines (292 loc) · 12.3 KB
/
AccessRequests.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
//===--- AccessRequests.cpp - AccessLevel and AccessScope Requests --------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift/Subsystems.h"
#include "swift/AST/AccessRequests.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticsCommon.h"
#include "swift/AST/Module.h"
#include "swift/AST/NameLookupRequests.h"
#include "swift/AST/SourceFile.h"
#include "swift/AST/Types.h"
#include "llvm/Support/MathExtras.h"
using namespace swift;
namespace swift {
// Implement the access-control type zone.
#define SWIFT_TYPEID_ZONE AccessControl
#define SWIFT_TYPEID_HEADER "swift/AST/AccessTypeIDZone.def"
#include "swift/Basic/ImplementTypeIDZone.h"
#undef SWIFT_TYPEID_ZONE
#undef SWIFT_TYPEID_HEADER
}
//----------------------------------------------------------------------------//
// AccessLevel computation
//----------------------------------------------------------------------------//
AccessLevel
AccessLevelRequest::evaluate(Evaluator &evaluator, ValueDecl *D) const {
assert(!D->hasAccess());
// Check if the decl has an explicit access control attribute.
if (auto *AA = D->getAttrs().getAttribute<AccessControlAttr>())
return AA->getAccess();
// Special case for accessors, which inherit the access of their storage.
// decl. A setter attribute can also override this.
if (auto accessor = dyn_cast<AccessorDecl>(D)) {
AbstractStorageDecl *storage = accessor->getStorage();
switch (accessor->getAccessorKind()) {
case AccessorKind::Get:
case AccessorKind::Address:
case AccessorKind::Read:
return storage->getFormalAccess();
case AccessorKind::Set:
case AccessorKind::MutableAddress:
case AccessorKind::Modify:
return storage->getSetterFormalAccess();
case AccessorKind::WillSet:
case AccessorKind::DidSet:
// These are only needed to synthesize the setter.
return AccessLevel::Private;
}
}
DeclContext *DC = D->getDeclContext();
// Special case for generic parameters; we just give them a dummy
// access level.
if (isa<GenericTypeParamDecl>(D)) {
return AccessLevel::Internal;
}
// Special case for associated types: inherit access from protocol.
if (auto assocType = dyn_cast<AssociatedTypeDecl>(D)) {
auto prot = assocType->getProtocol();
return std::max(prot->getFormalAccess(), AccessLevel::Internal);
}
// Special case for dtors and enum elements: inherit from container
if (D->getKind() == DeclKind::Destructor ||
D->getKind() == DeclKind::EnumElement) {
if (D->hasInterfaceType() && D->isInvalid()) {
return AccessLevel::Private;
} else {
auto container = cast<NominalTypeDecl>(D->getDeclContext());
return std::max(container->getFormalAccess(), AccessLevel::Internal);
}
}
switch (DC->getContextKind()) {
case DeclContextKind::TopLevelCodeDecl:
// Variables declared in a top-level 'guard' statement can be accessed in
// later top-level code.
return AccessLevel::FilePrivate;
case DeclContextKind::AbstractClosureExpr:
if (isa<ParamDecl>(D)) {
// Closure parameters may need to be accessible to the enclosing
// context, for single-expression closures.
return AccessLevel::FilePrivate;
} else {
return AccessLevel::Private;
}
case DeclContextKind::SerializedLocal:
case DeclContextKind::Initializer:
case DeclContextKind::AbstractFunctionDecl:
case DeclContextKind::SubscriptDecl:
case DeclContextKind::EnumElementDecl:
return AccessLevel::Private;
case DeclContextKind::Module:
case DeclContextKind::FileUnit:
return AccessLevel::Internal;
case DeclContextKind::GenericTypeDecl: {
auto generic = cast<GenericTypeDecl>(DC);
AccessLevel access = AccessLevel::Internal;
if (isa<ProtocolDecl>(generic))
access = std::max(AccessLevel::FilePrivate, generic->getFormalAccess());
return access;
}
case DeclContextKind::ExtensionDecl:
return cast<ExtensionDecl>(DC)->getDefaultAccessLevel();
}
llvm_unreachable("unhandled kind");
}
Optional<AccessLevel> AccessLevelRequest::getCachedResult() const {
auto valueDecl = std::get<0>(getStorage());
if (valueDecl->hasAccess())
return valueDecl->TypeAndAccess.getInt().getValue();
return None;
}
void AccessLevelRequest::cacheResult(AccessLevel value) const {
auto valueDecl = std::get<0>(getStorage());
valueDecl->setAccess(value);
}
//----------------------------------------------------------------------------//
// SetterAccessLevel computation
//----------------------------------------------------------------------------//
//
// An AbstractStorageDecl has both its own formal access and also a special
// "setter" formal access like "private(set)" that might override (and lower)
// the normal one, when evaluating the accessibility of mutating accessors.
//
// As this value can be computed, stored, synthesized and set independently from
// the cycle of computation associated with formal accesses, we give it its own
// request.
// In a .swiftinterface file, a stored property with an explicit @_hasStorage
// attribute but no setter is assumed to have originally been a private(set).
static bool isStoredWithPrivateSetter(VarDecl *VD) {
auto *HSA = VD->getAttrs().getAttribute<HasStorageAttr>();
if (!HSA || HSA->isImplicit())
return false;
auto *DC = VD->getDeclContext();
auto *SF = DC->getParentSourceFile();
if (!SF || SF->Kind != SourceFileKind::Interface)
return false;
if (VD->isLet() ||
VD->getParsedAccessor(AccessorKind::Set))
return false;
return true;
}
AccessLevel
SetterAccessLevelRequest::evaluate(Evaluator &evaluator,
AbstractStorageDecl *ASD) const {
assert(!ASD->Accessors.getInt().hasValue());
if (auto *SAA = ASD->getAttrs().getAttribute<SetterAccessAttr>())
return SAA->getAccess();
if (auto *VD = dyn_cast<VarDecl>(ASD))
if (isStoredWithPrivateSetter(VD))
return AccessLevel::Private;
return ASD->getFormalAccess();
}
Optional<AccessLevel> SetterAccessLevelRequest::getCachedResult() const {
auto abstractStorageDecl = std::get<0>(getStorage());
if (abstractStorageDecl->Accessors.getInt().hasValue())
return abstractStorageDecl->Accessors.getInt().getValue();
return None;
}
void SetterAccessLevelRequest::cacheResult(AccessLevel value) const {
auto abstractStorageDecl = std::get<0>(getStorage());
// NB: don't call setSetterAccess here because it drives values through to the
// associated accessors' formalAccess, which we might also be in the middle of
// doing a request for. Reserve setSetterAccess for deserialization &
// clangImporter use.
assert(!abstractStorageDecl->Accessors.getInt().hasValue());
abstractStorageDecl->Accessors.setInt(value);
}
//----------------------------------------------------------------------------//
// DefaultAccessLevel computation
//----------------------------------------------------------------------------//
std::pair<AccessLevel, AccessLevel>
DefaultAndMaxAccessLevelRequest::evaluate(Evaluator &evaluator,
ExtensionDecl *ED) const {
auto &Ctx = ED->getASTContext();
assert(!ED->hasDefaultAccessLevel());
AccessLevel maxAccess = AccessLevel::Public;
if (ED->getGenericParams()) {
// Only check the trailing 'where' requirements. Other requirements come
// from the extended type and have already been checked.
DirectlyReferencedTypeDecls typeDecls =
evaluateOrDefault(Ctx.evaluator, TypeDeclsFromWhereClauseRequest{ED}, {});
Optional<AccessScope> maxScope = AccessScope::getPublic();
// Try to scope the extension's access to the least public type mentioned
// in its where clause.
for (auto *typeDecl : typeDecls) {
if (isa<TypeAliasDecl>(typeDecl) || isa<NominalTypeDecl>(typeDecl)) {
auto scope = typeDecl->getFormalAccessScope(ED->getDeclContext());
maxScope = maxScope->intersectWith(scope);
}
}
// Now include the scope of the extended nominal type.
if (NominalTypeDecl *nominal = ED->getExtendedNominal()) {
auto scope = nominal->getFormalAccessScope(ED->getDeclContext());
maxScope = maxScope->intersectWith(scope);
}
if (!maxScope.hasValue()) {
// This is an error case and will be diagnosed elsewhere.
maxAccess = AccessLevel::Public;
} else if (maxScope->isPublic()) {
maxAccess = AccessLevel::Public;
} else if (isa<ModuleDecl>(maxScope->getDeclContext())) {
maxAccess = AccessLevel::Internal;
} else {
// Because extensions are always at top-level, they should never
// reference declarations not at the top level. (And any such references
// should be diagnosed elsewhere.) This code should not crash if that
// occurs, though.
maxAccess = AccessLevel::FilePrivate;
}
}
AccessLevel defaultAccess;
if (auto *AA = ED->getAttrs().getAttribute<AccessControlAttr>())
defaultAccess = std::max(AA->getAccess(), AccessLevel::FilePrivate);
else
defaultAccess = AccessLevel::Internal;
// Don't set the max or default access level to 'open'. This should
// be diagnosed as invalid anyway.
defaultAccess = std::min(defaultAccess, AccessLevel::Public);
maxAccess = std::min(maxAccess, AccessLevel::Public);
// Normally putting a public member in an internal extension is harmless,
// because that member can never be used elsewhere. But if some of the types
// in the signature are public, it could actually end up getting picked in
// overload resolution. Therefore, we only enforce the maximum access if the
// extension has a 'where' clause.
if (ED->getTrailingWhereClause())
defaultAccess = std::min(defaultAccess, maxAccess);
else
maxAccess = AccessLevel::Public;
return std::make_pair(defaultAccess, maxAccess);
}
// Default and Max access levels are stored combined as a 3-bit bitset. The Bits
// are numbered using the 3 middle values of the AccessLevel enumeration, and
// the combined value is just the bitwise-OR of the bits for Default and Max.
//
// For example, if Max=Internal and Default=FilePrivate, we will see:
//
// 0 1 1
// | | |
// | | [FilePrivate]
// | |
// | [Internal]
// |
// [Public]
//
// This is unambiguous to decode because of the following facts:
//
// - At least one of the bits is set (all-zero means "not yet set").
// - At most two of the bits are set.
// - Max >= Default by definition.
//
// So we decode Max as the last (high) bit that is set, and Default as the first
// (low). And add one to each, to map them back into AccessLevels.
Optional<std::pair<AccessLevel,AccessLevel>>
DefaultAndMaxAccessLevelRequest::getCachedResult() const {
auto extensionDecl = std::get<0>(getStorage());
if (extensionDecl->hasDefaultAccessLevel()) {
uint8_t Bits = extensionDecl->getDefaultAndMaxAccessLevelBits();
assert(Bits != 0x7 && "more than two bits set for Default and Max");
AccessLevel Max = static_cast<AccessLevel>(llvm::findLastSet(Bits) + 1);
AccessLevel Default = static_cast<AccessLevel>(llvm::findFirstSet(Bits) + 1);
assert(Max >= Default);
return std::make_pair(Default, Max);
}
return None;
}
void
DefaultAndMaxAccessLevelRequest::cacheResult(
std::pair<AccessLevel, AccessLevel> value) const {
auto extensionDecl = std::get<0>(getStorage());
extensionDecl->setDefaultAndMaxAccessLevelBits(value.first, value.second);
assert(getCachedResult().getValue().first == value.first);
assert(getCachedResult().getValue().second == value.second);
}
// Define request evaluation functions for each of the access requests.
static AbstractRequestFunction *accessRequestFunctions[] = {
#define SWIFT_REQUEST(Zone, Name, Sig, Caching, LocOptions) \
reinterpret_cast<AbstractRequestFunction *>(&Name::evaluateRequest),
#include "swift/AST/AccessTypeIDZone.def"
#undef SWIFT_REQUEST
};
void swift::registerAccessRequestFunctions(Evaluator &evaluator) {
evaluator.registerRequestFunctions(Zone::AccessControl,
accessRequestFunctions);
}