static unsigned getCallEditDistance(DeclName writtenName, DeclName correctedName, unsigned maxEditDistance) { // TODO: consider arguments. // TODO: maybe ignore certain kinds of missing / present labels for the // first argument label? // TODO: word-based rather than character-based? if (writtenName.getBaseName().getKind() != correctedName.getBaseName().getKind()) { return UnreasonableCallEditDistance; } if (writtenName.getBaseName().getKind() != DeclBaseName::Kind::Normal) { return 0; } StringRef writtenBase = writtenName.getBaseName().userFacingName(); StringRef correctedBase = correctedName.getBaseName().userFacingName(); unsigned distance = writtenBase.edit_distance(correctedBase, maxEditDistance); // Bound the distance to UnreasonableCallEditDistance. if (distance >= maxEditDistance || distance > (correctedBase.size() + 2) / 3) { return UnreasonableCallEditDistance; } return distance; }
static void addParameters(const SubscriptDecl *D, TextEntity &Ent, SourceManager &SM, unsigned BufferID) { ArrayRef<Identifier> ArgNames; DeclName Name = D->getFullName(); if (Name) { ArgNames = Name.getArgumentNames(); } addParameters(ArgNames, D->getIndices(), Ent, SM, BufferID); }
void TypeChecker::noteTypoCorrection(DeclName writtenName, DeclNameLoc loc, const LookupResult::Result &suggestion) { auto decl = suggestion.Decl; auto &&diagnostic = diagnoseTypoCorrection(*this, loc, decl); DeclName declName = decl->getFullName(); if (writtenName.getBaseName() != declName.getBaseName()) diagnostic.fixItReplace(loc.getBaseNameLoc(), declName.getBaseName().str()); // TODO: add fix-its for typo'ed argument labels. This is trickier // because of the reordering rules. }
void ModuleFile::lookupClassMember(Module::AccessPathTy accessPath, DeclName name, SmallVectorImpl<ValueDecl*> &results) { PrettyModuleFileDeserialization stackEntry(*this); assert(accessPath.size() <= 1 && "can only refer to top-level decls"); if (!ClassMembersByName) return; auto iter = ClassMembersByName->find(name.getBaseName()); if (iter == ClassMembersByName->end()) return; if (!accessPath.empty()) { // As a hack to avoid completely redoing how the module is indexed, we take // the simple-name-based lookup then filter by the compound name if we have // one. if (name.isSimpleName()) { for (auto item : *iter) { auto vd = cast<ValueDecl>(getDecl(item.second)); auto dc = vd->getDeclContext(); while (!dc->getParent()->isModuleScopeContext()) dc = dc->getParent(); if (auto nominal = dc->getAsNominalTypeOrNominalTypeExtensionContext()) if (nominal->getName() == accessPath.front().first) results.push_back(vd); } } else { for (auto item : *iter) { auto vd = cast<ValueDecl>(getDecl(item.second)); if (!vd->getFullName().matchesRef(name)) continue; auto dc = vd->getDeclContext(); while (!dc->getParent()->isModuleScopeContext()) dc = dc->getParent(); if (auto nominal = dc->getAsNominalTypeOrNominalTypeExtensionContext()) if (nominal->getName() == accessPath.front().first) results.push_back(vd); } } return; } for (auto item : *iter) { auto vd = cast<ValueDecl>(getDecl(item.second)); results.push_back(vd); } }
static bool isPlausibleTypo(DeclRefKind refKind, DeclName typedName, ValueDecl *candidate) { // Ignore anonymous declarations. if (!candidate->hasName()) return false; // An operator / identifier mismatch is never a plausible typo. auto fn = dyn_cast<FuncDecl>(candidate); if (typedName.isOperator() != (fn && fn->isOperator())) return false; if (!typedName.isOperator()) return true; // TODO: honor ref kind? This is trickier than it sounds because we // may not have processed attributes and types on the candidate yet. return true; }
static void addParameters(const AbstractFunctionDecl *FD, TextEntity &Ent, SourceManager &SM, unsigned BufferID) { auto params = FD->getParameterLists(); // Ignore 'self'. if (FD->getDeclContext()->isTypeContext()) params = params.slice(1); ArrayRef<Identifier> ArgNames; DeclName Name = FD->getFullName(); if (Name) { ArgNames = Name.getArgumentNames(); } for (auto paramList : params) { addParameters(ArgNames, paramList, Ent, SM, BufferID); } }
static unsigned getCallEditDistance(DeclName argName, DeclName paramName, unsigned maxEditDistance) { // TODO: consider arguments. // TODO: maybe ignore certain kinds of missing / present labels for the // first argument label? // TODO: word-based rather than character-based? StringRef argBase = argName.getBaseName().str(); StringRef paramBase = paramName.getBaseName().str(); unsigned distance = argBase.edit_distance(paramBase, maxEditDistance); // Bound the distance to UnreasonableCallEditDistance. if (distance >= maxEditDistance || distance > (paramBase.size() + 2) / 3) { return UnreasonableCallEditDistance; } return distance; }
int DeclName::compare(DeclName other) const { // Compare base names. if (int result = getBaseName().compare(other.getBaseName())) return result; // Compare argument names. auto argNames = getArgumentNames(); auto otherArgNames = other.getArgumentNames(); for (unsigned i = 0, n = std::min(argNames.size(), otherArgNames.size()); i != n; ++i) { if (int result = argNames[i].compare(otherArgNames[i])) return result; } if (argNames.size() == otherArgNames.size()) return 0; return argNames.size() < otherArgNames.size() ? -1 : 1; }
static void addParameters(const AbstractFunctionDecl *FD, TextEntity &Ent, SourceManager &SM, unsigned BufferID) { auto Pats = FD->getBodyParamPatterns(); // Ignore 'self'. if (FD->getDeclContext()->isTypeContext() && !Pats.empty() && isa<TypedPattern>(Pats.front())) { Pats = Pats.slice(1); } ArrayRef<Identifier> ArgNames; DeclName Name = FD->getFullName(); if (Name) { ArgNames = Name.getArgumentNames(); } for (auto Pat : Pats) { addParameters(ArgNames, Pat, Ent, SM, BufferID); } }
static void recordLookupOfTopLevelName(DeclContext *topLevelContext, DeclName name, bool isCascading) { auto SF = dyn_cast<SourceFile>(topLevelContext); if (!SF) return; auto *nameTracker = SF->getReferencedNameTracker(); if (!nameTracker) return; nameTracker->addTopLevelName(name.getBaseName(), isCascading); }
void ModuleFile::lookupValue(DeclName name, SmallVectorImpl<ValueDecl*> &results) { PrettyModuleFileDeserialization stackEntry(*this); if (TopLevelDecls) { // Find top-level declarations with the given name. // FIXME: As a bit of a hack, do lookup by the simple name, then filter // compound decls, to avoid having to completely redo how modules are // serialized. auto iter = TopLevelDecls->find(name.getBaseName()); if (iter != TopLevelDecls->end()) { if (name.isSimpleName()) { for (auto item : *iter) { auto VD = cast<ValueDecl>(getDecl(item.second)); results.push_back(VD); } } else { for (auto item : *iter) { auto VD = cast<ValueDecl>(getDecl(item.second)); if (VD->getFullName().matchesRef(name)) results.push_back(VD); } } } } // If the name is an operator name, also look for operator methods. if (name.isOperator() && OperatorMethodDecls) { auto iter = OperatorMethodDecls->find(name.getBaseName()); if (iter != OperatorMethodDecls->end()) { for (auto item : *iter) { auto VD = cast<ValueDecl>(getDecl(item.second)); results.push_back(VD); } } } }
void SwiftLookupTable::addEntry(DeclName name, SingleEntry newEntry, clang::DeclContext *effectiveContext) { assert(!Reader && "Cannot modify a lookup table stored on disk"); // Translate the context. auto contextOpt = translateContext(effectiveContext); if (!contextOpt) return; auto context = *contextOpt; // Find the list of entries for this base name. auto &entries = LookupTable[name.getBaseName().str()]; auto decl = newEntry.dyn_cast<clang::NamedDecl *>(); auto macro = newEntry.dyn_cast<clang::MacroInfo *>(); for (auto &entry : entries) { if (entry.Context == context) { // We have entries for this context. // Check whether this entry matches any existing entry. for (auto &existingEntry : entry.DeclsOrMacros) { // If it matches an existing declaration, there's nothing to do. if (decl && isDeclEntry(existingEntry) && matchesExistingDecl(decl, mapStoredDecl(existingEntry))) return; // If it matches an existing macro, overwrite the existing entry. if (macro && isMacroEntry(existingEntry)) { existingEntry = encodeEntry(macro); return; } } // Add an entry to this context. if (decl) entry.DeclsOrMacros.push_back(encodeEntry(decl)); else entry.DeclsOrMacros.push_back(encodeEntry(macro)); return; } } // This is a new context for this name. Add it. FullTableEntry entry; entry.Context = context; if (decl) entry.DeclsOrMacros.push_back(encodeEntry(decl)); else entry.DeclsOrMacros.push_back(encodeEntry(macro)); entries.push_back(entry); }
UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC, LazyResolver *TypeResolver, bool IsKnownNonCascading, SourceLoc Loc, bool IsTypeLookup, bool AllowProtocolMembers) { Module &M = *DC->getParentModule(); ASTContext &Ctx = M.getASTContext(); const SourceManager &SM = Ctx.SourceMgr; DebuggerClient *DebugClient = M.getDebugClient(); NamedDeclConsumer Consumer(Name, Results, IsTypeLookup); Optional<bool> isCascadingUse; if (IsKnownNonCascading) isCascadingUse = false; SmallVector<UnqualifiedLookupResult, 4> UnavailableInnerResults; // Never perform local lookup for operators. if (Name.isOperator()) { if (!isCascadingUse.hasValue()) { isCascadingUse = DC->isCascadingContextForLookup(/*excludeFunctions=*/true); } DC = DC->getModuleScopeContext(); } else { // 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. // FIXME: We should persist this information between lookups. while (!DC->isModuleScopeContext()) { ValueDecl *BaseDecl = 0; ValueDecl *MetaBaseDecl = 0; GenericParamList *GenericParams = nullptr; Type ExtendedType; if (auto *AFD = dyn_cast<AbstractFunctionDecl>(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()) { if (!isCascadingUse.hasValue()) { isCascadingUse = !SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc); } namelookup::FindLocalVal localVal(SM, Loc, Consumer); localVal.visit(AFD->getBody()); if (!Results.empty()) return; for (auto *PL : AFD->getParameterLists()) localVal.checkParameterList(PL); if (!Results.empty()) return; } if (!isCascadingUse.hasValue() || isCascadingUse.getValue()) isCascadingUse = AFD->isCascadingContextForLookup(false); if (AFD->getExtensionType()) { if (AFD->getDeclContext()->getAsProtocolOrProtocolExtensionContext()) { ExtendedType = AFD->getDeclContext()->getSelfTypeInContext(); // Fallback path. if (!ExtendedType) ExtendedType = AFD->getExtensionType(); } else { ExtendedType = AFD->getExtensionType(); } BaseDecl = AFD->getImplicitSelfDecl(); MetaBaseDecl = AFD->getExtensionType()->getAnyNominal(); DC = DC->getParent(); if (auto *FD = dyn_cast<FuncDecl>(AFD)) if (FD->isStatic()) ExtendedType = MetatypeType::get(ExtendedType); // If we're not in the body of the function, the base declaration // is the nominal type, not 'self'. if (Loc.isValid() && AFD->getBodySourceRange().isValid() && !SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc)) { BaseDecl = MetaBaseDecl; } } // Look in the generic parameters after checking our local declaration. GenericParams = AFD->getGenericParams(); } else if (auto *ACE = dyn_cast<AbstractClosureExpr>(DC)) { // Look for local variables; normally, the parser resolves these // for us, but it can't do the right thing inside local types. if (Loc.isValid()) { if (auto *CE = dyn_cast<ClosureExpr>(ACE)) { namelookup::FindLocalVal localVal(SM, Loc, Consumer); localVal.visit(CE->getBody()); if (!Results.empty()) return; localVal.checkParameterList(CE->getParameters()); if (!Results.empty()) return; } } if (!isCascadingUse.hasValue()) isCascadingUse = ACE->isCascadingContextForLookup(false); } else if (ExtensionDecl *ED = dyn_cast<ExtensionDecl>(DC)) { ExtendedType = ED->getSelfTypeInContext(); BaseDecl = ED->getAsNominalTypeOrNominalTypeExtensionContext(); MetaBaseDecl = BaseDecl; if (!isCascadingUse.hasValue()) isCascadingUse = ED->isCascadingContextForLookup(false); } else if (NominalTypeDecl *ND = dyn_cast<NominalTypeDecl>(DC)) { ExtendedType = ND->getDeclaredType(); BaseDecl = ND; MetaBaseDecl = BaseDecl; if (!isCascadingUse.hasValue()) isCascadingUse = ND->isCascadingContextForLookup(false); } else if (auto I = dyn_cast<DefaultArgumentInitializer>(DC)) { // In a default argument, skip immediately out of both the // initializer and the function. isCascadingUse = false; DC = I->getParent()->getParent(); continue; } else { assert(isa<TopLevelCodeDecl>(DC) || isa<Initializer>(DC)); if (!isCascadingUse.hasValue()) isCascadingUse = DC->isCascadingContextForLookup(false); } // Check the generic parameters for something with the given name. if (GenericParams) { namelookup::FindLocalVal localVal(SM, Loc, Consumer); localVal.checkGenericParams(GenericParams); if (!Results.empty()) return; } if (BaseDecl) { if (TypeResolver) TypeResolver->resolveDeclSignature(BaseDecl); NLOptions options = NL_UnqualifiedDefault; if (isCascadingUse.getValue()) options |= NL_KnownCascadingDependency; else options |= NL_KnownNonCascadingDependency; if (AllowProtocolMembers) options |= NL_ProtocolMembers; if (IsTypeLookup) options |= NL_OnlyTypes; if (!ExtendedType) ExtendedType = ErrorType::get(Ctx); SmallVector<ValueDecl *, 4> Lookup; DC->lookupQualified(ExtendedType, Name, options, TypeResolver, Lookup); bool isMetatypeType = ExtendedType->is<AnyMetatypeType>(); bool FoundAny = false; for (auto Result : Lookup) { // If we're looking into an instance, skip static functions. if (!isMetatypeType && isa<FuncDecl>(Result) && cast<FuncDecl>(Result)->isStatic()) continue; // Classify this declaration. FoundAny = true; // Types are local or metatype members. if (auto TD = dyn_cast<TypeDecl>(Result)) { if (isa<GenericTypeParamDecl>(TD)) Results.push_back(UnqualifiedLookupResult(Result)); else Results.push_back(UnqualifiedLookupResult(MetaBaseDecl, Result)); continue; } else if (auto FD = dyn_cast<FuncDecl>(Result)) { if (FD->isStatic() && !isMetatypeType) continue; } else if (isa<EnumElementDecl>(Result)) { Results.push_back(UnqualifiedLookupResult(BaseDecl, Result)); continue; } Results.push_back(UnqualifiedLookupResult(BaseDecl, Result)); } if (FoundAny) { // Predicate that determines whether a lookup result should // be unavailable except as a last-ditch effort. auto unavailableLookupResult = [&](const UnqualifiedLookupResult &result) { return result.getValueDecl()->getAttrs() .isUnavailableInCurrentSwift(); }; // If all of the results we found are unavailable, keep looking. if (std::all_of(Results.begin(), Results.end(), unavailableLookupResult)) { UnavailableInnerResults.append(Results.begin(), Results.end()); Results.clear(); FoundAny = false; } else { if (DebugClient) filterForDiscriminator(Results, DebugClient); return; } } // Check the generic parameters if our context is a generic type or // extension thereof. GenericParamList *dcGenericParams = nullptr; if (auto nominal = dyn_cast<NominalTypeDecl>(DC)) dcGenericParams = nominal->getGenericParams(); else if (auto ext = dyn_cast<ExtensionDecl>(DC)) dcGenericParams = ext->getGenericParams(); if (dcGenericParams) { namelookup::FindLocalVal localVal(SM, Loc, Consumer); localVal.checkGenericParams(dcGenericParams); if (!Results.empty()) return; } } DC = DC->getParent(); } if (!isCascadingUse.hasValue()) isCascadingUse = true; } if (auto SF = dyn_cast<SourceFile>(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 localVal(SM, Loc, Consumer); localVal.checkSourceFile(*SF); if (!Results.empty()) return; } } // TODO: Does the debugger client care about compound names? if (Name.isSimpleName() && DebugClient && DebugClient->lookupOverrides(Name.getBaseName(), DC, Loc, IsTypeLookup, Results)) return; recordLookupOfTopLevelName(DC, Name, isCascadingUse.getValue()); // Add private imports to the extra search list. SmallVector<Module::ImportedModule, 8> extraImports; if (auto FU = dyn_cast<FileUnit>(DC)) FU->getImportedModules(extraImports, Module::ImportFilter::Private); using namespace namelookup; SmallVector<ValueDecl *, 8> CurModuleResults; auto resolutionKind = IsTypeLookup ? ResolutionKind::TypesOnly : ResolutionKind::Overloadable; lookupInModule(&M, {}, Name, CurModuleResults, NLKind::UnqualifiedLookup, resolutionKind, TypeResolver, DC, extraImports); for (auto VD : CurModuleResults) Results.push_back(UnqualifiedLookupResult(VD)); if (DebugClient) filterForDiscriminator(Results, DebugClient); // Now add any names the DebugClient knows about to the lookup. if (Name.isSimpleName() && DebugClient) DebugClient->lookupAdditions(Name.getBaseName(), DC, Loc, IsTypeLookup, Results); // If we've found something, we're done. if (!Results.empty()) return; // If we still haven't found anything, but we do have some // declarations that are "unavailable in the current Swift", drop // those in. if (!UnavailableInnerResults.empty()) { Results = std::move(UnavailableInnerResults); return; } if (!Name.isSimpleName()) return; // Look for a module with the given name. if (Name.isSimpleName(M.getName())) { Results.push_back(UnqualifiedLookupResult(&M)); return; } Module *desiredModule = Ctx.getLoadedModule(Name.getBaseName()); if (!desiredModule && Name == Ctx.TheBuiltinModule->getName()) desiredModule = Ctx.TheBuiltinModule; if (desiredModule) { forAllVisibleModules(DC, [&](const Module::ImportedModule &import) -> bool { if (import.second == desiredModule) { Results.push_back(UnqualifiedLookupResult(import.second)); return false; } return true; }); } }
bool DeclContext::lookupQualified(Type type, DeclName member, NLOptions options, LazyResolver *typeResolver, SmallVectorImpl<ValueDecl *> &decls) const { using namespace namelookup; assert(decls.empty() && "additive lookup not supported"); if (type->is<ErrorType>()) return false; auto checkLookupCascading = [this, options]() -> Optional<bool> { switch (static_cast<unsigned>(options & NL_KnownDependencyMask)) { case 0: return isCascadingContextForLookup(/*excludeFunctions=*/false); case NL_KnownNonCascadingDependency: return false; case NL_KnownCascadingDependency: return true; case NL_KnownNoDependency: return None; default: // FIXME: Use llvm::CountPopulation_64 when that's declared constexpr. static_assert(__builtin_popcountll(NL_KnownDependencyMask) == 2, "mask should only include four values"); llvm_unreachable("mask only includes four values"); } }; // Look through lvalue and inout types. type = type->getLValueOrInOutObjectType(); // Look through metatypes. if (auto metaTy = type->getAs<AnyMetatypeType>()) type = metaTy->getInstanceType(); // Look through DynamicSelf. if (auto dynamicSelf = type->getAs<DynamicSelfType>()) type = dynamicSelf->getSelfType(); // Look for module references. if (auto moduleTy = type->getAs<ModuleType>()) { Module *module = moduleTy->getModule(); auto topLevelScope = getModuleScopeContext(); if (module == topLevelScope->getParentModule()) { if (auto maybeLookupCascade = checkLookupCascading()) { recordLookupOfTopLevelName(topLevelScope, member, maybeLookupCascade.getValue()); } lookupInModule(module, /*accessPath=*/{}, member, decls, NLKind::QualifiedLookup, ResolutionKind::Overloadable, typeResolver, topLevelScope); } else { // Note: This is a lookup into another module. Unless we're compiling // multiple modules at once, or if the other module re-exports this one, // it shouldn't be possible to have a dependency from that module on // anything in this one. // Perform the lookup in all imports of this module. forAllVisibleModules(this, [&](const Module::ImportedModule &import) -> bool { if (import.second != module) return true; lookupInModule(import.second, import.first, member, decls, NLKind::QualifiedLookup, ResolutionKind::Overloadable, typeResolver, topLevelScope); // If we're able to do an unscoped lookup, we see everything. No need // to keep going. return !import.first.empty(); }); } llvm::SmallPtrSet<ValueDecl *, 4> knownDecls; decls.erase(std::remove_if(decls.begin(), decls.end(), [&](ValueDecl *vd) -> bool { // If we're performing a type lookup, don't even attempt to validate // the decl if its not a type. if ((options & NL_OnlyTypes) && !isa<TypeDecl>(vd)) return true; return !knownDecls.insert(vd).second; }), decls.end()); if (auto *debugClient = topLevelScope->getParentModule()->getDebugClient()) filterForDiscriminator(decls, debugClient); return !decls.empty(); } auto &ctx = getASTContext(); if (!ctx.LangOpts.EnableAccessControl) options |= NL_IgnoreAccessibility; // The set of nominal type declarations we should (and have) visited. SmallVector<NominalTypeDecl *, 4> stack; llvm::SmallPtrSet<NominalTypeDecl *, 4> visited; // Handle nominal types. bool wantProtocolMembers = false; bool wantLookupInAllClasses = false; if (auto nominal = type->getAnyNominal()) { visited.insert(nominal); stack.push_back(nominal); wantProtocolMembers = (options & NL_ProtocolMembers) && !isa<ProtocolDecl>(nominal); // If we want dynamic lookup and we're searching in the // AnyObject protocol, note this for later. if (options & NL_DynamicLookup) { if (auto proto = dyn_cast<ProtocolDecl>(nominal)) { if (proto->isSpecificProtocol(KnownProtocolKind::AnyObject)) wantLookupInAllClasses = true; } } } // Handle archetypes else if (auto archetypeTy = type->getAs<ArchetypeType>()) { // Look in the protocols to which the archetype conforms (always). for (auto proto : archetypeTy->getConformsTo()) if (visited.insert(proto).second) stack.push_back(proto); // If requested, look into the superclasses of this archetype. if (options & NL_VisitSupertypes) { if (auto superclassTy = archetypeTy->getSuperclass()) { if (auto superclassDecl = superclassTy->getAnyNominal()) { if (visited.insert(superclassDecl).second) { stack.push_back(superclassDecl); wantProtocolMembers = (options & NL_ProtocolMembers) && !isa<ProtocolDecl>(superclassDecl); } } } } } // Handle protocol compositions. else if (auto compositionTy = type->getAs<ProtocolCompositionType>()) { SmallVector<ProtocolDecl *, 4> protocols; if (compositionTy->isExistentialType(protocols)) { for (auto proto : protocols) { if (visited.insert(proto).second) { stack.push_back(proto); // If we want dynamic lookup and this is the AnyObject // protocol, note this for later. if ((options & NL_DynamicLookup) && proto->isSpecificProtocol(KnownProtocolKind::AnyObject)) wantLookupInAllClasses = true; } } } } // Allow filtering of the visible declarations based on various // criteria. bool onlyCompleteObjectInits = false; auto isAcceptableDecl = [&](NominalTypeDecl *current, Decl *decl) -> bool { // If the decl is currently being type checked, then we have something // cyclic going on. Instead of poking at parts that are potentially not // set up, just assume it is acceptable. This will make sure we produce an // error later. if (decl->isBeingTypeChecked()) return true; // Filter out designated initializers, if requested. if (onlyCompleteObjectInits) { if (auto ctor = dyn_cast<ConstructorDecl>(decl)) { if (!ctor->isInheritable()) return false; } else { return false; } } // Ignore stub implementations. if (auto ctor = dyn_cast<ConstructorDecl>(decl)) { if (ctor->hasStubImplementation()) return false; } // Check access. if (!(options & NL_IgnoreAccessibility)) if (auto VD = dyn_cast<ValueDecl>(decl)) return VD->isAccessibleFrom(this); return true; }; ReferencedNameTracker *tracker = nullptr; if (auto containingSourceFile = dyn_cast<SourceFile>(getModuleScopeContext())) tracker = containingSourceFile->getReferencedNameTracker(); bool isLookupCascading; if (tracker) { if (auto maybeLookupCascade = checkLookupCascading()) isLookupCascading = maybeLookupCascade.getValue(); else tracker = nullptr; } // Visit all of the nominal types we know about, discovering any others // we need along the way. while (!stack.empty()) { auto current = stack.back(); stack.pop_back(); if (tracker) tracker->addUsedMember({current, member.getBaseName()},isLookupCascading); // Make sure we've resolved implicit constructors, if we need them. if (member.getBaseName() == ctx.Id_init && typeResolver) typeResolver->resolveImplicitConstructors(current); // Look for results within the current nominal type and its extensions. bool currentIsProtocol = isa<ProtocolDecl>(current); for (auto decl : current->lookupDirect(member)) { // If we're performing a type lookup, don't even attempt to validate // the decl if its not a type. if ((options & NL_OnlyTypes) && !isa<TypeDecl>(decl)) continue; // Resolve the declaration signature when we find the // declaration. if (typeResolver && !decl->isBeingTypeChecked()) { typeResolver->resolveDeclSignature(decl); if (!decl->hasType()) continue; } if (isAcceptableDecl(current, decl)) decls.push_back(decl); } // If we're not supposed to visit our supertypes, we're done. if ((options & NL_VisitSupertypes) == 0) continue; // Visit superclass. if (auto classDecl = dyn_cast<ClassDecl>(current)) { // If we're looking for initializers, only look at the superclass if the // current class permits inheritance. Even then, only find complete // object initializers. bool visitSuperclass = true; if (member.getBaseName() == ctx.Id_init) { if (classDecl->inheritsSuperclassInitializers(typeResolver)) onlyCompleteObjectInits = true; else visitSuperclass = false; } if (visitSuperclass) { if (auto superclassType = classDecl->getSuperclass()) if (auto superclassDecl = superclassType->getClassOrBoundGenericClass()) if (visited.insert(superclassDecl).second) stack.push_back(superclassDecl); } } // If we're not looking at a protocol and we're not supposed to // visit the protocols that this type conforms to, skip the next // step. if (!wantProtocolMembers && !currentIsProtocol) continue; SmallVector<ProtocolDecl *, 4> protocols; for (auto proto : current->getAllProtocols()) { if (visited.insert(proto).second) { stack.push_back(proto); } } // For a class, we don't need to visit the protocol members of the // superclass: that's already handled. if (isa<ClassDecl>(current)) wantProtocolMembers = false; } // If we want to perform lookup into all classes, do so now. if (wantLookupInAllClasses) { if (tracker) tracker->addDynamicLookupName(member.getBaseName(), isLookupCascading); // Collect all of the visible declarations. SmallVector<ValueDecl *, 4> allDecls; forAllVisibleModules(this, [&](Module::ImportedModule import) { import.second->lookupClassMember(import.first, member, allDecls); }); // For each declaration whose context is not something we've // already visited above, add it to the list of declarations. llvm::SmallPtrSet<ValueDecl *, 4> knownDecls; for (auto decl : allDecls) { // If we're performing a type lookup, don't even attempt to validate // the decl if its not a type. if ((options & NL_OnlyTypes) && !isa<TypeDecl>(decl)) continue; if (typeResolver && !decl->isBeingTypeChecked()) { typeResolver->resolveDeclSignature(decl); if (!decl->hasType()) continue; } // 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 (decl->getOverriddenDecl()) continue; auto dc = decl->getDeclContext(); auto nominal = dyn_cast<NominalTypeDecl>(dc); if (!nominal) { auto ext = cast<ExtensionDecl>(dc); nominal = ext->getExtendedType()->getAnyNominal(); assert(nominal && "Couldn't find nominal type?"); } // If we didn't visit this nominal type above, add this // declaration to the list. if (!visited.count(nominal) && knownDecls.insert(decl).second && isAcceptableDecl(nominal, decl)) decls.push_back(decl); } } // If we're supposed to remove overridden declarations, do so now. if (options & NL_RemoveOverridden) removeOverriddenDecls(decls); // If we're supposed to remove shadowed/hidden declarations, do so now. Module *M = getParentModule(); if (options & NL_RemoveNonVisible) removeShadowedDecls(decls, M, typeResolver); if (auto *debugClient = M->getDebugClient()) filterForDiscriminator(decls, debugClient); // We're done. Report success/failure. return !decls.empty(); }