20
20
21
21
namespace swift {
22
22
23
- // / Used to provide the kind of scope limitation in AccessScope::Value
24
- enum class AccessLimitKind : uint8_t { None = 0 , Private, Package };
25
-
26
23
// / The wrapper around the outermost DeclContext from which
27
24
// / a particular declaration can be accessed.
28
25
class AccessScope {
29
- // / The declaration context along with an enum indicating the level of
30
- // / scope limitation.
31
- // / If the declaration context is set, and the limit kind is Private, the
32
- // / access level is considered 'private'. Whether it's 'internal' or
33
- // / 'fileprivate' is determined by what the declaration context casts to. If
34
- // / the declaration context is null, and the limit kind is None, the access
35
- // / level is considered 'public'. If the limit kind is Private, the access
36
- // / level is considered SPI. If it's Package, the access level is considered
37
- // / 'package'. Below is a table showing the combinations.
26
+ // / To validate access of a decl, access scope check for both decl site
27
+ // / and use site needs to be done. The underlying mechanism uses a
28
+ // / <DeclContext*, bool> pair to determine the scope, as shown
29
+ // / in the table below.
38
30
// /
39
- // / AccessLimitKind DC == nullptr DC != nullptr
40
- // / ---------------------------------------------------------------------------
41
- // / None public fileprivate or internal (check DC to tell which)
42
- // / Private `@_spi` public private
43
- // / Package package (unused)
44
-
45
- llvm::PointerIntPair<const DeclContext *, 2 , AccessLimitKind> Value;
31
+ // / <DeclContext*, bool> AccessScope AccessLevel
32
+ // / --------------------------------------------
33
+ // / <nullptr, false> Public public or open
34
+ // / <nullptr, true> Public public `@_spi`
35
+ // / <PackageUnit*, _> Package package
36
+ // / <ModuleDecl*, _> Module internal
37
+ // / <FileUnit*, false> FileScope fileprivate
38
+ // / <FileUnit*, true> Private private
39
+ // /
40
+ // / For example, if a decl with `public` access level is referenced outside of
41
+ // / its defining module, it will be maped to the <nullptr, false> pair during
42
+ // / the access scope check. This pair is determined based on the decl's access
43
+ // / level in \c getAccessScopeForFormalAccess and passed to
44
+ // / \c checkAccessUsingAccessScope which compares access scope of the
45
+ // / use site and decl site.
46
+ // /
47
+ // / \see AccessScope::getAccessScopeForFormalAccess
48
+ // / \see AccessScope::checkAccessUsingAccessScope
49
+ // / \see DeclContext::ASTHierarchy
50
+ llvm::PointerIntPair<const DeclContext *, 1 , bool > Value;
46
51
47
52
public:
48
- AccessScope (const DeclContext *DC,
49
- AccessLimitKind limitKind = AccessLimitKind::None);
53
+ AccessScope (const DeclContext *DC, bool isPrivate = false );
50
54
51
- static AccessScope getPublic () {
52
- return AccessScope (nullptr , AccessLimitKind::None);
53
- }
54
- static AccessScope getPackage () {
55
- return AccessScope (nullptr , AccessLimitKind::Package);
56
- }
55
+ static AccessScope getPublic () { return AccessScope (nullptr , false ); }
57
56
58
57
// / Check if private access is allowed. This is a lexical scope check in Swift
59
58
// / 3 mode. In Swift 4 mode, declarations and extensions of the same type will
@@ -66,63 +65,60 @@ class AccessScope {
66
65
bool operator ==(AccessScope RHS) const { return Value == RHS.Value ; }
67
66
bool operator !=(AccessScope RHS) const { return !(*this == RHS); }
68
67
bool hasEqualDeclContextWith (AccessScope RHS) const {
69
- if (isPublic ())
70
- return RHS.isPublic ();
71
- if (isPackage ())
72
- return RHS.isPackage ();
73
68
return getDeclContext () == RHS.getDeclContext ();
74
69
}
75
70
76
- bool isPublic () const {
77
- return !Value.getPointer () && Value.getInt () == AccessLimitKind::None;
78
- }
79
- bool isPrivate () const {
80
- return Value.getPointer () && Value.getInt () == AccessLimitKind::Private;
81
- }
71
+ bool isPublic () const { return !Value.getPointer (); }
72
+ bool isPrivate () const { return Value.getPointer () && Value.getInt (); }
82
73
bool isFileScope () const ;
83
74
bool isInternal () const ;
84
- bool isPackage () const {
85
- return !Value.getPointer () && Value.getInt () == AccessLimitKind::Package;
86
- }
75
+ bool isPackage () const ;
87
76
88
- // / Returns true if the context of this (use site) is more restrictive than
89
- // / the argument context (decl site). This function does _not_ check the
90
- // / restrictiveness of the access level between this and the argument. \see
91
- // / AccessScope::isInContext
77
+ // / Checks if the DeclContext of this (use site) access scope is more
78
+ // / restrictive than that of the argument (decl site) based on the DeclContext
79
+ // / hierarchy: (most to least restrictive)
80
+ // / decl/expr (e.g. ClassDecl) -> FileUnit -> ModuleDecl -> PackageUnit -> nullptr
81
+ // /
82
+ // / A few things to note:
83
+ // / 1. If both have the same DeclContext, returns false as one is _not_ a
84
+ // / child of the other.
85
+ // / 2. This function does _not_ check the restrictiveness of the _access
86
+ // / level_ between two decls.
87
+ // / 3. The DeclContext of this (use site) may not be null even if the use site has
88
+ // / a `public` access level.
89
+ // /
90
+ // / Here's an example while typechecking a file with the following code.
91
+ // /
92
+ // / ```
93
+ // / import OtherModule
94
+ // /
95
+ // / // `Foo` is a `public` struct defined in `OtherModule`
96
+ // / public func myFunc(_ arg: OtherModule.Foo) {}
97
+ // / ```
98
+ // /
99
+ // / The use site of `Foo`is a function `myFunc`, and its DeclContext is non-null
100
+ // / (FileUnit) even though the function decl itself has a `public` access level.
101
+ // / When `isChildOf` is called, the argument passed in is a pair <nullptr,
102
+ // / false> created in \c getAccessScopeForFormalAccess based on the access
103
+ // / level of the decl `Foo`. Since FileUnit is a child of nullptr in the DeclContext
104
+ // / hierarchy (described above), it returns true.
105
+ // /
106
+ // / \see AccessScope::getAccessScopeForFormalAccess
107
+ // / \see AccessScope::checkAccessUsingAccessScope
108
+ // / \see DeclContext::ASTHierarchy
92
109
bool isChildOf (AccessScope AS) const {
93
- if (isInContext ()) {
110
+ if (isPackage ()) { // This needs to be checked first before isInContext
111
+ return AS.isPublic ();
112
+ } else if (isInContext ()) {
94
113
if (AS.isInContext ())
95
114
return allowsPrivateAccess (getDeclContext (), AS.getDeclContext ());
96
115
else
97
- return AS.isPackage () || AS.isPublic ();
116
+ return AS.isPublic ();
117
+ } else {// It's public, so can't be a child of the argument scope
118
+ return false ;
98
119
}
99
- if (isPackage ())
100
- return AS.isPublic ();
101
- // If this is public, it can't be less than access level of AS
102
- // so return false
103
- return false ;
104
120
}
105
121
106
- // / Result depends on whether it's called at a use site or a decl site:
107
- // /
108
- // / For example,
109
- // /
110
- // / ```
111
- // / public func foo(_ arg: bar) {} // `bar` is a `package` decl in another
112
- // / module
113
- // / ```
114
- // /
115
- // / The meaning of \c isInContext changes whether it's at the use site or the
116
- // / decl site.
117
- // /
118
- // / The use site of \c bar, i.e. \c foo, is "in context" (decl context is
119
- // / non-null), regardless of the access level of \c foo (\c public in this
120
- // / case).
121
- // /
122
- // / The decl site of \c bar is only "in context" if the access level of the
123
- // / decl is \c internal or more restrictive. The context at the decl site is\c
124
- // / FileUnit if the decl is \c fileprivate or \c private; \c ModuleDecl if \c
125
- // / internal, and null if \c package or \c public.
126
122
bool isInContext () const { return getDeclContext () != nullptr ; }
127
123
128
124
// / Returns the associated access level for diagnostic purposes.
0 commit comments