Files
swift-mirror/include/swift/AST/AccessScope.h
Ben Barham ef8825bfe6 Migrate llvm::Optional to std::optional
LLVM has removed llvm::Optional, move over to std::optional. Also
clang-format to fix up all the renamed #includes.
2024-02-21 11:20:06 -08:00

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