void ModuleFile::lookupClassMembers(Module::AccessPathTy accessPath, VisibleDeclConsumer &consumer) { PrettyModuleFileDeserialization stackEntry(*this); assert(accessPath.size() <= 1 && "can only refer to top-level decls"); if (!ClassMembersByName) return; if (!accessPath.empty()) { for (const auto &list : ClassMembersByName->data()) { for (auto item : list) { 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) consumer.foundDecl(vd, DeclVisibilityKind::DynamicLookup); } } return; } for (const auto &list : ClassMembersByName->data()) { for (auto item : list) consumer.foundDecl(cast<ValueDecl>(getDecl(item.second)), DeclVisibilityKind::DynamicLookup); } }
void ModuleFile::lookupVisibleDecls(Module::AccessPathTy accessPath, VisibleDeclConsumer &consumer, NLKind lookupKind) { PrettyModuleFileDeserialization stackEntry(*this); assert(accessPath.size() <= 1 && "can only refer to top-level decls"); if (!TopLevelDecls) return; if (!accessPath.empty()) { auto iter = TopLevelDecls->find(accessPath.front().first); if (iter == TopLevelDecls->end()) return; for (auto item : *iter) consumer.foundDecl(cast<ValueDecl>(getDecl(item.second)), DeclVisibilityKind::VisibleAtTopLevel); return; } for (auto entry : TopLevelDecls->data()) { for (auto item : entry) consumer.foundDecl(cast<ValueDecl>(getDecl(item.second)), DeclVisibilityKind::VisibleAtTopLevel); } }
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 void lookupInModule(Module *module, Module::AccessPathTy accessPath, SmallVectorImpl<ValueDecl *> &decls, ResolutionKind resolutionKind, bool canReturnEarly, LazyResolver *typeResolver, ModuleLookupCache &cache, const DeclContext *moduleScopeContext, bool respectAccessControl, ArrayRef<Module::ImportedModule> extraImports, CallbackTy callback) { assert(module); assert(std::none_of(extraImports.begin(), extraImports.end(), [](Module::ImportedModule import) -> bool { return !import.second; })); ModuleLookupCache::iterator iter; bool isNew; std::tie(iter, isNew) = cache.insert({{accessPath, module}, {}}); if (!isNew) { decls.append(iter->second.begin(), iter->second.end()); return; } size_t initialCount = decls.size(); SmallVector<ValueDecl *, 4> localDecls; callback(module, accessPath, localDecls); if (respectAccessControl) { auto newEndIter = std::remove_if(localDecls.begin(), localDecls.end(), [=](ValueDecl *VD) { if (typeResolver) { typeResolver->resolveAccessibility(VD); } if (!VD->hasAccessibility()) return false; return !VD->isAccessibleFrom(moduleScopeContext); }); localDecls.erase(newEndIter, localDecls.end()); // This only applies to immediate imports of the top-level module. if (moduleScopeContext && moduleScopeContext->getParentModule() != module) moduleScopeContext = nullptr; } OverloadSetTy overloads; resolutionKind = recordImportDecls(typeResolver, decls, localDecls, overloads, resolutionKind); bool foundDecls = decls.size() > initialCount; if (!foundDecls || !canReturnEarly || resolutionKind == ResolutionKind::Overloadable) { SmallVector<Module::ImportedModule, 8> reexports; module->getImportedModulesForLookup(reexports); assert(std::none_of(reexports.begin(), reexports.end(), [](Module::ImportedModule import) -> bool { return !import.second; })); reexports.append(extraImports.begin(), extraImports.end()); // Prefer scoped imports (import func Swift.max) to whole-module imports. SmallVector<ValueDecl *, 8> unscopedValues; SmallVector<ValueDecl *, 8> scopedValues; for (auto next : reexports) { // Filter any whole-module imports, and skip specific-decl imports if the // import path doesn't match exactly. Module::AccessPathTy combinedAccessPath; if (accessPath.empty()) { combinedAccessPath = next.first; } else if (!next.first.empty() && !Module::isSameAccessPath(next.first, accessPath)) { // If we ever allow importing non-top-level decls, it's possible the // rule above isn't what we want. assert(next.first.size() == 1 && "import of non-top-level decl"); continue; } else { combinedAccessPath = accessPath; } auto &resultSet = next.first.empty() ? unscopedValues : scopedValues; lookupInModule<OverloadSetTy>(next.second, combinedAccessPath, resultSet, resolutionKind, canReturnEarly, typeResolver, cache, moduleScopeContext, respectAccessControl, {}, callback); } // Add the results from scoped imports. resolutionKind = recordImportDecls(typeResolver, decls, scopedValues, overloads, resolutionKind); // Add the results from unscoped imports. foundDecls = decls.size() > initialCount; if (!foundDecls || !canReturnEarly || resolutionKind == ResolutionKind::Overloadable) { resolutionKind = recordImportDecls(typeResolver, decls, unscopedValues, overloads, resolutionKind); } } // Remove duplicated declarations. llvm::SmallPtrSet<ValueDecl *, 4> knownDecls; decls.erase(std::remove_if(decls.begin() + initialCount, decls.end(), [&](ValueDecl *d) -> bool { return !knownDecls.insert(d).second; }), decls.end()); auto &cachedValues = cache[{accessPath, module}]; cachedValues.insert(cachedValues.end(), decls.begin() + initialCount, decls.end()); }