blob: f8860e540a47d810bb31226c4dcb57cc774a260a [file] [log] [blame]
//===--- DeclContext.cpp - DeclContext implementation ---------------------===//
//
// 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/AST/DeclContext.h"
#include "swift/AST/AccessScope.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/Expr.h"
#include "swift/AST/FileUnit.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/LazyResolver.h"
#include "swift/AST/Module.h"
#include "swift/AST/ParseRequests.h"
#include "swift/AST/SourceFile.h"
#include "swift/AST/Types.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/Statistic.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace swift;
#define DEBUG_TYPE "Name lookup"
STATISTIC(NumLazyIterableDeclContexts,
"# of serialized iterable declaration contexts");
STATISTIC(NumUnloadedLazyIterableDeclContexts,
"# of serialized iterable declaration contexts never loaded");
// Only allow allocation of DeclContext using the allocator in ASTContext.
void *DeclContext::operator new(size_t Bytes, ASTContext &C,
unsigned Alignment) {
return C.Allocate(Bytes, Alignment);
}
ASTContext &DeclContext::getASTContext() const {
return getParentModule()->getASTContext();
}
GenericTypeDecl *DeclContext::getSelfTypeDecl() const {
auto decl = const_cast<Decl*>(getAsDecl());
if (!decl) return nullptr;
auto ext = dyn_cast<ExtensionDecl>(decl);
if (!ext) return dyn_cast<GenericTypeDecl>(decl);
return ext->getExtendedNominal();
}
/// If this DeclContext is a NominalType declaration or an
/// extension thereof, return the NominalTypeDecl.
NominalTypeDecl *DeclContext::getSelfNominalTypeDecl() const {
return dyn_cast_or_null<NominalTypeDecl>(getSelfTypeDecl());
}
ClassDecl *DeclContext::getSelfClassDecl() const {
return dyn_cast_or_null<ClassDecl>(getSelfTypeDecl());
}
EnumDecl *DeclContext::getSelfEnumDecl() const {
return dyn_cast_or_null<EnumDecl>(getSelfTypeDecl());
}
StructDecl *DeclContext::getSelfStructDecl() const {
return dyn_cast_or_null<StructDecl>(getSelfTypeDecl());
}
ProtocolDecl *DeclContext::getSelfProtocolDecl() const {
return dyn_cast_or_null<ProtocolDecl>(getSelfTypeDecl());
}
ProtocolDecl *DeclContext::getExtendedProtocolDecl() const {
if (auto decl = const_cast<Decl*>(getAsDecl()))
if (auto ED = dyn_cast<ExtensionDecl>(decl))
return dyn_cast_or_null<ProtocolDecl>(ED->getExtendedNominal());
return nullptr;
}
GenericTypeParamType *DeclContext::getProtocolSelfType() const {
assert(getSelfProtocolDecl() && "not a protocol");
GenericParamList *genericParams;
if (auto proto = dyn_cast<ProtocolDecl>(this)) {
genericParams = proto->getGenericParams();
} else {
genericParams = cast<ExtensionDecl>(this)->getGenericParams();
}
if (genericParams == nullptr)
return nullptr;
return genericParams->getParams().front()
->getDeclaredInterfaceType()
->castTo<GenericTypeParamType>();
}
Type DeclContext::getDeclaredTypeInContext() const {
if (auto declaredType = getDeclaredInterfaceType())
return mapTypeIntoContext(declaredType);
return Type();
}
Type DeclContext::getDeclaredInterfaceType() const {
if (auto *ED = dyn_cast<ExtensionDecl>(this)) {
auto *NTD = ED->getExtendedNominal();
if (NTD == nullptr)
return ErrorType::get(ED->getASTContext());
return NTD->getDeclaredInterfaceType();
}
if (auto *NTD = dyn_cast<NominalTypeDecl>(this))
return NTD->getDeclaredInterfaceType();
return Type();
}
void DeclContext::forEachGenericContext(
llvm::function_ref<void (GenericParamList *)> fn) const {
auto dc = this;
do {
if (auto decl = dc->getAsDecl()) {
// Extensions do not capture outer generic parameters.
if (auto *ext = dyn_cast<ExtensionDecl>(decl)) {
for (auto *gpList = ext->getGenericParams();
gpList != nullptr;
gpList = gpList->getOuterParameters()) {
fn(gpList);
}
return;
}
if (auto genericCtx = decl->getAsGenericContext())
if (auto *gpList = genericCtx->getGenericParams())
fn(gpList);
}
} while ((dc = dc->getParent()));
}
unsigned DeclContext::getGenericContextDepth() const {
unsigned depth = -1;
forEachGenericContext([&](GenericParamList *) { ++depth; });
return depth;
}
GenericSignature DeclContext::getGenericSignatureOfContext() const {
auto dc = this;
do {
if (auto decl = dc->getAsDecl())
if (auto GC = decl->getAsGenericContext())
return GC->getGenericSignature();
} while ((dc = dc->getParent()));
return nullptr;
}
GenericEnvironment *DeclContext::getGenericEnvironmentOfContext() const {
auto dc = this;
do {
if (auto decl = dc->getAsDecl())
if (auto GC = decl->getAsGenericContext())
return GC->getGenericEnvironment();
} while ((dc = dc->getParent()));
return nullptr;
}
Type DeclContext::mapTypeIntoContext(Type type) const {
return GenericEnvironment::mapTypeIntoContext(
getGenericEnvironmentOfContext(), type);
}
DeclContext *DeclContext::getLocalContext() {
if (isLocalContext())
return this;
if (isModuleContext())
return nullptr;
return getParent()->getLocalContext();
}
AbstractFunctionDecl *DeclContext::getInnermostMethodContext() {
auto dc = this;
do {
if (auto decl = dc->getAsDecl()) {
auto func = dyn_cast<AbstractFunctionDecl>(decl);
// If we found a non-func decl, we're done.
if (func == nullptr)
return nullptr;
if (func->getDeclContext()->isTypeContext())
return func;
}
} while ((dc = dc->getParent()));
return nullptr;
}
bool DeclContext::isTypeContext() const {
if (auto decl = getAsDecl())
return isa<NominalTypeDecl>(decl) || isa<ExtensionDecl>(decl);
return false;
}
DeclContext *DeclContext::getInnermostTypeContext() {
auto dc = this;
do {
if (dc->isTypeContext())
return dc;
} while ((dc = dc->getParent()));
return nullptr;
}
Decl *DeclContext::getInnermostDeclarationDeclContext() {
auto DC = this;
do {
if (auto decl = DC->getAsDecl())
return isa<ModuleDecl>(decl) ? nullptr : decl;
} while ((DC = DC->getParent()));
return nullptr;
}
DeclContext *DeclContext::getInnermostSkippedFunctionContext() {
auto dc = this;
do {
if (auto afd = dyn_cast<AbstractFunctionDecl>(dc))
if (afd->isBodySkipped())
return afd;
} while ((dc = dc->getParent()));
return nullptr;
}
DeclContext *DeclContext::getParentForLookup() const {
if (isa<ProtocolDecl>(this) || isa<ExtensionDecl>(this)) {
// If we are inside a protocol or an extension, skip directly
// to the module scope context, without looking at any (invalid)
// outer types.
return getModuleScopeContext();
}
if (isa<NominalTypeDecl>(this)) {
// If we are inside a nominal type that is inside a protocol,
// skip the protocol.
if (isa<ProtocolDecl>(getParent()))
return getModuleScopeContext();
}
return getParent();
}
ModuleDecl *DeclContext::getParentModule() const {
const DeclContext *DC = this;
while (!DC->isModuleContext())
DC = DC->getParent();
return const_cast<ModuleDecl *>(cast<ModuleDecl>(DC));
}
SourceFile *DeclContext::getParentSourceFile() const {
const DeclContext *DC = this;
while (!DC->isModuleScopeContext())
DC = DC->getParent();
return const_cast<SourceFile *>(dyn_cast<SourceFile>(DC));
}
DeclContext *DeclContext::getModuleScopeContext() const {
auto DC = const_cast<DeclContext*>(this);
while (true) {
if (DC->ParentAndKind.getInt() == ASTHierarchy::FileUnit)
return DC;
if (auto NextDC = DC->getParent()) {
DC = NextDC;
} else {
assert(isa<ModuleDecl>(DC->getAsDecl()));
return DC;
}
}
}
/// Determine whether the given context is generic at any level.
bool DeclContext::isGenericContext() const {
auto dc = this;
do {
if (auto decl = dc->getAsDecl()) {
if (auto GC = decl->getAsGenericContext()) {
if (GC->getGenericParams())
return true;
// Extensions do not capture outer generic parameters.
if (isa<ExtensionDecl>(decl))
break;
}
}
} while ((dc = dc->getParent()));
return false;
}
/// Get the most optimal resilience expansion for the body of this function.
/// If the body is able to be inlined into functions in other resilience
/// domains, this ensures that only sufficiently-conservative access patterns
/// are used.
ResilienceExpansion DeclContext::getResilienceExpansion() const {
auto &context = getASTContext();
return evaluateOrDefault(context.evaluator,
ResilienceExpansionRequest { const_cast<DeclContext *>(this) },
ResilienceExpansion::Minimal);
}
llvm::Expected<ResilienceExpansion>
swift::ResilienceExpansionRequest::evaluate(Evaluator &evaluator,
DeclContext *context) const {
for (const auto *dc = context->getLocalContext(); dc && dc->isLocalContext();
dc = dc->getParent()) {
// Default argument initializer contexts have their resilience expansion
// set when they're type checked.
if (isa<DefaultArgumentInitializer>(dc)) {
dc = dc->getParent();
auto *VD = cast<ValueDecl>(dc->getAsDecl());
assert(VD->hasParameterList());
auto access =
VD->getFormalAccessScope(/*useDC=*/nullptr,
/*treatUsableFromInlineAsPublic=*/true);
if (access.isPublic())
return ResilienceExpansion::Minimal;
return ResilienceExpansion::Maximal;
}
// Stored property initializer contexts use minimal resilience expansion
// if the type is formally fixed layout.
if (isa<PatternBindingInitializer>(dc)) {
if (auto *NTD = dyn_cast<NominalTypeDecl>(dc->getParent())) {
auto nominalAccess =
NTD->getFormalAccessScope(/*useDC=*/nullptr,
/*treatUsableFromInlineAsPublic=*/true);
if (!nominalAccess.isPublic())
return ResilienceExpansion::Maximal;
if (NTD->isFormallyResilient())
return ResilienceExpansion::Maximal;
return ResilienceExpansion::Minimal;
}
}
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(dc)) {
// If the function is a nested function, we will serialize its body if
// we serialize the parent's body.
if (AFD->getDeclContext()->isLocalContext())
continue;
auto funcAccess =
AFD->getFormalAccessScope(/*useDC=*/nullptr,
/*treatUsableFromInlineAsPublic=*/true);
// If the function is not externally visible, we will not be serializing
// its body.
if (!funcAccess.isPublic())
break;
// If the function is public, @_transparent implies @inlinable.
if (AFD->isTransparent())
return ResilienceExpansion::Minimal;
if (AFD->getAttrs().hasAttribute<InlinableAttr>())
return ResilienceExpansion::Minimal;
if (AFD->getAttrs().hasAttribute<AlwaysEmitIntoClientAttr>())
return ResilienceExpansion::Minimal;
// If a property or subscript is @inlinable or @_alwaysEmitIntoClient,
// the accessors are @inlinable or @_alwaysEmitIntoClient also.
if (auto accessor = dyn_cast<AccessorDecl>(AFD)) {
auto *storage = accessor->getStorage();
if (storage->getAttrs().getAttribute<InlinableAttr>())
return ResilienceExpansion::Minimal;
if (storage->getAttrs().hasAttribute<AlwaysEmitIntoClientAttr>())
return ResilienceExpansion::Minimal;
}
}
}
return ResilienceExpansion::Maximal;
}
/// Determine whether the innermost context is generic.
bool DeclContext::isInnermostContextGeneric() const {
if (auto Decl = getAsDecl())
if (auto GC = Decl->getAsGenericContext())
return GC->isGeneric();
return false;
}
bool
DeclContext::isCascadingContextForLookup(bool functionsAreNonCascading) const {
// FIXME: This is explicitly checking for attributes in some cases because
// it can be called before access control is computed.
switch (getContextKind()) {
case DeclContextKind::AbstractClosureExpr:
break;
case DeclContextKind::SerializedLocal:
llvm_unreachable("should not perform lookups in deserialized contexts");
case DeclContextKind::Initializer:
// Default arguments still require a type.
if (isa<DefaultArgumentInitializer>(this))
return false;
break;
case DeclContextKind::TopLevelCodeDecl:
// FIXME: Pattern initializers at top-level scope end up here.
return true;
case DeclContextKind::AbstractFunctionDecl:
if (functionsAreNonCascading)
return false;
break;
case DeclContextKind::SubscriptDecl:
break;
case DeclContextKind::EnumElementDecl:
break;
case DeclContextKind::Module:
case DeclContextKind::FileUnit:
return true;
case DeclContextKind::GenericTypeDecl:
break;
case DeclContextKind::ExtensionDecl:
return true;
}
return getParent()->isCascadingContextForLookup(true);
}
unsigned DeclContext::getSyntacticDepth() const {
// Module scope == depth 0.
if (isModuleScopeContext())
return 0;
return 1 + getParent()->getSyntacticDepth();
}
unsigned DeclContext::getSemanticDepth() const {
// For extensions, count the depth of the nominal type being extended.
if (isa<ExtensionDecl>(this)) {
if (auto nominal = getSelfNominalTypeDecl())
return nominal->getSemanticDepth();
return 1;
}
// Module scope == depth 0.
if (isModuleScopeContext())
return 0;
return 1 + getParent()->getSemanticDepth();
}
bool DeclContext::mayContainMembersAccessedByDynamicLookup() const {
// Members of non-generic classes and class extensions can be found by
/// dynamic lookup.
if (auto *CD = getSelfClassDecl())
return !CD->isGenericContext();
// Members of @objc protocols (but not protocol extensions) can be
// found by dynamic lookup.
if (auto *PD = dyn_cast<ProtocolDecl>(this))
return PD->getAttrs().hasAttribute<ObjCAttr>();
return false;
}
bool DeclContext::canBeParentOfExtension() const {
return isa<SourceFile>(this);
}
bool DeclContext::walkContext(ASTWalker &Walker) {
switch (getContextKind()) {
case DeclContextKind::Module:
return cast<ModuleDecl>(this)->walk(Walker);
case DeclContextKind::FileUnit:
return cast<FileUnit>(this)->walk(Walker);
case DeclContextKind::AbstractClosureExpr:
return cast<AbstractClosureExpr>(this)->walk(Walker);
case DeclContextKind::GenericTypeDecl:
return cast<GenericTypeDecl>(this)->walk(Walker);
case DeclContextKind::ExtensionDecl:
return cast<ExtensionDecl>(this)->walk(Walker);
case DeclContextKind::TopLevelCodeDecl:
return cast<TopLevelCodeDecl>(this)->walk(Walker);
case DeclContextKind::AbstractFunctionDecl:
return cast<AbstractFunctionDecl>(this)->walk(Walker);
case DeclContextKind::SubscriptDecl:
return cast<SubscriptDecl>(this)->walk(Walker);
case DeclContextKind::EnumElementDecl:
return cast<EnumElementDecl>(this)->walk(Walker);
case DeclContextKind::SerializedLocal:
llvm_unreachable("walk is unimplemented for deserialized contexts");
case DeclContextKind::Initializer:
// Is there any point in trying to walk the expression?
return false;
}
llvm_unreachable("bad DeclContextKind");
}
void DeclContext::dumpContext() const {
printContext(llvm::errs());
}
void AccessScope::dump() const {
llvm::errs() << getAccessLevelSpelling(accessLevelForDiagnostics()) << ": ";
if (isPublic()) {
llvm::errs() << "(null)\n";
return;
}
if (auto *file = dyn_cast<SourceFile>(getDeclContext())) {
llvm::errs() << "file '" << file->getFilename() << "'\n";
return;
}
if (auto *decl = getDeclContext()->getAsDecl()) {
llvm::errs() << Decl::getKindName(decl->getKind()) << " ";
if (auto *ext = dyn_cast<ExtensionDecl>(decl))
llvm::errs() << ext->getExtendedNominal()->getName();
else if (auto *named = dyn_cast<ValueDecl>(decl))
llvm::errs() << named->getFullName();
else
llvm::errs() << (const void *)decl;
SourceLoc loc = decl->getLoc();
if (loc.isValid()) {
llvm::errs() << " at ";
loc.print(llvm::errs(), decl->getASTContext().SourceMgr);
}
llvm::errs() << "\n";
return;
}
// If all else fails, dump the DeclContext tree.
getDeclContext()->printContext(llvm::errs());
}
template <typename DCType>
static unsigned getLineNumber(DCType *DC) {
SourceLoc loc = DC->getLoc();
if (loc.isInvalid())
return 0;
const ASTContext &ctx = static_cast<const DeclContext *>(DC)->getASTContext();
return ctx.SourceMgr.getLineAndColumn(loc).first;
}
unsigned DeclContext::printContext(raw_ostream &OS, const unsigned indent,
const bool onlyAPartialLine) const {
unsigned Depth = 0;
if (!onlyAPartialLine)
if (auto *P = getParent())
Depth = P->printContext(OS, indent);
const char *Kind;
switch (getContextKind()) {
case DeclContextKind::Module: Kind = "Module"; break;
case DeclContextKind::FileUnit: Kind = "FileUnit"; break;
case DeclContextKind::SerializedLocal: Kind = "Serialized Local"; break;
case DeclContextKind::AbstractClosureExpr:
Kind = "AbstractClosureExpr";
break;
case DeclContextKind::GenericTypeDecl:
switch (cast<GenericTypeDecl>(this)->getKind()) {
#define DECL(ID, PARENT) \
case DeclKind::ID: Kind = #ID "Decl"; break;
#include "swift/AST/DeclNodes.def"
}
break;
case DeclContextKind::ExtensionDecl: Kind = "ExtensionDecl"; break;
case DeclContextKind::TopLevelCodeDecl: Kind = "TopLevelCodeDecl"; break;
case DeclContextKind::Initializer: Kind = "Initializer"; break;
case DeclContextKind::AbstractFunctionDecl:
Kind = "AbstractFunctionDecl";
break;
case DeclContextKind::SubscriptDecl: Kind = "SubscriptDecl"; break;
case DeclContextKind::EnumElementDecl: Kind = "EnumElementDecl"; break;
}
OS.indent(Depth*2 + indent) << (void*)this << " " << Kind;
switch (getContextKind()) {
case DeclContextKind::Module:
OS << " name=" << cast<ModuleDecl>(this)->getName();
break;
case DeclContextKind::FileUnit:
switch (cast<FileUnit>(this)->getKind()) {
case FileUnitKind::Builtin:
OS << " Builtin";
break;
case FileUnitKind::Source:
OS << " file=\"" << cast<SourceFile>(this)->getFilename() << "\"";
break;
case FileUnitKind::SerializedAST:
case FileUnitKind::ClangModule:
case FileUnitKind::DWARFModule:
OS << " file=\"" << cast<LoadedFile>(this)->getFilename() << "\"";
break;
}
break;
case DeclContextKind::AbstractClosureExpr:
OS << " line=" << getLineNumber(cast<AbstractClosureExpr>(this));
OS << " : " << cast<AbstractClosureExpr>(this)->getType();
break;
case DeclContextKind::GenericTypeDecl:
OS << " name=" << cast<GenericTypeDecl>(this)->getName();
break;
case DeclContextKind::ExtensionDecl:
OS << " line=" << getLineNumber(cast<ExtensionDecl>(this));
OS << " base=" << cast<ExtensionDecl>(this)->getExtendedType();
break;
case DeclContextKind::TopLevelCodeDecl:
OS << " line=" << getLineNumber(cast<TopLevelCodeDecl>(this));
break;
case DeclContextKind::AbstractFunctionDecl: {
auto *AFD = cast<AbstractFunctionDecl>(this);
OS << " name=" << AFD->getFullName();
if (AFD->hasInterfaceType())
OS << " : " << AFD->getInterfaceType();
else
OS << " : (no type set)";
break;
}
case DeclContextKind::SubscriptDecl: {
auto *SD = cast<SubscriptDecl>(this);
OS << " name=" << SD->getBaseName();
if (SD->hasInterfaceType())
OS << " : " << SD->getInterfaceType();
else
OS << " : (no type set)";
break;
}
case DeclContextKind::EnumElementDecl: {
auto *EED = cast<EnumElementDecl>(this);
OS << " name=" << EED->getBaseName();
if (EED->hasInterfaceType())
OS << " : " << EED->getInterfaceType();
else
OS << " : (no type set)";
break;
}
case DeclContextKind::Initializer:
switch (cast<Initializer>(this)->getInitializerKind()) {
case InitializerKind::PatternBinding: {
auto init = cast<PatternBindingInitializer>(this);
OS << " PatternBinding 0x" << (void*) init->getBinding()
<< " #" << init->getBindingIndex();
break;
}
case InitializerKind::DefaultArgument: {
auto init = cast<DefaultArgumentInitializer>(this);
OS << " DefaultArgument index=" << init->getIndex();
break;
}
}
break;
case DeclContextKind::SerializedLocal: {
auto local = cast<SerializedLocalDeclContext>(this);
switch (local->getLocalDeclContextKind()) {
case LocalDeclContextKind::AbstractClosure: {
auto serializedClosure = cast<SerializedAbstractClosureExpr>(local);
OS << " closure : " << serializedClosure->getType();
break;
}
case LocalDeclContextKind::DefaultArgumentInitializer: {
auto init = cast<SerializedDefaultArgumentInitializer>(local);
OS << "DefaultArgument index=" << init->getIndex();
break;
}
case LocalDeclContextKind::PatternBindingInitializer: {
auto init = cast<SerializedPatternBindingInitializer>(local);
OS << " PatternBinding 0x" << (void*) init->getBinding()
<< " #" << init->getBindingIndex();
break;
}
case LocalDeclContextKind::TopLevelCodeDecl:
OS << " TopLevelCode";
break;
}
}
}
if (!onlyAPartialLine)
OS << "\n";
return Depth + 1;
}
const Decl *
IterableDeclContext::getDecl() const {
switch (getIterableContextKind()) {
case IterableDeclContextKind::NominalTypeDecl:
return cast<NominalTypeDecl>(this);
break;
case IterableDeclContextKind::ExtensionDecl:
return cast<ExtensionDecl>(this);
break;
}
llvm_unreachable("Unhandled IterableDeclContextKind in switch.");
}
ASTContext &IterableDeclContext::getASTContext() const {
return getDecl()->getASTContext();
}
DeclRange IterableDeclContext::getCurrentMembersWithoutLoading() const {
return DeclRange(FirstDeclAndLazyMembers.getPointer(), nullptr);
}
DeclRange IterableDeclContext::getMembers() const {
loadAllMembers();
return getCurrentMembersWithoutLoading();
}
/// Add a member to this context.
void IterableDeclContext::addMember(Decl *member, Decl *Hint) {
// Add the member to the list of declarations without notification.
addMemberSilently(member, Hint);
++MemberCount;
// Notify our parent declaration that we have added the member, which can
// be used to update the lookup tables.
switch (getIterableContextKind()) {
case IterableDeclContextKind::NominalTypeDecl: {
auto nominal = cast<NominalTypeDecl>(this);
nominal->addedMember(member);
assert(member->getDeclContext() == nominal &&
"Added member to the wrong context");
break;
}
case IterableDeclContextKind::ExtensionDecl: {
auto ext = cast<ExtensionDecl>(this);
ext->addedMember(member);
assert(member->getDeclContext() == ext &&
"Added member to the wrong context");
break;
}
}
}
void IterableDeclContext::addMemberSilently(Decl *member, Decl *hint) const {
assert(!isa<AccessorDecl>(member) && "Accessors should not be added here");
assert(!member->NextDecl && "Already added to a container");
// If there is a hint decl that specifies where to add this, just
// link into the chain immediately following it.
if (hint) {
member->NextDecl = hint->NextDecl;
hint->NextDecl = member;
// If the hint was the last in the parent context's chain, update it.
if (LastDeclAndKind.getPointer() == hint)
LastDeclAndKind.setPointer(member);
return;
}
if (auto last = LastDeclAndKind.getPointer()) {
last->NextDecl = member;
assert(last != member && "Simple cycle in decl list");
} else {
FirstDeclAndLazyMembers.setPointer(member);
}
LastDeclAndKind.setPointer(member);
}
void IterableDeclContext::setMemberLoader(LazyMemberLoader *loader,
uint64_t contextData) {
assert(!hasLazyMembers() && "already have lazy members");
ASTContext &ctx = getASTContext();
auto contextInfo = ctx.getOrCreateLazyIterableContextData(this, loader);
auto lazyMembers = FirstDeclAndLazyMembers.getInt() | LazyMembers::Present;
FirstDeclAndLazyMembers.setInt(LazyMembers(lazyMembers));
contextInfo->memberData = contextData;
++NumLazyIterableDeclContexts;
++NumUnloadedLazyIterableDeclContexts;
// FIXME: (transitional) increment the redundant "always-on" counter.
if (auto s = ctx.Stats) {
++s->getFrontendCounters().NumLazyIterableDeclContexts;
++s->getFrontendCounters().NumUnloadedLazyIterableDeclContexts;
}
}
bool IterableDeclContext::hasUnparsedMembers() const {
if (AddedParsedMembers)
return false;
if (!getDecl()->getDeclContext()->getParentSourceFile()) {
// There will never be any parsed members to add, so set the flag to say
// we are done so we can short-circuit next time.
const_cast<IterableDeclContext *>(this)->AddedParsedMembers = 1;
return false;
}
return true;
}
unsigned IterableDeclContext::getMemberCount() const {
if (hasUnparsedMembers())
loadAllMembers();
return MemberCount;
}
void IterableDeclContext::loadAllMembers() const {
ASTContext &ctx = getASTContext();
// For contexts within a source file, get the list of parsed members.
if (getDecl()->getDeclContext()->getParentSourceFile()) {
// Retrieve the parsed members. Even if we've already added the parsed
// members to this context, this call is important for recording the
// dependency edge.
auto mutableThis = const_cast<IterableDeclContext *>(this);
auto members = evaluateOrDefault(
ctx.evaluator, ParseMembersRequest{mutableThis}, ArrayRef<Decl*>());
// If we haven't already done so, add these members to this context.
if (!AddedParsedMembers) {
mutableThis->AddedParsedMembers = 1;
for (auto member : members) {
mutableThis->addMember(member);
}
}
}
if (!hasLazyMembers())
return;
// Don't try to load all members re-entrant-ly.
auto contextInfo = ctx.getOrCreateLazyIterableContextData(this,
/*lazyLoader=*/nullptr);
auto lazyMembers = FirstDeclAndLazyMembers.getInt() & ~LazyMembers::Present;
FirstDeclAndLazyMembers.setInt(LazyMembers(lazyMembers));
const Decl *container = getDecl();
contextInfo->loader->loadAllMembers(const_cast<Decl *>(container),
contextInfo->memberData);
--NumUnloadedLazyIterableDeclContexts;
// FIXME: (transitional) decrement the redundant "always-on" counter.
if (auto s = ctx.Stats)
s->getFrontendCounters().NumUnloadedLazyIterableDeclContexts--;
}
bool IterableDeclContext::wasDeserialized() const {
const DeclContext *DC = cast<DeclContext>(getDecl());
if (auto F = dyn_cast<FileUnit>(DC->getModuleScopeContext())) {
return F->getKind() == FileUnitKind::SerializedAST;
}
return false;
}
bool IterableDeclContext::classof(const Decl *D) {
switch (D->getKind()) {
default: return false;
#define DECL(ID, PARENT) // See previous line
#define ITERABLE_DECL(ID, PARENT) \
case DeclKind::ID: return true;
#include "swift/AST/DeclNodes.def"
}
}
IterableDeclContext *
IterableDeclContext::castDeclToIterableDeclContext(const Decl *D) {
switch (D->getKind()) {
default: llvm_unreachable("Decl is not a IterableDeclContext.");
#define DECL(ID, PARENT) // See previous line
#define ITERABLE_DECL(ID, PARENT) \
case DeclKind::ID: \
return const_cast<IterableDeclContext *>( \
static_cast<const IterableDeclContext*>(cast<ID##Decl>(D)));
#include "swift/AST/DeclNodes.def"
}
}
/// Return the DeclContext to compare when checking private access in
/// Swift 4 mode. The context returned is the type declaration if the context
/// and the type declaration are in the same file, otherwise it is the types
/// last extension in the source file. If the context does not refer to a
/// declaration or extension, the supplied context is returned.
static const DeclContext *
getPrivateDeclContext(const DeclContext *DC, const SourceFile *useSF) {
auto NTD = DC->getSelfNominalTypeDecl();
if (!NTD)
return DC;
// use the type declaration as the private scope if it is in the same
// file as useSF. This occurs for both extensions and declarations.
if (NTD->getParentSourceFile() == useSF)
return NTD;
// Otherwise use the last extension declaration in the same file.
const DeclContext *lastExtension = nullptr;
for (ExtensionDecl *ED : NTD->getExtensions())
if (ED->getParentSourceFile() == useSF)
lastExtension = ED;
// If there's no last extension, return the supplied context.
return lastExtension ? lastExtension : DC;
}
AccessScope::AccessScope(const DeclContext *DC, bool isPrivate)
: Value(DC, isPrivate) {
if (isPrivate) {
DC = getPrivateDeclContext(DC, DC->getParentSourceFile());
Value.setPointer(DC);
}
if (!DC || isa<ModuleDecl>(DC))
assert(!isPrivate && "public or internal scope can't be private");
}
bool AccessScope::isFileScope() const {
auto DC = getDeclContext();
return DC && isa<FileUnit>(DC);
}
bool AccessScope::isInternal() const {
auto DC = getDeclContext();
return DC && isa<ModuleDecl>(DC);
}
AccessLevel AccessScope::accessLevelForDiagnostics() const {
if (isPublic())
return AccessLevel::Public;
if (isa<ModuleDecl>(getDeclContext()))
return AccessLevel::Internal;
if (getDeclContext()->isModuleScopeContext()) {
return isPrivate() ? AccessLevel::Private : AccessLevel::FilePrivate;
}
return AccessLevel::Private;
}
bool AccessScope::allowsPrivateAccess(const DeclContext *useDC, const DeclContext *sourceDC) {
// Check the lexical scope.
if (useDC->isChildContextOf(sourceDC))
return true;
// Do not allow access if the sourceDC is in a different file
auto useSF = useDC->getParentSourceFile();
if (useSF != sourceDC->getParentSourceFile())
return false;
// Do not allow access if the sourceDC does not represent a type.
auto sourceNTD = sourceDC->getSelfNominalTypeDecl();
if (!sourceNTD)
return false;
// Compare the private scopes and iterate over the parent types.
sourceDC = getPrivateDeclContext(sourceDC, useSF);
while (!useDC->isModuleContext()) {
useDC = getPrivateDeclContext(useDC, useSF);
if (useDC == sourceDC)
return true;
// Get the parent type. If the context represents a type, look at the types
// declaring context instead of the contexts parent. This will crawl up
// the type hierarchy in nested extensions correctly.
if (auto NTD = useDC->getSelfNominalTypeDecl())
useDC = NTD->getDeclContext();
else
useDC = useDC->getParent();
}
return false;
}
DeclContext *Decl::getDeclContextForModule() const {
if (auto module = dyn_cast<ModuleDecl>(this))
return const_cast<ModuleDecl *>(module);
return nullptr;
}
DeclContextKind DeclContext::getContextKind() const {
switch (ParentAndKind.getInt()) {
case ASTHierarchy::Expr:
return DeclContextKind::AbstractClosureExpr;
case ASTHierarchy::Initializer:
return DeclContextKind::Initializer;
case ASTHierarchy::SerializedLocal:
return DeclContextKind::SerializedLocal;
case ASTHierarchy::FileUnit:
return DeclContextKind::FileUnit;
case ASTHierarchy::Decl: {
auto decl = reinterpret_cast<const Decl*>(this + 1);
if (isa<AbstractFunctionDecl>(decl))
return DeclContextKind::AbstractFunctionDecl;
if (isa<GenericTypeDecl>(decl))
return DeclContextKind::GenericTypeDecl;
switch (decl->getKind()) {
case DeclKind::Module:
return DeclContextKind::Module;
case DeclKind::TopLevelCode:
return DeclContextKind::TopLevelCodeDecl;
case DeclKind::Subscript:
return DeclContextKind::SubscriptDecl;
case DeclKind::EnumElement:
return DeclContextKind::EnumElementDecl;
case DeclKind::Extension:
return DeclContextKind::ExtensionDecl;
default:
llvm_unreachable("Unhandled Decl kind");
}
}
}
llvm_unreachable("Unhandled DeclContext ASTHierarchy");
}
SourceLoc swift::extractNearestSourceLoc(const DeclContext *dc) {
switch (dc->getContextKind()) {
case DeclContextKind::AbstractFunctionDecl:
case DeclContextKind::EnumElementDecl:
case DeclContextKind::ExtensionDecl:
case DeclContextKind::GenericTypeDecl:
case DeclContextKind::Module:
case DeclContextKind::SubscriptDecl:
case DeclContextKind::TopLevelCodeDecl:
return extractNearestSourceLoc(dc->getAsDecl());
case DeclContextKind::AbstractClosureExpr: {
SourceLoc loc = cast<AbstractClosureExpr>(dc)->getLoc();
if (loc.isValid())
return loc;
return extractNearestSourceLoc(dc->getParent());
}
case DeclContextKind::FileUnit:
return SourceLoc();
case DeclContextKind::Initializer:
case DeclContextKind::SerializedLocal:
return extractNearestSourceLoc(dc->getParent());
}
llvm_unreachable("Unhandled DeclCopntextKindin switch");
}
#define DECL(Id, Parent) \
static_assert(!std::is_base_of<DeclContext, Id##Decl>::value, \
"Non-context Decl node has context?");
#define CONTEXT_DECL(Id, Parent) \
static_assert(alignof(DeclContext) == alignof(Id##Decl), "Alignment error"); \
static_assert(std::is_base_of<DeclContext, Id##Decl>::value, \
"CONTEXT_DECL nodes must inherit from DeclContext");
#define CONTEXT_VALUE_DECL(Id, Parent) \
static_assert(alignof(DeclContext) == alignof(Id##Decl), "Alignment error"); \
static_assert(std::is_base_of<DeclContext, Id##Decl>::value, \
"CONTEXT_VALUE_DECL nodes must inherit from DeclContext");
#include "swift/AST/DeclNodes.def"
#define EXPR(Id, Parent) \
static_assert(!std::is_base_of<DeclContext, Id##Expr>::value, \
"Non-context Expr node has context?");
#define CONTEXT_EXPR(Id, Parent) \
static_assert(alignof(DeclContext) == alignof(Id##Expr), "Alignment error"); \
static_assert(std::is_base_of<DeclContext, Id##Expr>::value, \
"CONTEXT_EXPR nodes must inherit from DeclContext");
#include "swift/AST/ExprNodes.def"
#ifndef NDEBUG
// XXX -- static_cast is not static enough for use with static_assert().
// DO verify this by temporarily breaking a Decl or Expr.
// DO NOT assume that the compiler will emit this code blindly.
SWIFT_CONSTRUCTOR
static void verify_DeclContext_is_start_of_node() {
auto decl = reinterpret_cast<Decl*>(0x1000 + sizeof(DeclContext));
#define DECL(Id, Parent)
#define CONTEXT_DECL(Id, Parent) \
assert(reinterpret_cast<DeclContext*>(0x1000) == \
static_cast<Id##Decl*>(decl));
#define CONTEXT_VALUE_DECL(Id, Parent) \
assert(reinterpret_cast<DeclContext*>(0x1000) == \
static_cast<Id##Decl*>(decl));
#include "swift/AST/DeclNodes.def"
auto expr = reinterpret_cast<Expr*>(0x1000 + sizeof(DeclContext));
#define EXPR(Id, Parent)
#define CONTEXT_EXPR(Id, Parent) \
assert(reinterpret_cast<DeclContext*>(0x1000) == \
static_cast<Id##Expr*>(expr));
#include "swift/AST/ExprNodes.def"
}
#endif
void swift::simple_display(llvm::raw_ostream &out,
const IterableDeclContext *idc) {
simple_display(out, idc->getDecl());
}
SourceLoc swift::extractNearestSourceLoc(const IterableDeclContext *idc) {
return extractNearestSourceLoc(idc->getDecl());
}