mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
LLVM has removed llvm::Optional, move over to std::optional. Also clang-format to fix up all the renamed #includes.
158 lines
6.1 KiB
C++
158 lines
6.1 KiB
C++
//===--- AccessScope.h - Swift Access Scope ---------------------*- C++ -*-===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_ACCESSSCOPE_H
|
|
#define SWIFT_ACCESSSCOPE_H
|
|
|
|
#include "swift/AST/AttrKind.h"
|
|
#include "swift/AST/DeclContext.h"
|
|
#include "swift/Basic/Debug.h"
|
|
#include "llvm/ADT/PointerIntPair.h"
|
|
#include <optional>
|
|
|
|
namespace swift {
|
|
|
|
/// The wrapper around the outermost DeclContext from which
|
|
/// a particular declaration can be accessed.
|
|
class AccessScope {
|
|
/// To validate access of a decl, access scope check for both decl site
|
|
/// and use site needs to be done. The underlying mechanism uses a
|
|
/// <DeclContext*, bool> pair to determine the scope, as shown
|
|
/// in the table below.
|
|
///
|
|
/// <DeclContext*, bool> AccessScope AccessLevel
|
|
/// ----------------------------------------------------------------
|
|
/// <nullptr, false> Public public or open
|
|
/// <nullptr, true> Public public `@_spi`
|
|
/// <PackageUnit*, _> Package package
|
|
/// <ModuleDecl*, _> Module internal
|
|
/// <FileUnit*, false> FileScope fileprivate
|
|
/// <FileUnit*, true> Private private
|
|
///
|
|
/// For example, if a decl with `public` access level is referenced outside of
|
|
/// its defining module, it will be maped to the <nullptr, false> pair during
|
|
/// the access scope check. This pair is determined based on the decl's access
|
|
/// level in \c getAccessScopeForFormalAccess and passed to
|
|
/// \c checkAccessUsingAccessScope which compares access scope of the
|
|
/// use site and decl site.
|
|
///
|
|
/// \see AccessScope::getAccessScopeForFormalAccess
|
|
/// \see AccessScope::checkAccessUsingAccessScope
|
|
/// \see DeclContext::ASTHierarchy
|
|
llvm::PointerIntPair<const DeclContext *, 1, bool> Value;
|
|
|
|
public:
|
|
AccessScope(const DeclContext *DC, bool isPrivate = false);
|
|
|
|
static AccessScope getPublic() { return AccessScope(nullptr, false); }
|
|
|
|
/// Check if private access is allowed. This is a lexical scope check in Swift
|
|
/// 3 mode. In Swift 4 mode, declarations and extensions of the same type will
|
|
/// also allow access.
|
|
static bool allowsPrivateAccess(const DeclContext *useDC, const DeclContext *sourceDC);
|
|
|
|
/// Returns nullptr if access scope is public.
|
|
const DeclContext *getDeclContext() const { return Value.getPointer(); }
|
|
|
|
bool operator==(AccessScope RHS) const { return Value == RHS.Value; }
|
|
bool operator!=(AccessScope RHS) const { return !(*this == RHS); }
|
|
bool hasEqualDeclContextWith(AccessScope RHS) const {
|
|
return getDeclContext() == RHS.getDeclContext();
|
|
}
|
|
|
|
bool isPublic() const { return !Value.getPointer(); }
|
|
bool isPrivate() const { return Value.getPointer() && Value.getInt(); }
|
|
bool isFileScope() const;
|
|
bool isInternal() const;
|
|
bool isPackage() const;
|
|
bool isPublicOrPackage() const { return isPublic() || isPackage(); }
|
|
|
|
/// Checks if the DeclContext of this (use site) access scope is more
|
|
/// restrictive than that of the argument (decl site) based on the DeclContext
|
|
/// hierarchy: (most to least restrictive)
|
|
/// decl/expr (e.g. ClassDecl) -> FileUnit -> ModuleDecl -> PackageUnit -> nullptr
|
|
///
|
|
/// A few things to note:
|
|
/// 1. If both have the same DeclContext, returns false as one is _not_ a
|
|
/// child of the other.
|
|
/// 2. This function does _not_ check the restrictiveness of the _access
|
|
/// level_ between two decls.
|
|
/// 3. The DeclContext of this (use site) may not be null even if the use site
|
|
/// has a `public` access level.
|
|
///
|
|
/// Here's an example while typechecking a file with the following code.
|
|
///
|
|
/// ```
|
|
/// import OtherModule
|
|
///
|
|
/// // `Foo` is a `public` struct defined in `OtherModule`
|
|
/// public func myFunc(_ arg: OtherModule.Foo) {}
|
|
/// ```
|
|
///
|
|
/// The use site of `Foo`is a function `myFunc`, and its DeclContext is
|
|
/// non-null (FileUnit) even though the function decl itself has a `public`
|
|
/// access level. When `isChildOf` is called, the argument passed in is a pair
|
|
/// <nullptr, false> created in \c getAccessScopeForFormalAccess based on the
|
|
/// access level of the decl `Foo`. Since FileUnit is a child of nullptr in
|
|
/// the DeclContext hierarchy (described above), it returns true.
|
|
///
|
|
/// \see AccessScope::getAccessScopeForFormalAccess
|
|
/// \see AccessScope::checkAccessUsingAccessScope
|
|
/// \see DeclContext::ASTHierarchy
|
|
bool isChildOf(AccessScope AS) const {
|
|
if (isInContext()) {
|
|
if (AS.isInContext())
|
|
return allowsPrivateAccess(getDeclContext(), AS.getDeclContext());
|
|
else
|
|
return AS.isPublic();
|
|
} else { // It's public, so can't be a child of public or less argument scope
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool isInContext() const { return getDeclContext() != nullptr; }
|
|
|
|
/// Returns the associated access level for diagnostic purposes.
|
|
AccessLevel accessLevelForDiagnostics() const;
|
|
|
|
/// Returns the minimum access level required to access
|
|
/// associated DeclContext for diagnostic purposes.
|
|
AccessLevel requiredAccessForDiagnostics() const {
|
|
return isFileScope()
|
|
? AccessLevel::FilePrivate
|
|
: accessLevelForDiagnostics();
|
|
}
|
|
|
|
/// Returns the narrowest access scope if this and the specified access scope
|
|
/// have common intersection, or None if scopes don't intersect.
|
|
const std::optional<AccessScope>
|
|
intersectWith(AccessScope accessScope) const {
|
|
if (hasEqualDeclContextWith(accessScope)) {
|
|
if (isPrivate())
|
|
return *this;
|
|
return accessScope;
|
|
}
|
|
if (isChildOf(accessScope))
|
|
return *this;
|
|
if (accessScope.isChildOf(*this))
|
|
return accessScope;
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
SWIFT_DEBUG_DUMP;
|
|
};
|
|
|
|
} // end namespace swift
|
|
|
|
#endif
|