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; }
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); } } } }
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; }); } }