Files
swift-mirror/lib/TBDGen/TBDGen.cpp
Jordan Rose c506747a9c [Serialization] Drop inherited conformances on classes (#23347)
These can be recreated if needed in a client library. To do this, I've
added a new ConformanceLookupKind::NonInherited, which can also be
used elsewhere in the project where we're already filtering out
inherited conformances some other way.

Note that this doesn't drop inherited conformances from the entire
serialized interface, just from the list that a class explicitly
declares. They still get referenced sometimes.

rdar://problem/50541451 and possibly others
2019-05-13 13:41:10 -07:00

701 lines
24 KiB
C++

//===--- TBDGen.cpp - Swift TBD Generation --------------------------------===//
//
// 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 entrypoints into TBD file generation.
//
//===----------------------------------------------------------------------===//
#include "swift/TBDGen/TBDGen.h"
#include "swift/AST/Availability.h"
#include "swift/AST/ASTMangler.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/Module.h"
#include "swift/AST/ParameterList.h"
#include "swift/Basic/LLVM.h"
#include "swift/IRGen/Linking.h"
#include "swift/SIL/FormalLinkage.h"
#include "swift/SIL/SILDeclRef.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILVTableVisitor.h"
#include "swift/SIL/SILWitnessTable.h"
#include "swift/SIL/TypeLowering.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/YAMLTraits.h"
#include "TBDGenVisitor.h"
#include "tapi/Architecture.h"
#include "tapi/InterfaceFile.h"
#include "tapi/Platform.h"
#include "tapi/TextStub_v3.h"
#include "tapi/YAMLReaderWriter.h"
using namespace swift;
using namespace swift::irgen;
using namespace swift::tbdgen;
using StringSet = llvm::StringSet<>;
using SymbolKind = tapi::internal::SymbolKind;
static bool isGlobalOrStaticVar(VarDecl *VD) {
return VD->isStatic() || VD->getDeclContext()->isModuleScopeContext();
}
void TBDGenVisitor::addSymbol(StringRef name, SymbolKind kind) {
Symbols.addSymbol(kind, name, Archs);
if (StringSymbols && kind == SymbolKind::GlobalSymbol) {
auto isNewValue = StringSymbols->insert(name).second;
(void)isNewValue;
assert(isNewValue && "symbol appears twice");
}
}
void TBDGenVisitor::addSymbol(SILDeclRef declRef) {
auto linkage = effectiveLinkageForClassMember(
declRef.getLinkage(ForDefinition),
declRef.getSubclassScope());
if (linkage == SILLinkage::Public)
addSymbol(declRef.mangle());
}
void TBDGenVisitor::addSymbol(LinkEntity entity) {
auto linkage =
LinkInfo::get(UniversalLinkInfo, SwiftModule, AvailCtx,
entity, ForDefinition);
auto externallyVisible =
llvm::GlobalValue::isExternalLinkage(linkage.getLinkage()) &&
linkage.getVisibility() != llvm::GlobalValue::HiddenVisibility;
if (externallyVisible)
addSymbol(linkage.getName());
}
void TBDGenVisitor::addDispatchThunk(SILDeclRef declRef) {
auto entity = LinkEntity::forDispatchThunk(declRef);
addSymbol(entity);
}
void TBDGenVisitor::addMethodDescriptor(SILDeclRef declRef) {
auto entity = LinkEntity::forMethodDescriptor(declRef);
addSymbol(entity);
}
void TBDGenVisitor::addProtocolRequirementsBaseDescriptor(ProtocolDecl *proto) {
auto entity = LinkEntity::forProtocolRequirementsBaseDescriptor(proto);
addSymbol(entity);
}
void TBDGenVisitor::addAssociatedTypeDescriptor(AssociatedTypeDecl *assocType) {
auto entity = LinkEntity::forAssociatedTypeDescriptor(assocType);
addSymbol(entity);
}
void TBDGenVisitor::addAssociatedConformanceDescriptor(
AssociatedConformance conformance) {
auto entity = LinkEntity::forAssociatedConformanceDescriptor(conformance);
addSymbol(entity);
}
void TBDGenVisitor::addBaseConformanceDescriptor(
BaseConformance conformance) {
auto entity = LinkEntity::forBaseConformanceDescriptor(conformance);
addSymbol(entity);
}
void TBDGenVisitor::addConformances(DeclContext *DC) {
for (auto conformance : DC->getLocalConformances(
ConformanceLookupKind::NonInherited)) {
auto protocol = conformance->getProtocol();
auto needsWTable =
Lowering::TypeConverter::protocolRequiresWitnessTable(protocol);
if (!needsWTable)
continue;
// Only root conformances get symbols; the others get any public symbols
// from their parent conformances.
auto rootConformance = dyn_cast<RootProtocolConformance>(conformance);
if (!rootConformance) {
continue;
}
addSymbol(LinkEntity::forProtocolWitnessTable(rootConformance));
addSymbol(LinkEntity::forProtocolConformanceDescriptor(rootConformance));
// FIXME: the logic around visibility in extensions is confusing, and
// sometimes witness thunks need to be manually made public.
auto conformanceIsFixed = SILWitnessTable::conformanceIsSerialized(
rootConformance);
auto addSymbolIfNecessary = [&](ValueDecl *requirementDecl,
ValueDecl *witnessDecl) {
auto witnessLinkage = SILDeclRef(witnessDecl).getLinkage(ForDefinition);
if (conformanceIsFixed &&
(isa<SelfProtocolConformance>(rootConformance) ||
fixmeWitnessHasLinkageThatNeedsToBePublic(witnessLinkage))) {
Mangle::ASTMangler Mangler;
addSymbol(
Mangler.mangleWitnessThunk(rootConformance, requirementDecl));
}
};
rootConformance->forEachValueWitness(
nullptr, [&](ValueDecl *valueReq, Witness witness) {
auto witnessDecl = witness.getDecl();
if (isa<AbstractFunctionDecl>(valueReq)) {
addSymbolIfNecessary(valueReq, witnessDecl);
} else if (auto *storage = dyn_cast<AbstractStorageDecl>(valueReq)) {
auto witnessStorage = cast<AbstractStorageDecl>(witnessDecl);
storage->visitOpaqueAccessors([&](AccessorDecl *reqtAccessor) {
auto witnessAccessor =
witnessStorage->getAccessor(reqtAccessor->getAccessorKind());
assert(witnessAccessor && "no corresponding witness accessor?");
addSymbolIfNecessary(reqtAccessor, witnessAccessor);
});
}
});
}
}
/// Determine whether dynamic replacement should be emitted for the allocator or
/// the initializer given a decl.
/// The rule is that structs and convenience init of classes emit a
/// dynamic replacement for the allocator.
/// Designated init of classes emit a dynamic replacement for the intializer.
/// This is because the super class init call is emitted to the initializer and
/// needs to be dynamic.
static bool shouldUseAllocatorMangling(const AbstractFunctionDecl *afd) {
auto constructor = dyn_cast<ConstructorDecl>(afd);
if (!constructor)
return false;
return constructor->getParent()->getSelfClassDecl() == nullptr ||
constructor->isConvenienceInit();
}
void TBDGenVisitor::visitAbstractFunctionDecl(AbstractFunctionDecl *AFD) {
// A @_silgen_name("...") function without a body only exists
// to forward-declare a symbol from another library.
if (!AFD->hasBody() && AFD->getAttrs().hasAttribute<SILGenNameAttr>()) {
return;
}
addSymbol(SILDeclRef(AFD));
// Add the global function pointer for a dynamically replaceable function.
if (AFD->isNativeDynamic()) {
bool useAllocator = shouldUseAllocatorMangling(AFD);
addSymbol(LinkEntity::forDynamicallyReplaceableFunctionVariable(
AFD, useAllocator));
addSymbol(
LinkEntity::forDynamicallyReplaceableFunctionImpl(AFD, useAllocator));
addSymbol(
LinkEntity::forDynamicallyReplaceableFunctionKey(AFD, useAllocator));
}
if (AFD->getAttrs().hasAttribute<DynamicReplacementAttr>()) {
bool useAllocator = shouldUseAllocatorMangling(AFD);
addSymbol(LinkEntity::forDynamicallyReplaceableFunctionVariable(
AFD, useAllocator));
addSymbol(
LinkEntity::forDynamicallyReplaceableFunctionImpl(AFD, useAllocator));
}
if (AFD->getAttrs().hasAttribute<CDeclAttr>()) {
// A @_cdecl("...") function has an extra symbol, with the name from the
// attribute.
addSymbol(SILDeclRef(AFD).asForeign());
}
auto publicDefaultArgGenerators = SwiftModule->isTestingEnabled() ||
SwiftModule->arePrivateImportsEnabled();
if (!publicDefaultArgGenerators)
return;
// In Swift 3 (or under -enable-testing), default arguments (of public
// functions) are public symbols, as the default values are computed at the
// call site.
auto index = 0;
for (auto *param : *AFD->getParameters()) {
if (param->isDefaultArgument())
addSymbol(SILDeclRef::getDefaultArgGenerator(AFD, index));
index++;
}
}
void TBDGenVisitor::visitFuncDecl(FuncDecl *FD) {
// If there's an opaque return type, its descriptor is exported.
if (auto opaqueResult = FD->getOpaqueResultTypeDecl()) {
addSymbol(LinkEntity::forOpaqueTypeDescriptor(opaqueResult));
assert(opaqueResult->getNamingDecl() == FD);
if (FD->isNativeDynamic()) {
addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessor(opaqueResult));
addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorImpl(opaqueResult));
addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorKey(opaqueResult));
addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorVar(opaqueResult));
}
if (FD->getAttrs().hasAttribute<DynamicReplacementAttr>()) {
addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessor(opaqueResult));
addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorVar(opaqueResult));
}
}
visitAbstractFunctionDecl(FD);
}
void TBDGenVisitor::visitAccessorDecl(AccessorDecl *AD) {
// Do nothing: accessors are always nested within the storage decl, but
// sometimes appear outside it too. To avoid double-walking them, we
// explicitly visit them as members of the storage and ignore them when we
// visit them as part of the main walk, here.
}
void TBDGenVisitor::visitAbstractStorageDecl(AbstractStorageDecl *ASD) {
// Add the property descriptor if the decl needs it.
if (ASD->exportsPropertyDescriptor()) {
addSymbol(LinkEntity::forPropertyDescriptor(ASD));
}
// ...and the opaque result decl if it has one.
if (auto opaqueResult = ASD->getOpaqueResultTypeDecl()) {
addSymbol(LinkEntity::forOpaqueTypeDescriptor(opaqueResult));
assert(opaqueResult->getNamingDecl() == ASD);
if (ASD->hasAnyNativeDynamicAccessors()) {
addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessor(opaqueResult));
addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorImpl(opaqueResult));
addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorKey(opaqueResult));
addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorVar(opaqueResult));
}
if (ASD->hasAnyDynamicReplacementAccessors()) {
addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessor(opaqueResult));
addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorVar(opaqueResult));
}
}
// Explicitly look at each accessor here: see visitAccessorDecl.
for (auto accessor : ASD->getAllAccessors()) {
visitAbstractFunctionDecl(accessor);
}
}
void TBDGenVisitor::visitVarDecl(VarDecl *VD) {
// Variables inside non-resilient modules have some additional symbols.
if (!VD->isResilient()) {
// Non-global variables might have an explicit initializer symbol, in
// non-resilient modules.
if (VD->getAttrs().hasAttribute<HasInitialValueAttr>() &&
!isGlobalOrStaticVar(VD)) {
auto declRef = SILDeclRef(VD, SILDeclRef::Kind::StoredPropertyInitializer);
// Stored property initializers for public properties are currently
// public.
addSymbol(declRef);
}
// statically/globally stored variables have some special handling.
if (VD->hasStorage() &&
isGlobalOrStaticVar(VD)) {
if (getDeclLinkage(VD) == FormalLinkage::PublicUnique) {
// The actual variable has a symbol.
Mangle::ASTMangler mangler;
addSymbol(mangler.mangleEntity(VD, false));
}
if (VD->isLazilyInitializedGlobal())
addSymbol(SILDeclRef(VD, SILDeclRef::Kind::GlobalAccessor));
}
}
visitAbstractStorageDecl(VD);
}
void TBDGenVisitor::visitNominalTypeDecl(NominalTypeDecl *NTD) {
auto declaredType = NTD->getDeclaredType()->getCanonicalType();
addSymbol(LinkEntity::forNominalTypeDescriptor(NTD));
// Generic types do not get metadata directly, only through the function.
if (!NTD->isGenericContext()) {
addSymbol(LinkEntity::forTypeMetadata(declaredType,
TypeMetadataAddress::AddressPoint));
}
addSymbol(LinkEntity::forTypeMetadataAccessFunction(declaredType));
// There are symbols associated with any protocols this type conforms to.
addConformances(NTD);
for (auto member : NTD->getMembers())
visit(member);
}
void TBDGenVisitor::visitClassDecl(ClassDecl *CD) {
if (getDeclLinkage(CD) != FormalLinkage::PublicUnique)
return;
auto &ctxt = CD->getASTContext();
auto isGeneric = CD->isGenericContext();
auto objCCompatible = ctxt.LangOpts.EnableObjCInterop && !isGeneric;
auto isObjC = objCCompatible && CD->isObjC();
// Metaclasses and ObjC class (duh) are a ObjC thing, and so are not needed in
// build artifacts/for classes which can't touch ObjC.
if (objCCompatible) {
bool addObjCClass = false;
if (isObjC) {
addObjCClass = true;
addSymbol(LinkEntity::forObjCClass(CD));
}
if (CD->getMetaclassKind() == ClassDecl::MetaclassKind::ObjC) {
addObjCClass = true;
addSymbol(LinkEntity::forObjCMetaclass(CD));
} else
addSymbol(LinkEntity::forSwiftMetaclassStub(CD));
if (addObjCClass) {
SmallString<128> buffer;
addSymbol(CD->getObjCRuntimeName(buffer), SymbolKind::ObjectiveCClass);
}
}
// Some members of classes get extra handling, beyond members of struct/enums,
// so let's walk over them manually.
for (auto *member : CD->getMembers()) {
auto value = dyn_cast<ValueDecl>(member);
if (!value)
continue;
auto var = dyn_cast<VarDecl>(value);
auto hasFieldOffset = var && var->hasStorage() && !var->isStatic();
if (hasFieldOffset)
addSymbol(LinkEntity::forFieldOffset(var));
}
visitNominalTypeDecl(CD);
bool resilientAncestry = CD->checkAncestry(AncestryFlags::ResilientOther);
// Types with resilient superclasses have some extra symbols.
if (resilientAncestry || CD->hasResilientMetadata()) {
addSymbol(LinkEntity::forClassMetadataBaseOffset(CD));
}
auto &Ctx = CD->getASTContext();
if (Ctx.LangOpts.EnableObjCInterop) {
if (resilientAncestry) {
addSymbol(LinkEntity::forObjCResilientClassStub(
CD, TypeMetadataAddress::AddressPoint));
}
}
// Emit dispatch thunks for every new vtable entry.
struct VTableVisitor : public SILVTableVisitor<VTableVisitor> {
TBDGenVisitor &TBD;
ClassDecl *CD;
bool FirstTime = true;
public:
VTableVisitor(TBDGenVisitor &TBD, ClassDecl *CD)
: TBD(TBD), CD(CD) {}
void addMethod(SILDeclRef method) {
assert(method.getDecl()->getDeclContext() == CD);
if (CD->hasResilientMetadata()) {
if (FirstTime) {
FirstTime = false;
// If the class is itself resilient and has at least one vtable entry,
// it has a method lookup function.
TBD.addSymbol(LinkEntity::forMethodLookupFunction(CD));
}
TBD.addDispatchThunk(method);
}
TBD.addMethodDescriptor(method);
}
void addMethodOverride(SILDeclRef baseRef, SILDeclRef derivedRef) {}
void addPlaceholder(MissingMemberDecl *) {}
void doIt() {
addVTableEntries(CD);
}
};
VTableVisitor(*this, CD).doIt();
}
void TBDGenVisitor::visitConstructorDecl(ConstructorDecl *CD) {
if (CD->getParent()->getSelfClassDecl()) {
// Class constructors come in two forms, allocating and non-allocating. The
// default ValueDecl handling gives the allocating one, so we have to
// manually include the non-allocating one.
addSymbol(SILDeclRef(CD, SILDeclRef::Kind::Initializer));
}
visitAbstractFunctionDecl(CD);
}
void TBDGenVisitor::visitDestructorDecl(DestructorDecl *DD) {
// Class destructors come in two forms (deallocating and non-deallocating),
// like constructors above. This is the deallocating one:
visitAbstractFunctionDecl(DD);
auto parentClass = DD->getParent()->getSelfClassDecl();
// But the non-deallocating one doesn't apply to some @objc classes.
if (!Lowering::usesObjCAllocator(parentClass)) {
addSymbol(SILDeclRef(DD, SILDeclRef::Kind::Destroyer));
}
}
void TBDGenVisitor::visitExtensionDecl(ExtensionDecl *ED) {
if (!isa<ProtocolDecl>(ED->getExtendedNominal())) {
addConformances(ED);
}
for (auto member : ED->getMembers())
visit(member);
}
/// Determine whether the protocol descriptor for the given protocol will
/// contain any protocol requirements.
static bool protocolDescriptorHasRequirements(ProtocolDecl *proto) {
if (!proto->getRequirementSignature().empty())
return true;
for (auto *member : proto->getMembers()) {
if (auto func = dyn_cast<AbstractFunctionDecl>(member)) {
if (SILDeclRef::requiresNewWitnessTableEntry(func))
return true;
}
if (auto assocType = dyn_cast<AssociatedTypeDecl>(member)) {
if (assocType->getOverriddenDecls().empty()) {
return true;
}
}
}
return false;
}
#ifndef NDEBUG
static bool isValidProtocolMemberForTBDGen(const Decl *D) {
switch (D->getKind()) {
case DeclKind::TypeAlias:
case DeclKind::AssociatedType:
case DeclKind::Var:
case DeclKind::Subscript:
case DeclKind::PatternBinding:
case DeclKind::Func:
case DeclKind::Accessor:
case DeclKind::Constructor:
case DeclKind::Destructor:
case DeclKind::IfConfig:
case DeclKind::PoundDiagnostic:
return true;
case DeclKind::OpaqueType:
case DeclKind::Enum:
case DeclKind::Struct:
case DeclKind::Class:
case DeclKind::Protocol:
case DeclKind::GenericTypeParam:
case DeclKind::Module:
case DeclKind::Param:
case DeclKind::EnumElement:
case DeclKind::Extension:
case DeclKind::TopLevelCode:
case DeclKind::Import:
case DeclKind::PrecedenceGroup:
case DeclKind::MissingMember:
case DeclKind::EnumCase:
case DeclKind::InfixOperator:
case DeclKind::PrefixOperator:
case DeclKind::PostfixOperator:
return false;
}
}
#endif
void TBDGenVisitor::visitProtocolDecl(ProtocolDecl *PD) {
if (!PD->isObjC()) {
addSymbol(LinkEntity::forProtocolDescriptor(PD));
// If there are any requirements, emit a requirements base descriptor.
if (protocolDescriptorHasRequirements(PD))
addProtocolRequirementsBaseDescriptor(PD);
for (const auto &req : PD->getRequirementSignature()) {
if (req.getKind() != RequirementKind::Conformance)
continue;
if (req.getFirstType()->isEqual(PD->getSelfInterfaceType())) {
BaseConformance conformance(
PD,
req.getSecondType()->castTo<ProtocolType>()->getDecl());
addBaseConformanceDescriptor(conformance);
} else {
AssociatedConformance conformance(
PD,
req.getFirstType()->getCanonicalType(),
req.getSecondType()->castTo<ProtocolType>()->getDecl());
addAssociatedConformanceDescriptor(conformance);
}
}
for (auto *member : PD->getMembers()) {
if (PD->isResilient()) {
if (auto *funcDecl = dyn_cast<AbstractFunctionDecl>(member)) {
if (SILDeclRef::requiresNewWitnessTableEntry(funcDecl)) {
addDispatchThunk(SILDeclRef(funcDecl));
addMethodDescriptor(SILDeclRef(funcDecl));
}
}
}
// Always produce associated type descriptors, because they can
// be referenced by generic signatures.
if (auto *assocType = dyn_cast<AssociatedTypeDecl>(member)) {
if (assocType->getOverriddenDecls().empty())
addAssociatedTypeDescriptor(assocType);
}
}
// Include the self-conformance.
addConformances(PD);
}
#ifndef NDEBUG
// There's no (currently) relevant information about members of a protocol at
// individual protocols, each conforming type has to handle them individually
// (NB. anything within an active IfConfigDecls also appears outside). Let's
// assert this fact:
for (auto *member : PD->getMembers()) {
assert(isValidProtocolMemberForTBDGen(member) &&
"unexpected member of protocol during TBD generation");
}
#endif
}
void TBDGenVisitor::visitEnumDecl(EnumDecl *ED) {
visitNominalTypeDecl(ED);
if (!ED->isResilient())
return;
// Emit resilient tags.
for (auto *elt : ED->getAllElements()) {
auto entity = LinkEntity::forEnumCase(elt);
addSymbol(entity);
}
}
void TBDGenVisitor::addFirstFileSymbols() {
if (!Opts.ModuleLinkName.empty()) {
SmallString<32> buf;
addSymbol(irgen::encodeForceLoadSymbolName(buf, Opts.ModuleLinkName));
}
}
/// Converts a version tuple into a packed version, ignoring components beyond
/// major, minor, and subminor.
static tapi::internal::PackedVersion
convertToPacked(const version::Version &version) {
// FIXME: Warn if version is greater than 3 components?
unsigned major = 0, minor = 0, subminor = 0;
if (version.size() > 0) major = version[0];
if (version.size() > 1) minor = version[1];
if (version.size() > 2) subminor = version[2];
return tapi::internal::PackedVersion(major, minor, subminor);
}
static bool isApplicationExtensionSafe(const LangOptions &LangOpts) {
return LangOpts.EnableAppExtensionRestrictions;
}
static void enumeratePublicSymbolsAndWrite(ModuleDecl *M, FileUnit *singleFile,
StringSet *symbols,
llvm::raw_ostream *os,
const TBDGenOptions &opts) {
auto &ctx = M->getASTContext();
auto isWholeModule = singleFile == nullptr;
const auto &target = ctx.LangOpts.Target;
UniversalLinkageInfo linkInfo(target, opts.HasMultipleIGMs, false,
isWholeModule);
auto availCtx = AvailabilityContext::forDeploymentTarget(ctx);
tapi::internal::InterfaceFile file;
file.setFileType(tapi::internal::FileType::TBD_V3);
file.setApplicationExtensionSafe(
isApplicationExtensionSafe(M->getASTContext().LangOpts));
file.setInstallName(opts.InstallName);
file.setCurrentVersion(convertToPacked(opts.CurrentVersion));
file.setCompatibilityVersion(convertToPacked(opts.CompatibilityVersion));
file.setTwoLevelNamespace();
file.setSwiftABIVersion(TAPI_SWIFT_ABI_VERSION);
file.setPlatform(tapi::internal::mapToSinglePlatform(target));
auto arch = tapi::internal::getArchType(target.getArchName());
file.setArch(arch);
file.setInstallAPI();
TBDGenVisitor visitor(file, arch, symbols, linkInfo, M, availCtx, opts);
auto visitFile = [&](FileUnit *file) {
if (file == M->getFiles()[0]) {
visitor.addFirstFileSymbols();
}
SmallVector<Decl *, 16> decls;
file->getTopLevelDecls(decls);
visitor.addMainIfNecessary(file);
for (auto d : decls)
visitor.visit(d);
};
if (singleFile) {
assert(M == singleFile->getParentModule() && "mismatched file and module");
visitFile(singleFile);
} else {
for (auto *file : M->getFiles()) {
visitFile(file);
}
}
if (os) {
tapi::internal::YAMLWriter writer;
writer.add(
llvm::make_unique<tapi::internal::stub::v3::YAMLDocumentHandler>());
assert(writer.canWrite(&file) &&
"YAML writer should be able to write TBD v3");
llvm::cantFail(writer.writeFile(*os, &file),
"YAML writing should be error-free");
}
}
void swift::enumeratePublicSymbols(FileUnit *file, StringSet &symbols,
const TBDGenOptions &opts) {
enumeratePublicSymbolsAndWrite(file->getParentModule(), file, &symbols,
nullptr, opts);
}
void swift::enumeratePublicSymbols(ModuleDecl *M, StringSet &symbols,
const TBDGenOptions &opts) {
enumeratePublicSymbolsAndWrite(M, nullptr, &symbols, nullptr, opts);
}
void swift::writeTBDFile(ModuleDecl *M, llvm::raw_ostream &os,
const TBDGenOptions &opts) {
enumeratePublicSymbolsAndWrite(M, nullptr, nullptr, &os, opts);
}