blob: 6d5497d4fdfef02c42a7672f111a37308bb38ed3 [file] [log] [blame]
//===--- ModuleFile.cpp - Loading a serialized module ---------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "ModuleFile.h"
#include "ModuleFileCoreTableInfo.h"
#include "BCReadingExtras.h"
#include "DeserializationErrors.h"
#include "ModuleFormat.h"
#include "swift/Serialization/SerializationOptions.h"
#include "swift/Subsystems.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTMangler.h"
#include "swift/AST/GenericSignature.h"
#include "swift/AST/ModuleLoader.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/PrettyStackTrace.h"
#include "swift/AST/USRGeneration.h"
#include "swift/Basic/Range.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "swift/Serialization/SerializedModuleLoader.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Chrono.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/OnDiskHashTable.h"
using namespace swift;
using namespace swift::serialization;
using namespace llvm::support;
using llvm::Expected;
static_assert(IsTriviallyDestructible<SerializedASTFile>::value,
"SerializedASTFiles are BumpPtrAllocated; d'tors are not called");
static bool areCompatibleArchitectures(const llvm::Triple &moduleTarget,
const llvm::Triple &ctxTarget) {
if (moduleTarget.getArch() == ctxTarget.getArch())
return true;
// Special case: ARM and Thumb are compatible.
const llvm::Triple::ArchType moduleArch = moduleTarget.getArch();
const llvm::Triple::ArchType ctxArch = ctxTarget.getArch();
if ((moduleArch == llvm::Triple::arm && ctxArch == llvm::Triple::thumb) ||
(moduleArch == llvm::Triple::thumb && ctxArch == llvm::Triple::arm))
return true;
if ((moduleArch == llvm::Triple::armeb && ctxArch == llvm::Triple::thumbeb) ||
(moduleArch == llvm::Triple::thumbeb && ctxArch == llvm::Triple::armeb))
return true;
return false;
}
static bool areCompatibleOSs(const llvm::Triple &moduleTarget,
const llvm::Triple &ctxTarget) {
if ((!moduleTarget.hasEnvironment() && ctxTarget.isSimulatorEnvironment()) ||
(!ctxTarget.hasEnvironment() && moduleTarget.isSimulatorEnvironment()))
return false;
if (moduleTarget.getOS() == ctxTarget.getOS())
return true;
// Special case: macOS and Darwin are compatible.
const llvm::Triple::OSType moduleOS = moduleTarget.getOS();
const llvm::Triple::OSType ctxOS = ctxTarget.getOS();
if ((moduleOS == llvm::Triple::Darwin && ctxOS == llvm::Triple::MacOSX) ||
(moduleOS == llvm::Triple::MacOSX && ctxOS == llvm::Triple::Darwin))
return true;
return false;
}
static bool isTargetTooNew(const llvm::Triple &moduleTarget,
const llvm::Triple &ctxTarget) {
unsigned major, minor, micro;
if (moduleTarget.isMacOSX()) {
moduleTarget.getMacOSXVersion(major, minor, micro);
return ctxTarget.isMacOSXVersionLT(major, minor, micro);
}
moduleTarget.getOSVersion(major, minor, micro);
return ctxTarget.isOSVersionLT(major, minor, micro);
}
ModuleFile::ModuleFile(std::shared_ptr<const ModuleFileSharedCore> core)
: Core(core),
DeserializedTypeCallback([](Type ty) {}) {
assert(!core->hasError());
DeclTypeCursor = core->DeclTypeCursor;
SILCursor = core->SILCursor;
SILIndexCursor = core->SILIndexCursor;
DeclMemberTablesCursor = core->DeclMemberTablesCursor;
for (const auto &coreDep : core->Dependencies) {
Dependencies.emplace_back(coreDep);
}
// `ModuleFileSharedCore` has immutable data, we copy these into `ModuleFile`
// so we can mutate the arrays and replace the offsets with AST object
// pointers as we lazily deserialize them.
allocateBuffer(Decls, core->Decls);
allocateBuffer(LocalDeclContexts, core->LocalDeclContexts);
allocateBuffer(NormalConformances, core->NormalConformances);
allocateBuffer(SILLayouts, core->SILLayouts);
allocateBuffer(Types, core->Types);
allocateBuffer(ClangTypes, core->ClangTypes);
allocateBuffer(GenericSignatures, core->GenericSignatures);
allocateBuffer(SubstitutionMaps, core->SubstitutionMaps);
allocateBuffer(Identifiers, core->Identifiers);
}
Status ModuleFile::associateWithFileContext(FileUnit *file, SourceLoc diagLoc) {
PrettyStackTraceModuleFile stackEntry(*this);
assert(!hasError() && "error already detected; should not call this");
assert(!FileContext && "already associated with an AST module");
FileContext = file;
ModuleDecl *M = file->getParentModule();
if (M->getName().str() != Core->Name)
return error(Status::NameMismatch);
ASTContext &ctx = getContext();
llvm::Triple moduleTarget(llvm::Triple::normalize(Core->TargetTriple));
if (!areCompatibleArchitectures(moduleTarget, ctx.LangOpts.Target) ||
!areCompatibleOSs(moduleTarget, ctx.LangOpts.Target)) {
return error(Status::TargetIncompatible);
}
if (ctx.LangOpts.EnableTargetOSChecking &&
!M->isResilient() &&
isTargetTooNew(moduleTarget, ctx.LangOpts.Target)) {
return error(Status::TargetTooNew);
}
for (const auto &searchPath : Core->SearchPaths)
ctx.addSearchPath(searchPath.Path, searchPath.IsFramework,
searchPath.IsSystem);
auto clangImporter = static_cast<ClangImporter *>(ctx.getClangModuleLoader());
bool missingDependency = false;
for (auto &dependency : Dependencies) {
assert(!dependency.isLoaded() && "already loaded?");
if (dependency.isHeader()) {
// The path may be empty if the file being loaded is a partial AST,
// and the current compiler invocation is a merge-modules step.
if (!dependency.Core.RawPath.empty()) {
bool hadError =
clangImporter->importHeader(dependency.Core.RawPath,
file->getParentModule(),
Core->importedHeaderInfo.fileSize,
Core->importedHeaderInfo.fileModTime,
Core->importedHeaderInfo.contents,
diagLoc);
if (hadError)
return error(Status::FailedToLoadBridgingHeader);
}
ModuleDecl *importedHeaderModule = clangImporter->getImportedHeaderModule();
dependency.Import = ImportedModule{ImportPath::Access(),
importedHeaderModule};
continue;
}
// If this module file is being installed into the main module, it's treated
// as a partial module.
auto isPartialModule = M->isMainModule();
if (dependency.isImplementationOnly() &&
!(isPartialModule || ctx.LangOpts.DebuggerSupport)) {
// When building normally (and not merging partial modules), we don't
// want to bring in the implementation-only module, because that might
// change the set of visible declarations. However, when debugging we
// want to allow getting at the internals of this module when possible,
// and so we'll try to reference the implementation-only module if it's
// available.
continue;
}
ImportPath::Builder builder(ctx, dependency.Core.RawPath,
/*separator=*/'\0');
for (const auto &elem : builder) {
assert(!elem.Item.empty() && "invalid import path name");
}
auto importPath = builder.copyTo(ctx);
auto modulePath = importPath.getModulePath(dependency.isScoped());
auto accessPath = importPath.getAccessPath(dependency.isScoped());
auto module = getModule(modulePath, /*allowLoading*/true);
if (!module || module->failedToLoad()) {
// If we're missing the module we're an overlay for, treat that specially.
if (modulePath.size() == 1 &&
modulePath.front().Item == file->getParentModule()->getName()) {
return error(Status::MissingUnderlyingModule);
}
// Otherwise, continue trying to load dependencies, so that we can list
// everything that's missing.
if (!(dependency.isImplementationOnly() && ctx.LangOpts.DebuggerSupport))
missingDependency = true;
continue;
}
dependency.Import = ImportedModule{accessPath, module};
// SPI
StringRef spisStr = dependency.Core.RawSPIs;
while (!spisStr.empty()) {
StringRef nextComponent;
std::tie(nextComponent, spisStr) = spisStr.split('\0');
dependency.spiGroups.push_back(ctx.getIdentifier(nextComponent));
}
if (!module->hasResolvedImports()) {
// Notice that we check this condition /after/ recording the module that
// caused the problem. Clients need to be able to track down what the
// cycle was.
return error(Status::CircularDependency);
}
}
if (missingDependency) {
return error(Status::MissingDependency);
}
if (Core->Bits.HasEntryPoint) {
FileContext->getParentModule()->registerEntryPointFile(FileContext,
SourceLoc(),
None);
}
return Status::Valid;
}
bool ModuleFile::mayHaveDiagnosticsPointingAtBuffer() const {
if (!hasError())
return false;
// Today, the only buffer that might have diagnostics in them is the input
// buffer, and even then only if it has imported module contents.
return !Core->importedHeaderInfo.contents.empty();
}
ModuleFile::~ModuleFile() { }
void ModuleFile::lookupValue(DeclName name,
SmallVectorImpl<ValueDecl*> &results) {
PrettyStackTraceModuleFile stackEntry(*this);
if (Core->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 = Core->TopLevelDecls->find(name.getBaseName());
if (iter != Core->TopLevelDecls->end()) {
for (auto item : *iter) {
Expected<Decl *> declOrError = getDeclChecked(item.second);
if (!declOrError) {
if (!getContext().LangOpts.EnableDeserializationRecovery)
fatal(declOrError.takeError());
llvm::consumeError(declOrError.takeError());
continue;
}
auto VD = cast<ValueDecl>(declOrError.get());
if (name.isSimpleName() || VD->getName().matchesRef(name))
results.push_back(VD);
}
}
}
// If the name is an operator name, also look for operator methods.
if (name.isOperator() && Core->OperatorMethodDecls) {
auto iter = Core->OperatorMethodDecls->find(name.getBaseName());
if (iter != Core->OperatorMethodDecls->end()) {
for (auto item : *iter) {
Expected<Decl *> declOrError = getDeclChecked(item.second);
if (!declOrError) {
if (!getContext().LangOpts.EnableDeserializationRecovery)
fatal(declOrError.takeError());
llvm::consumeError(declOrError.takeError());
continue;
}
auto VD = cast<ValueDecl>(declOrError.get());
results.push_back(VD);
}
}
}
}
TypeDecl *ModuleFile::lookupLocalType(StringRef MangledName) {
PrettyStackTraceModuleFile stackEntry(*this);
if (!Core->LocalTypeDecls)
return nullptr;
auto iter = Core->LocalTypeDecls->find(MangledName);
if (iter == Core->LocalTypeDecls->end())
return nullptr;
return cast<TypeDecl>(getDecl(*iter));
}
std::unique_ptr<llvm::MemoryBuffer>
ModuleFile::getModuleName(ASTContext &Ctx, StringRef modulePath,
std::string &Name) {
// Open the module file
auto &fs = *Ctx.SourceMgr.getFileSystem();
auto moduleBuf = fs.getBufferForFile(modulePath);
if (!moduleBuf)
return nullptr;
// FIXME: This goes through the full cost of creating a ModuleFile object
// and then it keeps just the name and discards the whole object.
// The user of this API is `ExplicitSwiftModuleLoader`, this API should
// change to return a `ModuleFileSharedCore` object that
// `ExplicitSwiftModuleLoader` caches.
// Load the module file without validation.
std::unique_ptr<llvm::MemoryBuffer> newBuf =
llvm::MemoryBuffer::getMemBuffer(llvm::MemoryBufferRef(*moduleBuf.get()),
/*RequiresNullTerminator=*/false);
std::shared_ptr<const ModuleFileSharedCore> loadedModuleFile;
bool isFramework = false;
serialization::ValidationInfo loadInfo =
ModuleFileSharedCore::load(modulePath.str(),
std::move(newBuf),
nullptr,
nullptr,
/*isFramework*/isFramework, loadedModuleFile);
Name = loadedModuleFile->Name.str();
return std::move(moduleBuf.get());
}
OpaqueTypeDecl *ModuleFile::lookupOpaqueResultType(StringRef MangledName) {
PrettyStackTraceModuleFile stackEntry(*this);
if (!Core->OpaqueReturnTypeDecls)
return nullptr;
auto iter = Core->OpaqueReturnTypeDecls->find(MangledName);
if (iter == Core->OpaqueReturnTypeDecls->end())
return nullptr;
return cast<OpaqueTypeDecl>(getDecl(*iter));
}
TypeDecl *ModuleFile::lookupNestedType(Identifier name,
const NominalTypeDecl *parent) {
PrettyStackTraceModuleFile stackEntry(*this);
if (Core->NestedTypeDecls) {
auto iter = Core->NestedTypeDecls->find(name);
if (iter != Core->NestedTypeDecls->end()) {
for (std::pair<DeclID, DeclID> entry : *iter) {
assert(entry.first);
auto declOrOffset = Decls[entry.first - 1];
if (!declOrOffset.isComplete())
continue;
Decl *decl = declOrOffset;
if (decl != parent)
continue;
return cast<TypeDecl>(getDecl(entry.second));
}
}
}
if (!UnderlyingModule)
return nullptr;
for (FileUnit *file : UnderlyingModule->getFiles())
if (auto *nestedType = file->lookupNestedType(name, parent))
return nestedType;
return nullptr;
}
OperatorDecl *ModuleFile::lookupOperator(Identifier name,
OperatorFixity fixity) {
PrettyStackTraceModuleFile stackEntry(*this);
if (!Core->OperatorDecls)
return nullptr;
auto iter = Core->OperatorDecls->find(name);
if (iter == Core->OperatorDecls->end())
return nullptr;
for (auto item : *iter) {
if (getStableFixity(fixity) == item.first)
return cast<OperatorDecl>(getDecl(item.second));
}
return nullptr;
}
PrecedenceGroupDecl *ModuleFile::lookupPrecedenceGroup(Identifier name) {
PrettyStackTraceModuleFile stackEntry(*this);
if (!Core->PrecedenceGroupDecls)
return nullptr;
auto iter = Core->PrecedenceGroupDecls->find(name);
if (iter == Core->PrecedenceGroupDecls->end())
return nullptr;
auto data = *iter;
assert(data.size() == 1);
return cast<PrecedenceGroupDecl>(getDecl(data[0].second));
}
void ModuleFile::getImportedModules(SmallVectorImpl<ImportedModule> &results,
ModuleDecl::ImportFilter filter) {
PrettyStackTraceModuleFile stackEntry(*this);
for (auto &dep : Dependencies) {
if (dep.isExported()) {
if (!filter.contains(ModuleDecl::ImportFilterKind::Exported))
continue;
} else if (dep.isImplementationOnly()) {
if (!filter.contains(ModuleDecl::ImportFilterKind::ImplementationOnly))
continue;
if (!dep.isLoaded()) {
// Pretend we didn't have this import if we weren't originally asked to
// load it.
continue;
}
} else {
if (!filter.contains(ModuleDecl::ImportFilterKind::Default))
continue;
}
assert(dep.isLoaded());
results.push_back(*(dep.Import));
}
}
void ModuleFile::getImportDecls(SmallVectorImpl<Decl *> &Results) {
if (!Bits.ComputedImportDecls) {
ASTContext &Ctx = getContext();
for (auto &Dep : Dependencies) {
// FIXME: We need a better way to show headers, since they usually /are/
// re-exported. This isn't likely to come up much, though.
if (Dep.isHeader())
continue;
ImportPath::Builder importPath(Ctx, Dep.Core.RawPath, /*separator=*/'\0');
if (importPath.size() == 1
&& importPath.front().Item == Ctx.StdlibModuleName)
continue;
auto modulePath = importPath.get().getModulePath(Dep.isScoped());
ModuleDecl *M = Ctx.getLoadedModule(modulePath);
auto Kind = ImportKind::Module;
if (Dep.isScoped()) {
auto ScopeID = importPath.get().getAccessPath(true).front().Item;
assert(!ScopeID.empty() &&
"invalid decl name (non-top-level decls not supported)");
if (!M) {
// The dependency module could not be loaded. Just make a guess
// about the import kind, we cannot do better.
Kind = ImportKind::Func;
} else {
// Lookup the decl in the top-level module.
ModuleDecl *TopLevelModule = M;
if (importPath.size() > 1)
TopLevelModule = Ctx.getLoadedModule(modulePath.getTopLevelPath());
SmallVector<ValueDecl *, 8> Decls;
TopLevelModule->lookupQualified(
TopLevelModule, DeclNameRef(ScopeID),
NL_QualifiedDefault, Decls);
Optional<ImportKind> FoundKind = ImportDecl::findBestImportKind(Decls);
assert(FoundKind.hasValue() &&
"deserialized imports should not be ambiguous");
Kind = *FoundKind;
}
}
auto *ID = ImportDecl::create(Ctx, FileContext, SourceLoc(), Kind,
SourceLoc(), importPath.get());
ID->setModule(M);
if (Dep.isExported())
ID->getAttrs().add(
new (Ctx) ExportedAttr(/*IsImplicit=*/false));
ImportDecls.push_back(ID);
}
Bits.ComputedImportDecls = true;
}
Results.append(ImportDecls.begin(), ImportDecls.end());
}
void ModuleFile::lookupVisibleDecls(ImportPath::Access accessPath,
VisibleDeclConsumer &consumer,
NLKind lookupKind) {
PrettyStackTraceModuleFile stackEntry(*this);
assert(accessPath.size() <= 1 && "can only refer to top-level decls");
if (!Core->TopLevelDecls)
return;
auto tryImport = [this, &consumer](DeclID ID) {
Expected<Decl *> declOrError = getDeclChecked(ID);
if (!declOrError) {
if (!getContext().LangOpts.EnableDeserializationRecovery)
fatal(declOrError.takeError());
llvm::consumeError(declOrError.takeError());
return;
}
consumer.foundDecl(cast<ValueDecl>(declOrError.get()),
DeclVisibilityKind::VisibleAtTopLevel);
};
if (!accessPath.empty()) {
auto iter = Core->TopLevelDecls->find(accessPath.front().Item);
if (iter == Core->TopLevelDecls->end())
return;
for (auto item : *iter)
tryImport(item.second);
return;
}
for (auto entry : Core->TopLevelDecls->data()) {
for (auto item : entry)
tryImport(item.second);
}
}
void ModuleFile::loadExtensions(NominalTypeDecl *nominal) {
PrettyStackTraceModuleFile stackEntry(*this);
if (!Core->ExtensionDecls)
return;
auto iter = Core->ExtensionDecls->find(nominal->getName());
if (iter == Core->ExtensionDecls->end())
return;
if (nominal->getEffectiveAccess() < AccessLevel::Internal) {
if (nominal->getModuleScopeContext() != getFile())
return;
}
if (nominal->getParent()->isModuleScopeContext()) {
auto parentFile = cast<FileUnit>(nominal->getParent());
StringRef moduleName = parentFile->getExportedModuleName();
for (auto item : *iter) {
if (item.first != moduleName)
continue;
Expected<Decl *> declOrError = getDeclChecked(item.second);
if (!declOrError) {
if (!getContext().LangOpts.EnableDeserializationRecovery)
fatal(declOrError.takeError());
llvm::consumeError(declOrError.takeError());
}
}
} else {
std::string mangledName =
Mangle::ASTMangler().mangleNominalType(nominal);
for (auto item : *iter) {
if (item.first != mangledName)
continue;
Expected<Decl *> declOrError = getDeclChecked(item.second);
if (!declOrError) {
if (!getContext().LangOpts.EnableDeserializationRecovery)
fatal(declOrError.takeError());
llvm::consumeError(declOrError.takeError());
}
}
}
}
void ModuleFile::loadObjCMethods(
ClassDecl *classDecl,
ObjCSelector selector,
bool isInstanceMethod,
llvm::TinyPtrVector<AbstractFunctionDecl *> &methods) {
// If we don't have an Objective-C method table, there's nothing to do.
if (!Core->ObjCMethods)
return;
// Look for all methods in the module file with this selector.
auto known = Core->ObjCMethods->find(selector);
if (known == Core->ObjCMethods->end()) {
return;
}
std::string ownerName = Mangle::ASTMangler().mangleNominalType(classDecl);
auto results = *known;
for (const auto &result : results) {
// If the method is the wrong kind (instance vs. class), skip it.
if (isInstanceMethod != std::get<1>(result))
continue;
// If the method isn't defined in the requested class, skip it.
if (std::get<0>(result) != ownerName)
continue;
// Deserialize the method and add it to the list.
if (auto func = dyn_cast_or_null<AbstractFunctionDecl>(
getDecl(std::get<2>(result)))) {
methods.push_back(func);
}
}
}
void ModuleFile::loadDerivativeFunctionConfigurations(
AbstractFunctionDecl *originalAFD,
llvm::SetVector<AutoDiffConfig> &results) {
if (!Core->DerivativeFunctionConfigurations)
return;
auto &ctx = originalAFD->getASTContext();
Mangle::ASTMangler Mangler;
auto mangledName = Mangler.mangleDeclAsUSR(originalAFD, "");
auto configs = Core->DerivativeFunctionConfigurations->find(mangledName);
if (configs == Core->DerivativeFunctionConfigurations->end())
return;
for (auto entry : *configs) {
auto *parameterIndices = IndexSubset::getFromString(ctx, entry.first);
auto derivativeGenSigOrError = getGenericSignatureChecked(entry.second);
if (!derivativeGenSigOrError) {
if (!getContext().LangOpts.EnableDeserializationRecovery)
fatal(derivativeGenSigOrError.takeError());
llvm::consumeError(derivativeGenSigOrError.takeError());
}
auto derivativeGenSig = derivativeGenSigOrError.get();
// NOTE(TF-1038): Result indices are currently unsupported in derivative
// registration attributes. In the meantime, always use `{0}` (wrt the
// first and only result).
auto resultIndices = IndexSubset::get(ctx, 1, {0});
results.insert({parameterIndices, resultIndices, derivativeGenSig});
}
}
Optional<Fingerprint>
ModuleFile::loadFingerprint(const IterableDeclContext *IDC) const {
PrettyStackTraceDecl trace("loading fingerprints for", IDC->getDecl());
assert(IDC->wasDeserialized());
assert(IDC->getDeclID() != 0);
if (!Core->DeclFingerprints) {
return None;
}
auto it = Core->DeclFingerprints->find(IDC->getDeclID());
if (it == Core->DeclFingerprints->end()) {
return None;
}
return *it;
}
TinyPtrVector<ValueDecl *>
ModuleFile::loadNamedMembers(const IterableDeclContext *IDC, DeclBaseName N,
uint64_t contextData) {
PrettyStackTraceDecl trace("loading members for", IDC->getDecl());
assert(IDC->wasDeserialized());
assert(Core->DeclMemberNames);
TinyPtrVector<ValueDecl *> results;
auto i = Core->DeclMemberNames->find(N);
if (i == Core->DeclMemberNames->end())
return results;
BitOffset subTableOffset = *i;
std::unique_ptr<SerializedDeclMembersTable> &subTable =
DeclMembersTables[subTableOffset];
if (!subTable) {
BCOffsetRAII restoreOffset(DeclMemberTablesCursor);
fatalIfNotSuccess(DeclMemberTablesCursor.JumpToBit(subTableOffset));
llvm::BitstreamEntry entry =
fatalIfUnexpected(DeclMemberTablesCursor.advance());
if (entry.Kind != llvm::BitstreamEntry::Record) {
fatal();
return results;
}
SmallVector<uint64_t, 64> scratch;
StringRef blobData;
unsigned kind = fatalIfUnexpected(
DeclMemberTablesCursor.readRecord(entry.ID, scratch, &blobData));
assert(kind == decl_member_tables_block::DECL_MEMBERS);
(void)kind;
subTable = Core->readDeclMembersTable(scratch, blobData);
}
assert(subTable);
auto j = subTable->find(IDC->getDeclID());
if (j != subTable->end()) {
for (DeclID d : *j) {
Expected<Decl *> mem = getDeclChecked(d);
if (mem) {
assert(mem.get() && "unchecked error deserializing named member");
if (auto MVD = dyn_cast<ValueDecl>(mem.get())) {
results.push_back(MVD);
}
} else {
if (!getContext().LangOpts.EnableDeserializationRecovery)
fatal(mem.takeError());
consumeError(mem.takeError());
}
}
}
return results;
}
void ModuleFile::lookupClassMember(ImportPath::Access accessPath,
DeclName name,
SmallVectorImpl<ValueDecl*> &results) {
PrettyStackTraceModuleFile stackEntry(*this);
assert(accessPath.size() <= 1 && "can only refer to top-level decls");
if (!Core->ClassMembersForDynamicLookup)
return;
auto iter = Core->ClassMembersForDynamicLookup->find(name.getBaseName());
if (iter == Core->ClassMembersForDynamicLookup->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->getSelfNominalTypeDecl())
if (nominal->getName() == accessPath.front().Item)
results.push_back(vd);
}
} else {
for (auto item : *iter) {
auto vd = cast<ValueDecl>(getDecl(item.second));
if (!vd->getName().matchesRef(name))
continue;
auto dc = vd->getDeclContext();
while (!dc->getParent()->isModuleScopeContext())
dc = dc->getParent();
if (auto nominal = dc->getSelfNominalTypeDecl())
if (nominal->getName() == accessPath.front().Item)
results.push_back(vd);
}
}
return;
}
for (auto item : *iter) {
auto vd = cast<ValueDecl>(getDecl(item.second));
results.push_back(vd);
}
}
void ModuleFile::lookupClassMembers(ImportPath::Access accessPath,
VisibleDeclConsumer &consumer) {
PrettyStackTraceModuleFile stackEntry(*this);
assert(accessPath.size() <= 1 && "can only refer to top-level decls");
if (!Core->ClassMembersForDynamicLookup)
return;
if (!accessPath.empty()) {
for (const auto &list : Core->ClassMembersForDynamicLookup->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->getSelfNominalTypeDecl())
if (nominal->getName() == accessPath.front().Item)
consumer.foundDecl(vd, DeclVisibilityKind::DynamicLookup,
DynamicLookupInfo::AnyObject);
}
}
return;
}
for (const auto &list : Core->ClassMembersForDynamicLookup->data()) {
for (auto item : list)
consumer.foundDecl(cast<ValueDecl>(getDecl(item.second)),
DeclVisibilityKind::DynamicLookup,
DynamicLookupInfo::AnyObject);
}
}
void ModuleFile::lookupObjCMethods(
ObjCSelector selector,
SmallVectorImpl<AbstractFunctionDecl *> &results) {
// If we don't have an Objective-C method table, there's nothing to do.
if (!Core->ObjCMethods) return;
// Look for all methods in the module file with this selector.
auto known = Core->ObjCMethods->find(selector);
if (known == Core->ObjCMethods->end()) return;
auto found = *known;
for (const auto &result : found) {
// Deserialize the method and add it to the list.
if (auto func = dyn_cast_or_null<AbstractFunctionDecl>(
getDecl(std::get<2>(result))))
results.push_back(func);
}
}
void ModuleFile::lookupImportedSPIGroups(
const ModuleDecl *importedModule,
llvm::SmallSetVector<Identifier, 4> &spiGroups) const {
for (auto &dep : Dependencies) {
auto depSpis = dep.spiGroups;
if (dep.Import.hasValue() && dep.Import->importedModule == importedModule &&
!depSpis.empty()) {
spiGroups.insert(depSpis.begin(), depSpis.end());
}
}
}
void
ModuleFile::collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const {
for (const auto &lib : Core->LinkLibraries)
callback(lib);
if (Core->Bits.IsFramework)
callback(LinkLibrary(Core->Name, LibraryKind::Framework));
}
void ModuleFile::getTopLevelDecls(
SmallVectorImpl<Decl *> &results,
llvm::function_ref<bool(DeclAttributes)> matchAttributes) {
PrettyStackTraceModuleFile stackEntry(*this);
for (DeclID entry : Core->OrderedTopLevelDecls) {
Expected<Decl *> declOrError = getDeclChecked(entry, matchAttributes);
if (!declOrError) {
if (declOrError.errorIsA<DeclAttributesDidNotMatch>()) {
// Decl rejected by matchAttributes, ignore it.
assert(matchAttributes);
consumeError(declOrError.takeError());
continue;
}
if (!getContext().LangOpts.EnableDeserializationRecovery)
fatal(declOrError.takeError());
consumeError(declOrError.takeError());
continue;
}
results.push_back(declOrError.get());
}
}
void ModuleFile::getExportedPrespecializations(
SmallVectorImpl<Decl *> &results) {
for (DeclID entry : Core->ExportedPrespecializationDecls) {
Expected<Decl *> declOrError = getDeclChecked(entry);
if (!declOrError) {
if (!getContext().LangOpts.EnableDeserializationRecovery)
fatal(declOrError.takeError());
consumeError(declOrError.takeError());
continue;
}
results.push_back(declOrError.get());
}
}
void ModuleFile::getOperatorDecls(SmallVectorImpl<OperatorDecl *> &results) {
PrettyStackTraceModuleFile stackEntry(*this);
if (!Core->OperatorDecls)
return;
for (auto entry : Core->OperatorDecls->data()) {
for (auto item : entry)
results.push_back(cast<OperatorDecl>(getDecl(item.second)));
}
}
void ModuleFile::getPrecedenceGroups(
SmallVectorImpl<PrecedenceGroupDecl*> &results) {
PrettyStackTraceModuleFile stackEntry(*this);
if (Core->PrecedenceGroupDecls) {
for (auto entry : Core->PrecedenceGroupDecls->data()) {
for (auto item : entry)
results.push_back(cast<PrecedenceGroupDecl>(getDecl(item.second)));
}
}
}
void
ModuleFile::getLocalTypeDecls(SmallVectorImpl<TypeDecl *> &results) {
PrettyStackTraceModuleFile stackEntry(*this);
if (!Core->LocalTypeDecls)
return;
for (auto DeclID : Core->LocalTypeDecls->data()) {
auto TD = cast<TypeDecl>(getDecl(DeclID));
results.push_back(TD);
}
}
void
ModuleFile::getOpaqueReturnTypeDecls(SmallVectorImpl<OpaqueTypeDecl *> &results)
{
PrettyStackTraceModuleFile stackEntry(*this);
if (!Core->OpaqueReturnTypeDecls)
return;
for (auto DeclID : Core->OpaqueReturnTypeDecls->data()) {
auto TD = cast<OpaqueTypeDecl>(getDecl(DeclID));
results.push_back(TD);
}
}
void ModuleFile::getDisplayDecls(SmallVectorImpl<Decl *> &results) {
if (UnderlyingModule)
UnderlyingModule->getDisplayDecls(results);
PrettyStackTraceModuleFile stackEntry(*this);
getImportDecls(results);
getTopLevelDecls(results);
}
Optional<CommentInfo> ModuleFile::getCommentForDecl(const Decl *D) const {
assert(D);
// Keep these as assertions instead of early exits to ensure that we are not
// doing extra work. These cases should be handled by clients of this API.
assert(!D->hasClangNode() &&
"cannot find comments for Clang decls in Swift modules");
assert(D->getDeclContext()->getModuleScopeContext() == FileContext &&
"Decl is from a different serialized file");
if (!Core->DeclCommentTable)
return None;
if (D->isImplicit())
return None;
// Compute the USR.
llvm::SmallString<128> USRBuffer;
llvm::raw_svector_ostream OS(USRBuffer);
if (ide::printDeclUSR(D, OS))
return None;
return getCommentForDeclByUSR(USRBuffer.str());
}
Optional<BasicDeclLocs>
ModuleFile::getBasicDeclLocsForDecl(const Decl *D) const {
assert(D);
// Keep these as assertions instead of early exits to ensure that we are not
// doing extra work. These cases should be handled by clients of this API.
assert(!D->hasClangNode() &&
"cannot find comments for Clang decls in Swift modules");
assert(D->getDeclContext()->getModuleScopeContext() == FileContext &&
"Decl is from a different serialized file");
if (!Core->DeclUSRsTable)
return None;
// Future compilers may not provide BasicDeclLocsData anymore.
if (Core->BasicDeclLocsData.empty())
return None;
if (D->isImplicit())
return None;
// Compute the USR.
llvm::SmallString<128> USRBuffer;
llvm::raw_svector_ostream OS(USRBuffer);
if (ide::printDeclUSR(D, OS))
return None;
auto It = Core->DeclUSRsTable->find(OS.str());
if (It == Core->DeclUSRsTable->end())
return None;
auto UsrId = *It;
uint32_t NumSize = 4;
// Size of BasicDeclLocs in the buffer.
// FilePathOffset + LocNum * LineColumn
uint32_t LineColumnCount = 3;
uint32_t RecordSize =
NumSize + // Offset into source filename blob
NumSize + // Offset into doc ranges blob
NumSize * 2 * LineColumnCount; // Line/column of: Loc, StartLoc, EndLoc
uint32_t RecordOffset = RecordSize * UsrId;
assert(RecordOffset < Core->BasicDeclLocsData.size());
assert(Core->BasicDeclLocsData.size() % RecordSize == 0);
BasicDeclLocs Result;
auto *Record = Core->BasicDeclLocsData.data() + RecordOffset;
auto ReadNext = [&Record]() {
return endian::readNext<uint32_t, little, unaligned>(Record);
};
auto FilePath = Core->SourceLocsTextData.substr(ReadNext());
size_t TerminatorOffset = FilePath.find('\0');
assert(TerminatorOffset != StringRef::npos && "unterminated string data");
Result.SourceFilePath = FilePath.slice(0, TerminatorOffset);
const auto DocRangesOffset = ReadNext();
if (DocRangesOffset) {
assert(!Core->DocRangesData.empty());
const auto *Data = Core->DocRangesData.data() + DocRangesOffset;
const auto NumLocs = endian::readNext<uint32_t, little, unaligned>(Data);
assert(NumLocs);
for (uint32_t i = 0; i < NumLocs; ++i) {
LineColumn LC;
LC.Line = endian::readNext<uint32_t, little, unaligned>(Data);
LC.Column = endian::readNext<uint32_t, little, unaligned>(Data);
auto Length = endian::readNext<uint32_t, little, unaligned>(Data);
Result.DocRanges.push_back(std::make_pair(LC, Length));
}
}
#define READ_FIELD(X) \
Result.X.Line = ReadNext(); \
Result.X.Column = ReadNext();
READ_FIELD(Loc)
READ_FIELD(StartLoc)
READ_FIELD(EndLoc)
#undef READ_FIELD
return Result;
}
const static StringRef Separator = "/";
Optional<StringRef> ModuleFile::getGroupNameById(unsigned Id) const {
if (!Core->GroupNamesMap)
return None;
const auto &GroupNamesMap = *Core->GroupNamesMap;
auto it = GroupNamesMap.find(Id);
if (it == GroupNamesMap.end())
return None;
StringRef Original = it->second;
if (Original.empty())
return None;
auto SepPos = Original.find_last_of(Separator);
assert(SepPos != StringRef::npos && "Cannot find Separator.");
return StringRef(Original.data(), SepPos);
}
Optional<StringRef> ModuleFile::getSourceFileNameById(unsigned Id) const {
if (!Core->GroupNamesMap)
return None;
const auto &GroupNamesMap = *Core->GroupNamesMap;
auto it = GroupNamesMap.find(Id);
if (it == GroupNamesMap.end())
return None;
StringRef Original = it->second;
if (Original.empty())
return None;
auto SepPos = Original.find_last_of(Separator);
assert(SepPos != StringRef::npos && "Cannot find Separator.");
auto Start = Original.data() + SepPos + 1;
auto Len = Original.size() - SepPos - 1;
return StringRef(Start, Len);
}
Optional<StringRef> ModuleFile::getGroupNameForDecl(const Decl *D) const {
auto Triple = getCommentForDecl(D);
if (!Triple.hasValue()) {
return None;
}
return getGroupNameById(Triple.getValue().Group);
}
Optional<StringRef>
ModuleFile::getSourceFileNameForDecl(const Decl *D) const {
auto Triple = getCommentForDecl(D);
if (!Triple.hasValue()) {
return None;
}
return getSourceFileNameById(Triple.getValue().Group);
}
Optional<unsigned>
ModuleFile::getSourceOrderForDecl(const Decl *D) const {
auto Triple = getCommentForDecl(D);
if (!Triple.hasValue()) {
return None;
}
return Triple.getValue().SourceOrder;
}
void ModuleFile::collectAllGroups(std::vector<StringRef> &Names) const {
if (!Core->GroupNamesMap)
return;
for (auto It = Core->GroupNamesMap->begin(); It != Core->GroupNamesMap->end();
++It) {
StringRef FullGroupName = It->getSecond();
if (FullGroupName.empty())
continue;
auto Sep = FullGroupName.find_last_of(Separator);
assert(Sep != StringRef::npos);
auto Group = FullGroupName.substr(0, Sep);
auto Found = std::find(Names.begin(), Names.end(), Group);
if (Found != Names.end())
continue;
Names.push_back(Group);
}
}
Optional<CommentInfo>
ModuleFile::getCommentForDeclByUSR(StringRef USR) const {
if (!Core->DeclCommentTable)
return None;
// Use the comment cache to preserve the memory that the array of
// `SingleRawComment`s, inside `CommentInfo`, points to, and generally avoid
// allocating memory every time we query `Core->DeclCommentTable`.
auto it = CommentsCache.find(USR);
if (it != CommentsCache.end()) {
const auto &cachePtr = it->second;
if (!cachePtr)
return None;
return cachePtr->Info;
}
auto I = Core->DeclCommentTable->find(USR);
if (I == Core->DeclCommentTable->end())
return None;
auto &cachePtr = CommentsCache[USR];
cachePtr = *I;
return cachePtr->Info;
}
Optional<StringRef>
ModuleFile::getGroupNameByUSR(StringRef USR) const {
if (auto Comment = getCommentForDeclByUSR(USR)) {
return getGroupNameById(Comment.getValue().Group);
}
return None;
}
Identifier ModuleFile::getDiscriminatorForPrivateValue(const ValueDecl *D) {
Identifier discriminator = PrivateDiscriminatorsByValue.lookup(D);
assert(!discriminator.empty() && "no discriminator found for decl");
return discriminator;
}
void ModuleFile::verify() const {
#ifndef NDEBUG
const auto &Context = getContext();
for (const Serialized<Decl*> &next : Decls)
if (next.isComplete() && swift::shouldVerify(next, Context))
swift::verify(next);
#endif
}
bool SerializedASTFile::hasEntryPoint() const {
return File.hasEntryPoint();
}
bool SerializedASTFile::getAllGenericSignatures(
SmallVectorImpl<GenericSignature> &genericSignatures) {
genericSignatures.clear();
for (unsigned index : indices(File.GenericSignatures)) {
if (auto genericSig = File.getGenericSignature(index + 1))
genericSignatures.push_back(genericSig);
}
return true;
}
Decl *SerializedASTFile::getMainDecl() const {
assert(hasEntryPoint());
return File.getDecl(File.getEntryPointDeclID());
}
const version::Version &SerializedASTFile::getLanguageVersionBuiltWith() const {
return File.getCompatibilityVersion();
}
StringRef SerializedASTFile::getModuleDefiningPath() const {
StringRef moduleFilename = getFilename();
StringRef parentDir = llvm::sys::path::parent_path(moduleFilename);
if (llvm::sys::path::extension(parentDir) == ".swiftmodule")
return parentDir;
return moduleFilename;
}