2020
2121namespace swift {
2222
23- // / Used to provide the kind of scope limitation in AccessScope::Value
24- enum class AccessLimitKind : uint8_t { None = 0 , Private, Package };
25-
2623// / The wrapper around the outermost DeclContext from which
2724// / a particular declaration can be accessed.
2825class 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.
3830 // /
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;
4651
4752public:
48- AccessScope (const DeclContext *DC,
49- AccessLimitKind limitKind = AccessLimitKind::None);
53+ AccessScope (const DeclContext *DC, bool isPrivate = false );
5054
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 ); }
5756
5857 // / Check if private access is allowed. This is a lexical scope check in Swift
5958 // / 3 mode. In Swift 4 mode, declarations and extensions of the same type will
@@ -66,63 +65,60 @@ class AccessScope {
6665 bool operator ==(AccessScope RHS) const { return Value == RHS.Value ; }
6766 bool operator !=(AccessScope RHS) const { return !(*this == RHS); }
6867 bool hasEqualDeclContextWith (AccessScope RHS) const {
69- if (isPublic ())
70- return RHS.isPublic ();
71- if (isPackage ())
72- return RHS.isPackage ();
7368 return getDeclContext () == RHS.getDeclContext ();
7469 }
7570
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 (); }
8273 bool isFileScope () const ;
8374 bool isInternal () const ;
84- bool isPackage () const {
85- return !Value.getPointer () && Value.getInt () == AccessLimitKind::Package;
86- }
75+ bool isPackage () const ;
8776
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
88+ // / has 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
100+ // / non-null (FileUnit) even though the function decl itself has a `public`
101+ // / access level. When `isChildOf` is called, the argument passed in is a pair
102+ // / <nullptr, false> created in \c getAccessScopeForFormalAccess based on the
103+ // / access level of the decl `Foo`. Since FileUnit is a child of nullptr in
104+ // / the DeclContext hierarchy (described above), it returns true.
105+ // /
106+ // / \see AccessScope::getAccessScopeForFormalAccess
107+ // / \see AccessScope::checkAccessUsingAccessScope
108+ // / \see DeclContext::ASTHierarchy
92109 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 ()) {
94113 if (AS.isInContext ())
95114 return allowsPrivateAccess (getDeclContext (), AS.getDeclContext ());
96115 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 ;
98119 }
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 ;
104120 }
105121
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.
126122 bool isInContext () const { return getDeclContext () != nullptr ; }
127123
128124 // / Returns the associated access level for diagnostic purposes.
0 commit comments