//===--- LookupVisibleDecls - Swift Name Lookup Routines ------------------===// // // 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 implements the lookupVisibleDecls interface for visiting named // declarations. // //===----------------------------------------------------------------------===// #include "NameLookupImpl.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Initializer.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/SubstitutionMap.h" #include "swift/Basic/SourceManager.h" #include "swift/Basic/STLExtras.h" #include "swift/Sema/IDETypeChecking.h" #include "llvm/ADT/SetVector.h" #include using namespace swift; void VisibleDeclConsumer::anchor() {} void VectorDeclConsumer::anchor() {} void NamedDeclConsumer::anchor() {} namespace { struct LookupState { private: /// If \c false, an unqualified lookup of all visible decls in a /// DeclContext. /// /// If \c true, lookup of all visible members of a given object (possibly of /// metatype type). unsigned IsQualified : 1; /// Is this a qualified lookup on a metatype? unsigned IsOnMetatype : 1; /// Did we recurse into a superclass? unsigned IsOnSuperclass : 1; unsigned InheritsSuperclassInitializers : 1; /// Should instance members be included even if lookup is performed on a type? unsigned IncludeInstanceMembers : 1; LookupState() : IsQualified(0), IsOnMetatype(0), IsOnSuperclass(0), InheritsSuperclassInitializers(0), IncludeInstanceMembers(0) {} public: LookupState(const LookupState &) = default; static LookupState makeQualified() { LookupState Result; Result.IsQualified = 1; return Result; } static LookupState makeUnqualified() { LookupState Result; Result.IsQualified = 0; return Result; } bool isQualified() const { return IsQualified; } bool isOnMetatype() const { return IsOnMetatype; } bool isOnSuperclass() const { return IsOnSuperclass; } bool isInheritsSuperclassInitializers() const { return InheritsSuperclassInitializers; } bool isIncludingInstanceMembers() const { return IncludeInstanceMembers; } LookupState withOnMetatype() const { auto Result = *this; Result.IsOnMetatype = 1; return Result; } LookupState withOnSuperclass() const { auto Result = *this; Result.IsOnSuperclass = 1; return Result; } LookupState withInheritsSuperclassInitializers() const { auto Result = *this; Result.InheritsSuperclassInitializers = 1; return Result; } LookupState withoutInheritsSuperclassInitializers() const { auto Result = *this; Result.InheritsSuperclassInitializers = 0; return Result; } LookupState withIncludedInstanceMembers() const { auto Result = *this; Result.IncludeInstanceMembers = 1; return Result; } }; } // unnamed namespace static bool areTypeDeclsVisibleInLookupMode(LookupState LS) { // Nested type declarations can be accessed only with unqualified lookup or // on metatypes. return !LS.isQualified() || LS.isOnMetatype(); } static bool isDeclVisibleInLookupMode(ValueDecl *Member, LookupState LS, const DeclContext *FromContext, LazyResolver *TypeResolver) { if (TypeResolver) { TypeResolver->resolveDeclSignature(Member); TypeResolver->resolveAccessibility(Member); } // Check accessibility when relevant. if (!Member->getDeclContext()->isLocalContext() && !isa(Member) && !isa(Member) && FromContext->getASTContext().LangOpts.EnableAccessControl) { if (Member->isInvalid() && !Member->hasAccessibility()) return false; if (!Member->isAccessibleFrom(FromContext)) return false; } if (auto *FD = dyn_cast(Member)) { // Cannot call static functions on non-metatypes. if (!LS.isOnMetatype() && FD->isStatic()) return false; // Otherwise, either call a function or curry it. return true; } if (auto *VD = dyn_cast(Member)) { // Cannot use static properties on non-metatypes. if (!(LS.isQualified() && LS.isOnMetatype()) && VD->isStatic()) return false; // Cannot use instance properties on metatypes. if (LS.isOnMetatype() && !VD->isStatic() && !LS.isIncludingInstanceMembers()) return false; return true; } if (isa(Member)) { // Cannot reference enum elements on non-metatypes. if (!(LS.isQualified() && LS.isOnMetatype())) return false; } if (auto CD = dyn_cast(Member)) { // Constructors with stub implementations cannot be called in Swift. if (CD->hasStubImplementation()) return false; if (LS.isQualified() && LS.isOnSuperclass()) { // Cannot call initializers from a superclass, except for inherited // convenience initializers. return LS.isInheritsSuperclassInitializers() && CD->isInheritable(); } } if (isa(Member)) return areTypeDeclsVisibleInLookupMode(LS); return true; } /// Lookup members in extensions of \p LookupType, using \p BaseType as the /// underlying type when checking any constraints on the extensions. static void doGlobalExtensionLookup(Type BaseType, Type LookupType, SmallVectorImpl &FoundDecls, const DeclContext *CurrDC, LookupState LS, DeclVisibilityKind Reason, LazyResolver *TypeResolver) { auto nominal = LookupType->getAnyNominal(); // Look in each extension of this type. for (auto extension : nominal->getExtensions()) { if (!isExtensionApplied(*const_cast(CurrDC), BaseType, extension)) continue; bool validatedExtension = false; if (TypeResolver && extension->getAsProtocolExtensionContext()) { if (!TypeResolver->isProtocolExtensionUsable( const_cast(CurrDC), BaseType, extension)) { continue; } validatedExtension = true; } for (auto Member : extension->getMembers()) { if (auto VD = dyn_cast(Member)) if (isDeclVisibleInLookupMode(VD, LS, CurrDC, TypeResolver)) { // Resolve the extension, if we haven't done so already. if (!validatedExtension && TypeResolver) { TypeResolver->resolveExtension(extension); validatedExtension = true; } FoundDecls.push_back(VD); } } } // Handle shadowing. removeShadowedDecls(FoundDecls, CurrDC->getParentModule(), TypeResolver); } /// \brief Enumerate immediate members of the type \c LookupType and its /// extensions, as seen from the context \c CurrDC. /// /// Don't do lookup into superclasses or implemented protocols. Uses /// \p BaseType as the underlying type when checking any constraints on the /// extensions. static void lookupTypeMembers(Type BaseType, Type LookupType, VisibleDeclConsumer &Consumer, const DeclContext *CurrDC, LookupState LS, DeclVisibilityKind Reason, LazyResolver *TypeResolver) { NominalTypeDecl *D = LookupType->getAnyNominal(); assert(D && "should have a nominal type"); bool LookupFromChildDeclContext = false; const DeclContext *TempDC = CurrDC; while (!TempDC->isModuleContext()) { if (TempDC == D) { LookupFromChildDeclContext = true; break; } TempDC = TempDC->getParent(); } SmallVector FoundDecls; if (LookupFromChildDeclContext) { // Current decl context is contained inside 'D', so generic parameters // are visible. if (D->getGenericParams()) for (auto Param : *D->getGenericParams()) if (isDeclVisibleInLookupMode(Param, LS, CurrDC, TypeResolver)) FoundDecls.push_back(Param); } for (Decl *Member : D->getMembers()) { if (auto *VD = dyn_cast(Member)) if (isDeclVisibleInLookupMode(VD, LS, CurrDC, TypeResolver)) FoundDecls.push_back(VD); } doGlobalExtensionLookup(BaseType, LookupType, FoundDecls, CurrDC, LS, Reason, TypeResolver); // Report the declarations we found to the consumer. for (auto *VD : FoundDecls) Consumer.foundDecl(VD, Reason); } /// Enumerate AnyObject declarations as seen from context \c CurrDC. static void doDynamicLookup(VisibleDeclConsumer &Consumer, const DeclContext *CurrDC, LookupState LS, LazyResolver *TypeResolver) { class DynamicLookupConsumer : public VisibleDeclConsumer { VisibleDeclConsumer &ChainedConsumer; LookupState LS; const DeclContext *CurrDC; LazyResolver *TypeResolver; llvm::DenseSet> FunctionsReported; llvm::DenseSet SubscriptsReported; llvm::DenseSet> PropertiesReported; public: explicit DynamicLookupConsumer(VisibleDeclConsumer &ChainedConsumer, LookupState LS, const DeclContext *CurrDC, LazyResolver *TypeResolver) : ChainedConsumer(ChainedConsumer), LS(LS), CurrDC(CurrDC), TypeResolver(TypeResolver) {} void foundDecl(ValueDecl *D, DeclVisibilityKind Reason) override { // If the declaration has an override, name lookup will also have found // the overridden method. Skip this declaration, because we prefer the // overridden method. if (D->getOverriddenDecl()) return; // Ensure that the declaration has a type. if (!D->hasInterfaceType()) { if (!TypeResolver) return; TypeResolver->resolveDeclSignature(D); if (!D->hasInterfaceType()) return; } switch (D->getKind()) { #define DECL(ID, SUPER) \ case DeclKind::ID: #define VALUE_DECL(ID, SUPER) #include "swift/AST/DeclNodes.def" llvm_unreachable("not a ValueDecl!"); // Types cannot be found by dynamic lookup. case DeclKind::GenericTypeParam: case DeclKind::AssociatedType: case DeclKind::TypeAlias: case DeclKind::Enum: case DeclKind::Class: case DeclKind::Struct: case DeclKind::Protocol: return; // Initializers cannot be found by dynamic lookup. case DeclKind::Constructor: case DeclKind::Destructor: return; // These cases are probably impossible here but can also just // be safely ignored. case DeclKind::EnumElement: case DeclKind::Param: case DeclKind::Module: return; // For other kinds of values, check if we already reported a decl // with the same signature. case DeclKind::Func: { auto FD = cast(D); assert(FD->getImplicitSelfDecl() && "should not find free functions"); (void)FD; if (FD->isInvalid()) break; // Get the type without the first uncurry level with 'self'. CanType T = D->getInterfaceType() ->castTo() ->getResult() ->getCanonicalType(); auto Signature = std::make_pair(D->getName(), T); if (!FunctionsReported.insert(Signature).second) return; break; } case DeclKind::Subscript: { auto Signature = D->getInterfaceType()->getCanonicalType(); if (!SubscriptsReported.insert(Signature).second) return; break; } case DeclKind::Var: { auto *VD = cast(D); auto Signature = std::make_pair(VD->getName(), VD->getInterfaceType()->getCanonicalType()); if (!PropertiesReported.insert(Signature).second) return; break; } } if (isDeclVisibleInLookupMode(D, LS, CurrDC, TypeResolver)) ChainedConsumer.foundDecl(D, DeclVisibilityKind::DynamicLookup); } }; DynamicLookupConsumer ConsumerWrapper(Consumer, LS, CurrDC, TypeResolver); CurrDC->getParentSourceFile()->forAllVisibleModules( [&](ModuleDecl::ImportedModule Import) { Import.second->lookupClassMembers(Import.first, ConsumerWrapper); }); } namespace { typedef llvm::SmallPtrSet VisitedSet; } // end anonymous namespace static DeclVisibilityKind getReasonForSuper(DeclVisibilityKind Reason) { switch (Reason) { case DeclVisibilityKind::MemberOfCurrentNominal: case DeclVisibilityKind::MemberOfProtocolImplementedByCurrentNominal: case DeclVisibilityKind::MemberOfSuper: return DeclVisibilityKind::MemberOfSuper; case DeclVisibilityKind::MemberOfOutsideNominal: return DeclVisibilityKind::MemberOfOutsideNominal; default: llvm_unreachable("should not see this kind"); } } static void lookupDeclsFromProtocolsBeingConformedTo( Type BaseTy, VisibleDeclConsumer &Consumer, LookupState LS, const DeclContext *FromContext, DeclVisibilityKind Reason, LazyResolver *TypeResolver, VisitedSet &Visited) { NominalTypeDecl *CurrNominal = BaseTy->getAnyNominal(); if (!CurrNominal) return; for (auto Conformance : CurrNominal->getAllConformances()) { auto Proto = Conformance->getProtocol(); if (!Proto->isAccessibleFrom(FromContext)) continue; DeclVisibilityKind ReasonForThisProtocol; if (Reason == DeclVisibilityKind::MemberOfCurrentNominal) ReasonForThisProtocol = DeclVisibilityKind::MemberOfProtocolImplementedByCurrentNominal; else ReasonForThisProtocol = getReasonForSuper(Reason); auto NormalConformance = Conformance->getRootNormalConformance(); for (auto Member : Proto->getMembers()) { if (auto *ATD = dyn_cast(Member)) { // Skip type decls if they aren't visible, or any type that has a // witness. This cuts down on duplicates. if (areTypeDeclsVisibleInLookupMode(LS) && !NormalConformance->hasTypeWitness(ATD)) { Consumer.foundDecl(ATD, ReasonForThisProtocol); } continue; } if (auto *VD = dyn_cast(Member)) { if (TypeResolver) TypeResolver->resolveDeclSignature(VD); // Skip value requirements that have corresponding witnesses. This cuts // down on duplicates. if (!NormalConformance->hasWitness(VD) || !NormalConformance->getWitness(VD, nullptr) || NormalConformance->getWitness(VD, nullptr).getDecl()->getFullName() != VD->getFullName()) { Consumer.foundDecl(VD, ReasonForThisProtocol); } } } // Add members from any extensions. SmallVector FoundDecls; doGlobalExtensionLookup(BaseTy, Proto->getDeclaredType(), FoundDecls, FromContext, LS, ReasonForThisProtocol, TypeResolver); for (auto *VD : FoundDecls) Consumer.foundDecl(VD, ReasonForThisProtocol); } } static void lookupVisibleMemberDeclsImpl(Type BaseTy, VisibleDeclConsumer &Consumer, const DeclContext *CurrDC, LookupState LS, DeclVisibilityKind Reason, LazyResolver *TypeResolver, VisitedSet &Visited); static void lookupVisibleProtocolMemberDecls( Type BaseTy, ProtocolType *PT, VisibleDeclConsumer &Consumer, const DeclContext *CurrDC, LookupState LS, DeclVisibilityKind Reason, LazyResolver *TypeResolver, VisitedSet &Visited) { if (PT->getDecl()->isSpecificProtocol(KnownProtocolKind::AnyObject)) { // Handle AnyObject in a special way. doDynamicLookup(Consumer, CurrDC, LS, TypeResolver); return; } if (!Visited.insert(PT->getDecl()).second) return; for (auto Proto : PT->getDecl()->getInheritedProtocols()) lookupVisibleProtocolMemberDecls(BaseTy, Proto->getDeclaredType(), Consumer, CurrDC, LS, getReasonForSuper(Reason), TypeResolver, Visited); lookupTypeMembers(BaseTy, PT, Consumer, CurrDC, LS, Reason, TypeResolver); } static void lookupVisibleMemberDeclsImpl( Type BaseTy, VisibleDeclConsumer &Consumer, const DeclContext *CurrDC, LookupState LS, DeclVisibilityKind Reason, LazyResolver *TypeResolver, VisitedSet &Visited) { // Just look through l-valueness. It doesn't affect name lookup. assert(BaseTy && "lookup into null type"); assert(!BaseTy->isLValueType()); // Handle metatype references, as in "some_type.some_member". These are // special and can't have extensions. if (auto MTT = BaseTy->getAs()) { // The metatype represents an arbitrary named type: dig through to the // declared type to see what we're dealing with. Type Ty = MTT->getInstanceType(); LookupState subLS = LookupState::makeQualified().withOnMetatype(); if (LS.isIncludingInstanceMembers()) { subLS = subLS.withIncludedInstanceMembers(); } // Just perform normal dot lookup on the type see if we find extensions or // anything else. For example, type SomeTy.SomeMember can look up static // functions, and can even look up non-static functions as well (thus // getting the address of the member). lookupVisibleMemberDeclsImpl(Ty, Consumer, CurrDC, subLS, Reason, TypeResolver, Visited); return; } // Lookup module references, as on some_module.some_member. These are // special and can't have extensions. if (ModuleType *MT = BaseTy->getAs()) { AccessFilteringDeclConsumer FilteringConsumer(CurrDC, Consumer, TypeResolver); MT->getModule()->lookupVisibleDecls(ModuleDecl::AccessPathTy(), FilteringConsumer, NLKind::QualifiedLookup); return; } // If the base is a protocol, enumerate its members. if (ProtocolType *PT = BaseTy->getAs()) { lookupVisibleProtocolMemberDecls(BaseTy, PT, Consumer, CurrDC, LS, Reason, TypeResolver, Visited); return; } // If the base is a protocol composition, enumerate members of the protocols. if (auto PC = BaseTy->getAs()) { for (auto Member : PC->getMembers()) lookupVisibleMemberDeclsImpl(Member, Consumer, CurrDC, LS, Reason, TypeResolver, Visited); return; } // Enumerate members of archetype's requirements. if (ArchetypeType *Archetype = BaseTy->getAs()) { for (auto Proto : Archetype->getConformsTo()) lookupVisibleProtocolMemberDecls( BaseTy, Proto->getDeclaredType(), Consumer, CurrDC, LS, getReasonForSuper(Reason), TypeResolver, Visited); if (auto superclass = Archetype->getSuperclass()) lookupVisibleMemberDeclsImpl(superclass, Consumer, CurrDC, LS, getReasonForSuper(Reason), TypeResolver, Visited); return; } do { NominalTypeDecl *CurNominal = BaseTy->getAnyNominal(); if (!CurNominal) break; // Look in for members of a nominal type. lookupTypeMembers(BaseTy, BaseTy, Consumer, CurrDC, LS, Reason, TypeResolver); lookupDeclsFromProtocolsBeingConformedTo(BaseTy, Consumer, LS, CurrDC, Reason, TypeResolver, Visited); // If we have a class type, look into its superclass. ClassDecl *CurClass = dyn_cast(CurNominal); if (CurClass && CurClass->hasSuperclass()) { assert(BaseTy.getPointer() != CurClass->getSuperclass().getPointer() && "type is its own superclass"); BaseTy = CurClass->getSuperclass(); Reason = getReasonForSuper(Reason); bool InheritsSuperclassInitializers = CurClass->inheritsSuperclassInitializers(TypeResolver); if (LS.isOnSuperclass() && !InheritsSuperclassInitializers) LS = LS.withoutInheritsSuperclassInitializers(); else if (!LS.isOnSuperclass()) { LS = LS.withOnSuperclass(); if (InheritsSuperclassInitializers) LS = LS.withInheritsSuperclassInitializers(); } } else { break; } } while (1); } namespace { struct FoundDeclTy { ValueDecl *D; DeclVisibilityKind Reason; FoundDeclTy(ValueDecl *D, DeclVisibilityKind Reason) : D(D), Reason(Reason) {} friend bool operator==(const FoundDeclTy &LHS, const FoundDeclTy &RHS) { // If this ever changes - e.g. to include Reason - be sure to also update // DenseMapInfo::getHashValue(). return LHS.D == RHS.D; } }; } // end anonymous namespace namespace llvm { template <> struct DenseMapInfo { static inline FoundDeclTy getEmptyKey() { return FoundDeclTy{nullptr, DeclVisibilityKind::LocalVariable}; } static inline FoundDeclTy getTombstoneKey() { return FoundDeclTy{reinterpret_cast(0x1), DeclVisibilityKind::LocalVariable}; } static unsigned getHashValue(const FoundDeclTy &Val) { // Note: FoundDeclTy::operator== only considers D, so don't hash Reason here. return llvm::hash_value(Val.D); } static bool isEqual(const FoundDeclTy &LHS, const FoundDeclTy &RHS) { return LHS == RHS; } }; } // namespace llvm namespace { /// Similar to swift::conflicting, but lenient about protocol extensions which /// don't affect code completion's concept of overloading. static bool relaxedConflicting(const OverloadSignature &sig1, const OverloadSignature &sig2) { // If the base names are different, they can't conflict. if (sig1.Name.getBaseName() != sig2.Name.getBaseName()) return false; // If one is a compound name and the other is not, they do not conflict // if one is a property and the other is a non-nullary function. if (sig1.Name.isCompoundName() != sig2.Name.isCompoundName()) { return !((sig1.IsProperty && sig2.Name.getArgumentNames().size() > 0) || (sig2.IsProperty && sig1.Name.getArgumentNames().size() > 0)); } // Allow null property types to match non-null ones, which only happens when // one property is from a generic extension and the other is not. if (sig1.InterfaceType != sig2.InterfaceType) { if (!sig1.IsProperty || !sig2.IsProperty) return false; if (sig1.InterfaceType && sig2.InterfaceType) return false; } return sig1.Name == sig2.Name && sig1.UnaryOperator == sig2.UnaryOperator && sig1.IsInstanceMember == sig2.IsInstanceMember; } /// Hack to guess at whether substituting into the type of a declaration will /// be okay. /// FIXME: This is awful. We should either have Type::subst() work for /// GenericFunctionType, or we should kill it outright. static bool shouldSubstIntoDeclType(Type type) { auto genericFnType = type->getAs(); if (!genericFnType) return true; return false; } class OverrideFilteringConsumer : public VisibleDeclConsumer { public: std::set AllFoundDecls; std::map> FoundDecls; llvm::SetVector DeclsToReport; Type BaseTy; const DeclContext *DC; LazyResolver *TypeResolver; OverrideFilteringConsumer(Type BaseTy, const DeclContext *DC, LazyResolver *resolver) : BaseTy(BaseTy), DC(DC), TypeResolver(resolver) { assert(!BaseTy->isLValueType()); if (auto *MetaTy = BaseTy->getAs()) BaseTy = MetaTy->getInstanceType(); assert(DC && BaseTy); } void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) override { if (!AllFoundDecls.insert(VD).second) return; // If this kind of declaration doesn't participate in overriding, there's // no filtering to do here. if (!isa(VD) && !isa(VD)) { DeclsToReport.insert(FoundDeclTy(VD, Reason)); return; } if (TypeResolver) { TypeResolver->resolveDeclSignature(VD); TypeResolver->resolveAccessibility(VD); } if (VD->isInvalid()) { FoundDecls[VD->getName()].insert(VD); DeclsToReport.insert(FoundDeclTy(VD, Reason)); return; } auto &PossiblyConflicting = FoundDecls[VD->getName()]; // Check all overridden decls. { auto *CurrentVD = VD->getOverriddenDecl(); while (CurrentVD) { if (!AllFoundDecls.insert(CurrentVD).second) break; if (PossiblyConflicting.count(CurrentVD)) { PossiblyConflicting.erase(CurrentVD); PossiblyConflicting.insert(VD); bool Erased = DeclsToReport.remove( FoundDeclTy(CurrentVD, DeclVisibilityKind::LocalVariable)); assert(Erased); (void)Erased; DeclsToReport.insert(FoundDeclTy(VD, Reason)); return; } CurrentVD = CurrentVD->getOverriddenDecl(); } } // Does it make sense to substitute types? // Don't pass UnboundGenericType here. If you see this assertion // being hit, fix the caller, don't remove it. assert(!BaseTy->hasUnboundGenericType()); // If the base type is AnyObject, we might be doing a dynamic // lookup, so the base type won't match the type of the member's // context type. // // If the base type is not a nominal type, we can't substitute // the member type. // // If the member is a free function and not a member of a type, // don't substitute either. bool shouldSubst = (!BaseTy->isAnyObject() && !BaseTy->hasTypeVariable() && BaseTy->getNominalOrBoundGenericNominal() && VD->getDeclContext()->isTypeContext()); ModuleDecl *M = DC->getParentModule(); auto FoundSignature = VD->getOverloadSignature(); if (FoundSignature.InterfaceType && shouldSubst && shouldSubstIntoDeclType(FoundSignature.InterfaceType)) { auto subs = BaseTy->getMemberSubstitutionMap(M, VD); if (auto CT = FoundSignature.InterfaceType.subst(subs)) FoundSignature.InterfaceType = CT->getCanonicalType(); } for (auto I = PossiblyConflicting.begin(), E = PossiblyConflicting.end(); I != E; ++I) { auto *OtherVD = *I; if (OtherVD->isInvalid()) { // For some invalid decls it might be impossible to compute the // signature, for example, if the types could not be resolved. continue; } auto OtherSignature = OtherVD->getOverloadSignature(); if (OtherSignature.InterfaceType && shouldSubst && shouldSubstIntoDeclType(OtherSignature.InterfaceType)) { auto subs = BaseTy->getMemberSubstitutionMap(M, OtherVD); if (auto CT = OtherSignature.InterfaceType.subst(subs)) OtherSignature.InterfaceType = CT->getCanonicalType(); } if (relaxedConflicting(FoundSignature, OtherSignature)) { if (VD->getFormalAccess() > OtherVD->getFormalAccess()) { PossiblyConflicting.erase(I); PossiblyConflicting.insert(VD); bool Erased = DeclsToReport.remove( FoundDeclTy(OtherVD, DeclVisibilityKind::LocalVariable)); assert(Erased); (void)Erased; DeclsToReport.insert(FoundDeclTy(VD, Reason)); } return; } } PossiblyConflicting.insert(VD); DeclsToReport.insert(FoundDeclTy(VD, Reason)); } }; } // unnamed namespace /// \brief Enumerate all members in \c BaseTy (including members of extensions, /// superclasses and implemented protocols), as seen from the context \c CurrDC. /// /// This operation corresponds to a standard "dot" lookup operation like "a.b" /// where 'self' is the type of 'a'. This operation is only valid after name /// binding. static void lookupVisibleMemberDecls( Type BaseTy, VisibleDeclConsumer &Consumer, const DeclContext *CurrDC, LookupState LS, DeclVisibilityKind Reason, LazyResolver *TypeResolver) { OverrideFilteringConsumer ConsumerWrapper(BaseTy, CurrDC, TypeResolver); VisitedSet Visited; lookupVisibleMemberDeclsImpl(BaseTy, ConsumerWrapper, CurrDC, LS, Reason, TypeResolver, Visited); // Report the declarations we found to the real consumer. for (const auto &DeclAndReason : ConsumerWrapper.DeclsToReport) Consumer.foundDecl(DeclAndReason.D, DeclAndReason.Reason); } void swift::lookupVisibleDecls(VisibleDeclConsumer &Consumer, const DeclContext *DC, LazyResolver *TypeResolver, bool IncludeTopLevel, SourceLoc Loc) { const ModuleDecl &M = *DC->getParentModule(); const SourceManager &SM = DC->getASTContext().SourceMgr; auto Reason = DeclVisibilityKind::MemberOfCurrentNominal; // If we are inside of a method, check to see if there are any ivars in scope, // and if so, whether this is a reference to one of them. while (!DC->isModuleScopeContext()) { const ValueDecl *BaseDecl = nullptr; GenericParamList *GenericParams = nullptr; Type ExtendedType; auto LS = LookupState::makeUnqualified(); // Skip initializer contexts, we will not find any declarations there. if (isa(DC)) { DC = DC->getParent(); LS = LS.withOnMetatype(); } if (auto *AFD = dyn_cast(DC)) { // Look for local variables; normally, the parser resolves these // for us, but it can't do the right thing inside local types. // FIXME: when we can parse and typecheck the function body partially for // code completion, AFD->getBody() check can be removed. if (Loc.isValid() && AFD->getBody()) { namelookup::FindLocalVal(SM, Loc, Consumer).visit(AFD->getBody()); } for (auto *P : AFD->getParameterLists()) namelookup::FindLocalVal(SM, Loc, Consumer).checkParameterList(P); // Constructors and destructors don't have 'self' in parameter patterns. if (isa(AFD) || isa(AFD)) if (auto *selfParam = AFD->getImplicitSelfDecl()) Consumer.foundDecl(const_cast(selfParam), DeclVisibilityKind::FunctionParameter); if (AFD->getDeclContext()->isTypeContext()) { ExtendedType = AFD->getDeclContext()->getSelfTypeInContext(); BaseDecl = AFD->getImplicitSelfDecl(); DC = DC->getParent(); if (auto *FD = dyn_cast(AFD)) if (FD->isStatic()) ExtendedType = MetatypeType::get(ExtendedType); } // Look in the generic parameters after checking our local declaration. GenericParams = AFD->getGenericParams(); } else if (auto CE = dyn_cast(DC)) { if (Loc.isValid()) { namelookup::FindLocalVal(SM, Loc, Consumer).visit(CE->getBody()); if (auto P = CE->getParameters()) { namelookup::FindLocalVal(SM, Loc, Consumer).checkParameterList(P); } } } else if (auto ED = dyn_cast(DC)) { ExtendedType = ED->getExtendedType(); if (ExtendedType) BaseDecl = ExtendedType->getNominalOrBoundGenericNominal(); } else if (auto ND = dyn_cast(DC)) { ExtendedType = ND->getDeclaredTypeInContext(); BaseDecl = ND; } if (BaseDecl && ExtendedType) { ::lookupVisibleMemberDecls(ExtendedType, Consumer, DC, LS, Reason, TypeResolver); } // Check any generic parameters for something with the given name. namelookup::FindLocalVal(SM, Loc, Consumer) .checkGenericParams(GenericParams); DC = DC->getParent(); Reason = DeclVisibilityKind::MemberOfOutsideNominal; } SmallVector extraImports; if (auto SF = dyn_cast(DC)) { if (Loc.isValid()) { // Look for local variables in top-level code; normally, the parser // resolves these for us, but it can't do the right thing for // local types. namelookup::FindLocalVal(SM, Loc, Consumer).checkSourceFile(*SF); } if (IncludeTopLevel) { auto &cached = SF->getCachedVisibleDecls(); if (!cached.empty()) { for (auto result : cached) Consumer.foundDecl(result, DeclVisibilityKind::VisibleAtTopLevel); return; } SF->getImportedModules(extraImports, ModuleDecl::ImportFilter::Private); } } if (IncludeTopLevel) { using namespace namelookup; SmallVector moduleResults; auto &mutableM = const_cast(M); lookupVisibleDeclsInModule(&mutableM, {}, moduleResults, NLKind::UnqualifiedLookup, ResolutionKind::Overloadable, TypeResolver, DC, extraImports); for (auto result : moduleResults) Consumer.foundDecl(result, DeclVisibilityKind::VisibleAtTopLevel); if (auto SF = dyn_cast(DC)) SF->cacheVisibleDecls(std::move(moduleResults)); } } void swift::lookupVisibleMemberDecls(VisibleDeclConsumer &Consumer, Type BaseTy, const DeclContext *CurrDC, LazyResolver *TypeResolver, bool includeInstanceMembers) { assert(CurrDC); LookupState ls = LookupState::makeQualified(); if (includeInstanceMembers) { ls = ls.withIncludedInstanceMembers(); } ::lookupVisibleMemberDecls(BaseTy, Consumer, CurrDC, ls, DeclVisibilityKind::MemberOfCurrentNominal, TypeResolver); }