Files
swift-mirror/include/swift/AST/NameLookup.h
2025-10-24 16:23:48 -07:00

883 lines
32 KiB
C++
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//===--- NameLookup.h - Swift Name Lookup Routines --------------*- 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
//
//===----------------------------------------------------------------------===//
//
// This file defines interfaces for performing name lookup.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_AST_NAME_LOOKUP_H
#define SWIFT_AST_NAME_LOOKUP_H
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/CatchNode.h"
#include "swift/AST/ConformanceAttributes.h"
#include "swift/AST/GenericSignature.h"
#include "swift/AST/Identifier.h"
#include "swift/AST/Module.h"
#include "swift/Basic/Compiler.h"
#include "swift/Basic/Debug.h"
#include "swift/Basic/NullablePtr.h"
#include "swift/Basic/SourceLoc.h"
#include "swift/Basic/SourceManager.h"
#include "llvm/ADT/SmallVector.h"
#include "swift/AST/TypeRepr.h"
namespace swift {
class ASTContext;
class DeclNameRef;
class Type;
class TypeDecl;
class ValueDecl;
struct SelfBounds;
class NominalTypeDecl;
namespace ast_scope {
class ASTSourceFileScope;
class ASTScopeImpl;
} // namespace ast_scope
/// Walk the type representation recursively, collecting any
/// \c OpaqueReturnTypeRepr, \c CompositionTypeRepr or \c DeclRefTypeRepr
/// nodes.
CollectedOpaqueReprs collectOpaqueTypeReprs(TypeRepr *, ASTContext &ctx,
DeclContext *dc);
/// LookupResultEntry - One result of unqualified lookup.
struct LookupResultEntry {
private:
/// The declaration context through which we found \c Value. For instance,
/// \code
/// class BaseClass {
/// func foo() {}
/// }
///
/// class DerivedClass : BaseClass {
/// func bar() {}
/// }
/// \endcode
///
/// When finding \c foo() from the body of \c DerivedClass, \c BaseDC is \c
/// DerivedClass.
///
/// Another example:
/// \code
/// class BaseClass {
/// func bar() {}
/// func foo() {}
/// }
/// \endcode
///
/// When finding \c bar() from the function body of \c foo(), \c BaseDC is
/// the method \c foo().
///
/// \c BaseDC will be the type if \c self is not needed for the lookup. If
/// \c self is needed, \c baseDC will be either the method or a closure
/// which explicitly captured \c self.
/// In other words: If \c baseDC is a method or a closure, it means you
/// found an instance member and you should add an implicit 'self.' (Each
/// method has its own implicit self decl.) There's one other kind of
/// non-method, non-closure context that has a 'self.' -- a lazy property
/// initializer, which unlike a non-lazy property can reference \c self.
/// \code
/// class Outer {
/// static func s()
/// func i()
/// class Inner {
/// static func ss()
/// func ii() {
/// func F() {
/// ii() // OK! implicitly self.ii; BaseDC is the method
/// s()// OK! s() is defined in an outer type; BaseDC is the type
/// ss() // error: must write /Inner.ss() here since its static
/// i() // error: there's no outer 'self.'
/// }
/// }
/// \endcode
///
/// To sum up: The distinction is whether you need to know the run-time
/// value of \c self. It might be clearer if \code baseDC was always a type,
/// and there was an additional \c ParamDecl field in \c LookupResult which
/// would store the implicit self, if any. \c BaseDC is always one of your
/// outer DCs. if you're inside a type it should never be an extension of
/// that type. And if you're inside an extension it will always be an
/// extension (if it found something at that level).
DeclContext *BaseDC;
/// The declaration that defines the base of the call to `Value`.
/// This is always available, as long as `BaseDC` is not null.
ValueDecl *BaseDecl;
/// The declaration corresponds to the given name; i.e. the decl we are
/// looking up.
ValueDecl *Value;
public:
LookupResultEntry(ValueDecl *value)
: BaseDC(nullptr), BaseDecl(nullptr), Value(value) {}
LookupResultEntry(DeclContext *baseDC, ValueDecl *baseDecl, ValueDecl *value)
: BaseDC(baseDC), BaseDecl(baseDecl), Value(value) {}
ValueDecl *getValueDecl() const { return Value; }
DeclContext *getDeclContext() const { return BaseDC; }
ValueDecl *getBaseDecl() const;
friend bool operator ==(const LookupResultEntry &lhs,
const LookupResultEntry &rhs) {
return lhs.BaseDC == rhs.BaseDC && lhs.Value == rhs.Value;
}
void print(llvm::raw_ostream &) const;
};
/// The result of name lookup.
class LookupResult {
private:
/// The set of results found.
SmallVector<LookupResultEntry, 4> Results;
size_t IndexOfFirstOuterResult = 0;
public:
LookupResult() {}
explicit LookupResult(const SmallVectorImpl<LookupResultEntry> &Results,
size_t indexOfFirstOuterResult)
: Results(Results.begin(), Results.end()),
IndexOfFirstOuterResult(indexOfFirstOuterResult) {}
using const_iterator = SmallVectorImpl<LookupResultEntry>::const_iterator;
const_iterator begin() const { return Results.begin(); }
const_iterator end() const {
return Results.begin() + IndexOfFirstOuterResult;
}
using iterator = SmallVectorImpl<LookupResultEntry>::iterator;
iterator begin() { return Results.begin(); }
iterator end() {
return Results.begin() + IndexOfFirstOuterResult;
}
unsigned size() const { return innerResults().size(); }
bool empty() const { return innerResults().empty(); }
ArrayRef<LookupResultEntry> innerResults() const {
return llvm::ArrayRef(Results).take_front(IndexOfFirstOuterResult);
}
ArrayRef<LookupResultEntry> outerResults() const {
return llvm::ArrayRef(Results).drop_front(IndexOfFirstOuterResult);
}
/// \returns An array of both the inner and outer results.
ArrayRef<LookupResultEntry> allResults() const {
return llvm::ArrayRef(Results);
}
const LookupResultEntry& operator[](unsigned index) const {
return Results[index];
}
LookupResultEntry front() const { return innerResults().front(); }
LookupResultEntry back() const { return innerResults().back(); }
/// \returns The index of the first outer result within \c allResults().
size_t getIndexOfFirstOuterResult() const { return IndexOfFirstOuterResult; }
/// Add a result to the set of results.
void add(LookupResultEntry result, bool isOuter) {
Results.push_back(result);
if (!isOuter) {
IndexOfFirstOuterResult++;
assert(IndexOfFirstOuterResult == Results.size() &&
"found an outer result before an inner one");
} else {
assert(IndexOfFirstOuterResult > 0 &&
"found outer results without an inner one");
}
}
void clear() { Results.clear(); }
/// Determine whether the result set is nonempty.
explicit operator bool() const {
return !empty();
}
TypeDecl *getSingleTypeResult() const {
if (size() != 1)
return nullptr;
return dyn_cast<TypeDecl>(front().getValueDecl());
}
friend bool operator ==(const LookupResult &lhs, const LookupResult &rhs) {
return lhs.Results == rhs.Results &&
lhs.IndexOfFirstOuterResult == rhs.IndexOfFirstOuterResult;
}
/// Filter out any results that aren't accepted by the given predicate.
void
filter(llvm::function_ref<bool(LookupResultEntry, /*isOuter*/ bool)> pred);
/// Shift down results by dropping inner results while keeping outer
/// results (if any), the innermost of which are recognized as inner
/// results afterwards.
void shiftDownResults();
};
enum class UnqualifiedLookupFlags {
/// This lookup should only return types.
TypeLookup = 1 << 0,
/// This lookup should consider declarations within protocols to which the
/// context type conforms.
AllowProtocolMembers = 1 << 2,
/// Don't check access when doing lookup into a type.
IgnoreAccessControl = 1 << 3,
/// This lookup should include results from outside the innermost scope with
/// results.
IncludeOuterResults = 1 << 4,
// This lookup should include results that are @inlinable or
// @usableFromInline.
IncludeUsableFromInline = 1 << 5,
/// This lookup should exclude any names introduced by macro expansions.
ExcludeMacroExpansions = 1 << 6,
/// This lookup should only return macros.
MacroLookup = 1 << 7,
/// This lookup should only return modules
ModuleLookup = 1 << 8,
/// This lookup should discard 'Self' requirements in protocol extension
/// 'where' clauses.
DisregardSelfBounds = 1 << 9,
/// This lookup should include members that would otherwise be filtered out
/// because they come from a module that has not been imported.
IgnoreMissingImports = 1 << 10,
/// If @abi attributes are present, return the decls representing the ABI,
/// not the API.
ABIProviding = 1 << 11,
// Reminder: If you add a flag, make sure you update simple_display() below
};
using UnqualifiedLookupOptions = OptionSet<UnqualifiedLookupFlags>;
void simple_display(llvm::raw_ostream &out, UnqualifiedLookupOptions options);
inline UnqualifiedLookupOptions operator|(UnqualifiedLookupFlags flag1,
UnqualifiedLookupFlags flag2) {
return UnqualifiedLookupOptions(flag1) | flag2;
}
/// Describes the reason why a certain declaration is visible.
enum class DeclVisibilityKind {
/// Declaration is a local variable or type.
LocalDecl,
/// Declaration is a function parameter.
FunctionParameter,
/// Declaration is a generic parameter.
GenericParameter,
/// Declaration is a member of the immediately enclosing nominal decl.
///
/// For example, 'Foo' is visible at (1) because of this.
/// \code
/// struct A {
/// typealias Foo = Int
/// func f() {
/// // (1)
/// }
/// }
/// \endcode
MemberOfCurrentNominal,
/// Declaration is a requirement in case the nominal decl does not supply
/// a corresponding witness or an extension member of a protocol
/// conformed to by the immediately enclosing nominal decl.
///
/// For example, 'foo' is visible at (1) because of this.
/// \code
/// protocol P {
/// func foo()
/// }
/// struct A : P {
/// func bar() {
/// // (1)
/// }
/// }
/// \endcode
MemberOfProtocolConformedToByCurrentNominal,
/// Declaration is a derived requirement of a protocol conformed to by the
/// immediately enclosing nominal decl (a witness for a synthesized
/// conformance).
MemberOfProtocolDerivedByCurrentNominal,
/// Declaration is a member of the superclass of the immediately enclosing
/// nominal decl.
MemberOfSuper,
/// Declaration is a member of the non-immediately enclosing nominal decl.
///
/// For example, 'Foo' is visible at (1) because of this.
/// \code
/// struct A {
/// typealias Foo = Int
/// struct B {
/// func foo() {
/// // (1)
/// }
/// }
/// }
/// \endcode
MemberOfOutsideNominal,
/// Declaration is visible at the top level because it is declared in this
/// module or in an imported module.
VisibleAtTopLevel,
/// Declaration was found via \c AnyObject or \c AnyObject.Type.
DynamicLookup,
};
/// For Decls found with DeclVisibilityKind::DynamicLookup, contains details of
/// how they were looked up. For example, the SubscriptDecl used to find a
/// KeyPath dynamic member.
class DynamicLookupInfo {
public:
enum Kind {
None,
AnyObject,
KeyPathDynamicMember,
};
struct KeyPathDynamicMemberInfo {
/// The subscript(dynamicMember:) by which we found the declaration.
SubscriptDecl *subscript = nullptr;
/// The type context of `subscript`, which may be different than the
/// original base type of the lookup if this declaration was found by nested
/// dynamic lookups.
Type baseType = Type();
/// Visibility of the declaration itself without dynamic lookup.
///
/// For example, dynamic lookup for KeyPath<Derived, U>, might find
/// Base::foo with originalVisibility == MemberOfSuper.
DeclVisibilityKind originalVisibility = DeclVisibilityKind::DynamicLookup;
};
Kind getKind() const { return kind; }
const KeyPathDynamicMemberInfo &getKeyPathDynamicMember() const;
DynamicLookupInfo() : kind(None) {}
DynamicLookupInfo(Kind kind) : kind(kind) {
assert(kind != KeyPathDynamicMember && "use KeyPathDynamicMemberInfo ctor");
}
/// Construct for a KeyPath dynamic member lookup.
DynamicLookupInfo(SubscriptDecl *subscript, Type baseType,
DeclVisibilityKind originalVisibility);
private:
Kind kind;
KeyPathDynamicMemberInfo keypath = {};
};
/// An abstract base class for a visitor that consumes declarations found within
/// a given context.
class VisibleDeclConsumer {
virtual void anchor();
public:
virtual ~VisibleDeclConsumer() = default;
/// This method is called every time it look for members from a decl.
virtual void onLookupNominalTypeMembers(NominalTypeDecl *NTD,
DeclVisibilityKind Reason) {}
/// This method is called by findVisibleDecls() every time it finds a decl.
virtual void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason,
DynamicLookupInfo dynamicLookupInfo = {}) = 0;
};
/// An implementation of VisibleDeclConsumer that's built from a lambda.
template <class Fn>
class LambdaDeclConsumer : public VisibleDeclConsumer {
Fn Callback;
public:
LambdaDeclConsumer(Fn &&callback) : Callback(std::move(callback)) {}
void foundDecl(ValueDecl *VD, DeclVisibilityKind reason, DynamicLookupInfo) override {
Callback(VD, reason);
}
};
template <class Fn>
LambdaDeclConsumer<Fn> makeDeclConsumer(Fn &&callback) {
return LambdaDeclConsumer<Fn>(std::move(callback));
}
/// A consumer that inserts found decls into an externally-owned SmallVector.
class VectorDeclConsumer : public VisibleDeclConsumer {
virtual void anchor() override;
public:
SmallVectorImpl<ValueDecl *> &results;
explicit VectorDeclConsumer(SmallVectorImpl<ValueDecl *> &decls)
: results(decls) {}
virtual void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason,
DynamicLookupInfo) override {
results.push_back(VD);
}
};
/// A consumer that filters out decls that are not accessible from a given
/// DeclContext.
class AccessFilteringDeclConsumer final : public VisibleDeclConsumer {
const DeclContext *DC;
VisibleDeclConsumer &ChainedConsumer;
public:
AccessFilteringDeclConsumer(const DeclContext *DC,
VisibleDeclConsumer &consumer)
: DC(DC), ChainedConsumer(consumer) {}
void onLookupNominalTypeMembers(NominalTypeDecl *NTD,
DeclVisibilityKind Reason) override {
ChainedConsumer.onLookupNominalTypeMembers(NTD, Reason);
}
void foundDecl(ValueDecl *D, DeclVisibilityKind reason,
DynamicLookupInfo dynamicLookupInfo = {}) override;
};
/// Filters out decls that are not usable based on their source location, e.g.
/// a top-level decl inside its own initializer or shadowed decls.
class UsableFilteringDeclConsumer final : public VisibleDeclConsumer {
const SourceManager &SM;
const DeclContext *DC;
const DeclContext *typeContext;
SourceLoc Loc;
llvm::DenseMap<DeclBaseName, std::pair<ValueDecl *, DeclVisibilityKind>>
SeenNames;
VisibleDeclConsumer &ChainedConsumer;
public:
UsableFilteringDeclConsumer(const SourceManager &SM, const DeclContext *DC,
SourceLoc loc, VisibleDeclConsumer &consumer)
: SM(SM), DC(DC), typeContext(DC->getInnermostTypeContext()), Loc(loc),
ChainedConsumer(consumer) {}
void onLookupNominalTypeMembers(NominalTypeDecl *NTD,
DeclVisibilityKind Reason) override {
ChainedConsumer.onLookupNominalTypeMembers(NTD, Reason);
}
void foundDecl(ValueDecl *D, DeclVisibilityKind reason,
DynamicLookupInfo dynamicLookupInfo = {}) override;
};
/// Remove any declarations in the given set that were overridden by
/// other declarations in that set.
///
/// \returns true if any declarations were removed, false otherwise.
bool removeOverriddenDecls(SmallVectorImpl<ValueDecl*> &decls);
/// Remove any declarations in the given set that do not match the
/// module selector, if it is not empty.
///
/// \returns true if any declarations were removed, false otherwise.
bool removeOutOfModuleDecls(SmallVectorImpl<ValueDecl*> &decls,
Identifier moduleSelector,
const DeclContext *dc);
/// Remove any declarations in the given set that are shadowed by
/// other declarations in that set.
///
/// \param decls The set of declarations being considered.
/// \param dc The DeclContext from which the lookup was performed.
///
/// \returns true if any shadowed declarations were removed.
bool removeShadowedDecls(SmallVectorImpl<ValueDecl*> &decls,
const DeclContext *dc);
/// Remove any operators in the given set that are shadowed by
/// other operators in that set.
///
/// \param decls The set of operators being considered.
/// \param dc The DeclContext from which the lookup was performed.
///
/// \returns true if any shadowed declarations were removed.
bool removeShadowedDecls(TinyPtrVector<OperatorDecl *> &decls,
const DeclContext *dc);
/// Remove any precedence groups in the given set that are shadowed by
/// other precedence groups in that set.
///
/// \param decls The set of precedence groups being considered.
/// \param dc The DeclContext from which the lookup was performed.
///
/// \returns true if any shadowed declarations were removed.
bool removeShadowedDecls(TinyPtrVector<PrecedenceGroupDecl *> &decls,
const DeclContext *dc);
/// Finds decls visible in the given context at the given location and feeds
/// them to the given VisibleDeclConsumer. The \p Loc must be valid, and \p DC
/// must be in a SourceFile.
void lookupVisibleDecls(VisibleDeclConsumer &Consumer, SourceLoc Loc,
const DeclContext *DC, bool IncludeTopLevel);
/// Finds decls visible as members of the given type and feeds them to the given
/// VisibleDeclConsumer.
///
/// \param CurrDC the DeclContext from which the lookup is done.
void lookupVisibleMemberDecls(VisibleDeclConsumer &Consumer,
Type BaseTy, SourceLoc loc,
const DeclContext *CurrDC,
bool includeInstanceMembers,
bool includeDerivedRequirements,
bool includeProtocolExtensionMembers,
GenericSignature genericSig = GenericSignature());
/// Determine the module-scope context from which lookup should proceed.
///
/// In the common case, module-scope context is the source file in which
/// the declaration context is nested. However, when declaration context is
/// part of an imported Clang declaration context, it won't be nested within a
/// source file. Rather, the source file will be on the side, and will be
/// provided here because it contains information about the available imports.
DeclContext *getModuleScopeLookupContext(DeclContext *dc);
namespace namelookup {
/// Add semantic members to \p type before attempting a semantic lookup.
void installSemanticMembersIfNeeded(Type type, DeclNameRef name);
/// Extracts directly referenced nominal type decls from a given type, asserting
/// if the type does not contain any references to a nominal.
void extractDirectlyReferencedNominalTypes(
Type type, SmallVectorImpl<NominalTypeDecl *> &decls);
/// Extracts directly referenced nominal type decls from a given type, or leaves
/// the vector empty if the type does not contain any references to a nominal.
void tryExtractDirectlyReferencedNominalTypes(
Type type, SmallVectorImpl<NominalTypeDecl *> &decls);
/// Once name lookup has gathered a set of results, perform any necessary
/// steps to prune the result set before returning it to the caller.
void pruneLookupResultSet(const DeclContext *dc, NLOptions options,
Identifier moduleSelector,
SmallVectorImpl<ValueDecl *> &decls);
/// Do nothing if debugClient is null.
template <typename Result>
void filterForDiscriminator(SmallVectorImpl<Result> &results,
DebuggerClient *debugClient);
/// \returns Whether the given source location is inside an \@abi attribute.
bool isInABIAttr(SourceFile *sourceFile, SourceLoc loc);
/// \returns The set of macro declarations with the given name that
/// fulfill any of the given macro roles.
SmallVector<MacroDecl *, 1> lookupMacros(DeclContext *dc,
DeclNameRef moduleName,
DeclNameRef macroName,
MacroRoles roles);
/// \returns Whether the given source location is inside an attached
/// or freestanding macro argument.
bool isInMacroArgument(SourceFile *sourceFile, SourceLoc loc);
/// Call the given function body with each macro declaration and its associated
/// role attribute for the given role.
///
/// This routine intentionally avoids calling `forEachAttachedMacro`, which
/// triggers request cycles, and should only be used when resolving macro
/// names for the purposes of (other) name lookup.
void forEachPotentialResolvedMacro(
DeclContext *moduleScopeCtx, DeclNameRef macroName, MacroRole role,
llvm::function_ref<void(MacroDecl *, const MacroRoleAttr *)> body
);
/// For each macro with the given role that might be attached to the given
/// declaration, call the body.
void forEachPotentialAttachedMacro(
Decl *decl, MacroRole role,
llvm::function_ref<void(MacroDecl *macro, const MacroRoleAttr *)> body
);
} // end namespace namelookup
/// Describes an inherited nominal entry.
struct InheritedNominalEntry : Located<NominalTypeDecl *> {
/// The `TypeRepr` of the inheritance clause entry from which this nominal was
/// sourced, if any. For example, if this is a conformance to `Y` declared as
/// `struct S: X, Y & Z {}`, this is the `TypeRepr` for `Y & Z`.
TypeRepr *inheritedTypeRepr;
ConformanceAttributes attributes;
/// Whether this inherited entry was suppressed via "~".
bool isSuppressed;
InheritedNominalEntry() { }
InheritedNominalEntry(NominalTypeDecl *item, SourceLoc loc,
TypeRepr *inheritedTypeRepr,
ConformanceAttributes attributes, bool isSuppressed)
: Located(item, loc), inheritedTypeRepr(inheritedTypeRepr),
attributes(attributes), isSuppressed(isSuppressed) {}
};
/// Retrieve the set of nominal type declarations that are directly
/// "inherited" by the given declaration at a particular position in the
/// list of "inherited" types.
///
/// Add anything we find to the \c result vector. If we come across the
/// AnyObject type, set \c anyObject true.
void getDirectlyInheritedNominalTypeDecls(
llvm::PointerUnion<const TypeDecl *, const ExtensionDecl *> decl,
unsigned i, llvm::SmallVectorImpl<InheritedNominalEntry> &result,
InvertibleProtocolSet &inverses, bool &anyObject);
/// Retrieve the set of nominal type declarations that are directly
/// "inherited" by the given declaration, looking through typealiases
/// and splitting out the components of compositions.
///
/// If we come across the AnyObject type, set \c anyObject true.
SmallVector<InheritedNominalEntry, 4> getDirectlyInheritedNominalTypeDecls(
llvm::PointerUnion<const TypeDecl *, const ExtensionDecl *> decl,
InvertibleProtocolSet &inverses, bool &anyObject);
/// Retrieve the set of nominal type declarations that appear as the
/// constraint type of any "Self" constraints in the where clause of the
/// given protocol or protocol extension.
SelfBounds getSelfBoundsFromWhereClause(
llvm::PointerUnion<const TypeDecl *, const ExtensionDecl *> decl);
/// Retrieve the set of nominal type declarations that appear as the
/// constraint type of any "Self" constraints in the generic signature of the
/// given protocol or protocol extension.
SelfBounds getSelfBoundsFromGenericSignature(const ExtensionDecl *extDecl);
/// Determine whether the given declaration is visible to name lookup when
/// found from the given module scope context.
///
/// Note that this routine does not check ASTContext::isAccessControlDisabled();
/// that's left for the caller.
bool declIsVisibleToNameLookup(
const ValueDecl *decl, const DeclContext *moduleScopeContext,
NLOptions options);
namespace namelookup {
/// The bridge between the legacy UnqualifiedLookupFactory and the new ASTScope
/// lookup system
class AbstractASTScopeDeclConsumer {
public:
AbstractASTScopeDeclConsumer() {}
virtual ~AbstractASTScopeDeclConsumer() = default;
/// Called for every ValueDecl visible from the lookup.
///
/// Takes an array in order to batch the consumption before setting
/// IndexOfFirstOuterResult when necessary.
///
/// \param baseDC either a type context or the local context of a
/// `self` parameter declaration. See LookupResult for a discussion
/// of type -vs- instance lookup results.
///
/// \return true if the lookup should be stopped at this point.
virtual bool consume(ArrayRef<ValueDecl *> values,
NullablePtr<DeclContext> baseDC = nullptr) = 0;
/// Look for members of a nominal type or extension scope.
///
/// \return true if the lookup should be stopped at this point.
virtual bool lookInMembers(const DeclContext *scopeDC) const = 0;
/// Called for local VarDecls that might not yet be in scope.
///
/// Note that the set of VarDecls visited here are going to be a
/// superset of those visited in consume().
virtual bool consumePossiblyNotInScope(ArrayRef<VarDecl *> values) {
return false;
}
/// Called right before looking at the parent scope of a BraceStmt.
///
/// \return true if the lookup should be stopped at this point.
virtual bool
finishLookupInBraceStmt(BraceStmt *stmt) {
return false;
}
#ifndef NDEBUG
virtual void startingNextLookupStep() {}
virtual void finishingLookup(std::string) const {}
virtual bool isTargetLookup() const { return false; }
#endif
};
/// Just used to print
/// Used to gather lookup results
class ASTScopeDeclGatherer : public AbstractASTScopeDeclConsumer {
SmallVector<ValueDecl *, 32> values;
public:
virtual ~ASTScopeDeclGatherer() = default;
bool consume(ArrayRef<ValueDecl *> values,
NullablePtr<DeclContext> baseDC = nullptr) override;
/// Eventually this functionality should move into ASTScopeLookup
bool lookInMembers(const DeclContext *) const override {
return false;
}
#ifndef NDEBUG
void startingNextLookupStep() override {}
void finishingLookup(std::string) const override {}
bool isTargetLookup() const override { return false; }
#endif
ArrayRef<ValueDecl *> getDecls() { return values; }
};
} // end namespace namelookup
/// The interface into the ASTScope subsystem
class ASTScope : public ASTAllocated<ASTScope> {
friend class ast_scope::ASTScopeImpl;
ast_scope::ASTSourceFileScope *const impl;
public:
ASTScope(SourceFile *);
void
buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals();
static void expandFunctionBody(AbstractFunctionDecl *);
/// Flesh out the tree for dumping
void buildFullyExpandedTree();
static void unqualifiedLookup(SourceFile *, SourceLoc,
namelookup::AbstractASTScopeDeclConsumer &);
/// Lookup that only finds local declarations and does not trigger
/// interface type computation.
///
/// \param stopAfterInnermostBraceStmt If lookup should consider
/// local declarations inside the innermost syntactic scope only.
static void lookupLocalDecls(SourceFile *, DeclNameRef, SourceLoc,
bool stopAfterInnermostBraceStmt,
ABIRole roleFilter,
SmallVectorImpl<ValueDecl *> &);
static void lookupLocalDecls(SourceFile *sf, DeclNameRef name, SourceLoc loc,
bool stopAfterInnermostBraceStmt,
SmallVectorImpl<ValueDecl *> &results) {
lookupLocalDecls(sf, name, loc, stopAfterInnermostBraceStmt,
ABIRole::ProvidesAPI, results);
}
/// Returns the result if there is exactly one, nullptr otherwise.
static ValueDecl *lookupSingleLocalDecl(SourceFile *, DeclNameRef, SourceLoc);
/// Entry point to record the visible statement labels from the given
/// point.
///
/// This lookup only considers labels that are visible within the current
/// function, so it will not return any labels from lexical scopes that
/// are not reachable via labeled control flow.
///
/// \returns the set of labeled statements visible from the given source
/// location, with the innermost labeled statement first and proceeding
/// to the outermost labeled statement.
static llvm::SmallVector<LabeledStmt *, 4>
lookupLabeledStmts(SourceFile *sourceFile, SourceLoc loc);
/// Look for the directly enclosing case statement and the next case
/// statement, which together act as the source and destination for a
/// 'fallthrough' statement within a switch case.
///
/// \returns a pair (fallthrough source, fallthrough dest). If the location
/// is not within the body of a case statement at all, the fallthrough
/// source will be \c nullptr. If there is a fallthrough source that case is
/// the last one, the fallthrough destination will be \c nullptr. A
/// well-formed 'fallthrough' statement has both a source and destination.
static std::pair<CaseStmt *, CaseStmt *>
lookupFallthroughSourceAndDest(SourceFile *sourceFile, SourceLoc loc);
using PotentialMacro =
llvm::PointerUnion<FreestandingMacroExpansion *, CustomAttr *>;
/// Look up the scope tree for the nearest enclosing macro scope at
/// the given source location.
///
/// \param sourceFile The source file containing the given location.
/// \param loc The source location to start lookup from.
/// \param consume A function that is called when a potential macro
/// scope is found. If \c consume returns \c true, lookup
/// will stop. If \c consume returns \c false, lookup will
/// continue up the scope tree.
static void lookupEnclosingMacroScope(
SourceFile *sourceFile, SourceLoc loc,
llvm::function_ref<bool(PotentialMacro macro)> consume);
/// Look up the scope tree for the nearest enclosing ABI attribute at
/// the given source location.
///
/// \param sourceFile The source file containing the given location.
/// \param loc The source location to start lookup from.
/// \param consume A function that is called when an ABI attribute
/// scope is found. If \c consume returns \c true, lookup
/// will stop. If \c consume returns \c false, lookup will
/// continue up the scope tree.
static ABIAttr *lookupEnclosingABIAttributeScope(
SourceFile *sourceFile, SourceLoc loc);
/// Look up the scope tree for the nearest point at which an error thrown from
/// this location can be caught or rethrown.
///
/// For example, given this code:
///
/// \code
/// func f() throws {
/// do {
/// try g() // A
/// } catch {
/// throw ErrorWrapper(error) // B
/// }
/// }
/// \endcode
///
/// At the point marked A, the catch node is the enclosing do...catch
/// statement. At the point marked B, the catch node is the function itself.
static CatchNode lookupCatchNode(ModuleDecl *module, SourceLoc loc);
SWIFT_DEBUG_DUMP;
void print(llvm::raw_ostream &) const;
void dumpOneScopeMapLocation(std::pair<unsigned, unsigned>);
private:
static ast_scope::ASTSourceFileScope *createScopeTree(SourceFile *);
void expandFunctionBodyImpl(AbstractFunctionDecl *);
};
} // end namespace swift
#endif