Files
swift-mirror/include/swift/AST/FileUnit.h
Allan Shortlidge 4841bcffa1 ModuleInterface: Print imports with @preconcurrency in swiftinterface files.
When a module has been imported `@preconcurrency` in source, when it is printed
in a `swiftinterface` file it should be printed along with the attribute to
ensure that type checking of the module's public declarations behaves
consistently.

This fix is a little unsatisfying because it adds another a linear scan over
all imports in the source for each printed import. This should be improved, but
it can be done later.

Resolves rdar://136857313.
2025-09-15 17:33:13 -07:00

513 lines
18 KiB
C++

//===--- FileUnit.h - The contents of a module ------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 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
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_AST_FILEUNIT_H
#define SWIFT_AST_FILEUNIT_H
#include "swift/AST/Module.h"
#include "swift/AST/RawComment.h"
#include "swift/Basic/BasicSourceInfo.h"
#include "swift/Basic/Debug.h"
#include "swift/Basic/Version.h"
#include "llvm/ADT/PointerIntPair.h"
namespace swift {
class SynthesizedFileUnit;
/// A container for module-scope declarations that itself provides a scope; the
/// smallest unit of code organization.
///
/// FileUnit is an abstract base class; its subclasses represent different
/// sorts of containers that can each provide a set of decls, e.g. a source
/// file. A module can contain several file-units.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
class FileUnit : public DeclContext, public ASTAllocated<FileUnit> {
#pragma clang diagnostic pop
virtual void anchor();
friend class DirectOperatorLookupRequest;
friend class DirectPrecedenceGroupLookupRequest;
/// The pointer is FileUnit insted of SynthesizedFileUnit to break
/// circularity.
llvm::PointerIntPair<FileUnit *, 3, FileUnitKind> SynthesizedFileAndKind;
protected:
FileUnit(FileUnitKind kind, ModuleDecl &M)
: DeclContext(DeclContextKind::FileUnit, &M),
SynthesizedFileAndKind(nullptr, kind) {
}
public:
FileUnitKind getKind() const {
return SynthesizedFileAndKind.getInt();
}
/// Returns the synthesized file for this source file, if it exists.
SynthesizedFileUnit *getSynthesizedFile() const;
/// Returns the synthesized file for this source file, creating one and
/// inserting it into the module if it does not exist.
SynthesizedFileUnit &getOrCreateSynthesizedFile();
/// Look up a (possibly overloaded) value set at top-level scope
/// (but with the specified access path, which may come from an import decl)
/// within this file.
///
/// This does a simple local lookup, not recursively looking through imports.
virtual void lookupValue(DeclName name, NLKind lookupKind,
OptionSet<ModuleLookupFlags> Flags,
SmallVectorImpl<ValueDecl*> &result) const = 0;
/// Look up a local type declaration by its mangled name.
///
/// This does a simple local lookup, not recursively looking through imports.
virtual TypeDecl *lookupLocalType(StringRef MangledName) const {
return nullptr;
}
/// Look up an opaque return type by the mangled name of the declaration
/// that defines it.
virtual OpaqueTypeDecl *lookupOpaqueResultType(StringRef MangledName) {
return nullptr;
}
/// Directly look for a nested type declared within this module inside the
/// given nominal type (including any extensions).
///
/// This is a fast-path hack to avoid circular dependencies in deserialization
/// and the Clang importer.
///
/// Private and fileprivate types should not be returned by this lookup.
virtual TypeDecl *lookupNestedType(Identifier name,
const NominalTypeDecl *parent) const {
return nullptr;
}
/// Find ValueDecls in the module and pass them to the given consumer object.
///
/// This does a simple local lookup, not recursively looking through imports.
virtual void lookupVisibleDecls(ImportPath::Access accessPath,
VisibleDeclConsumer &consumer,
NLKind lookupKind) const {}
/// Finds all class members defined in this file.
///
/// This does a simple local lookup, not recursively looking through imports.
virtual void lookupClassMembers(ImportPath::Access accessPath,
VisibleDeclConsumer &consumer) const {}
/// Finds class members defined in this file with the given name.
///
/// This does a simple local lookup, not recursively looking through imports.
virtual void lookupClassMember(ImportPath::Access accessPath,
DeclName name,
SmallVectorImpl<ValueDecl*> &results) const {}
/// Find all Objective-C methods with the given selector.
virtual void lookupObjCMethods(
ObjCSelector selector,
SmallVectorImpl<AbstractFunctionDecl *> &results) const = 0;
/// Find all SPI names imported from \p importedModule by this module,
/// collecting the identifiers in \p spiGroups.
virtual void lookupImportedSPIGroups(
const ModuleDecl *importedModule,
llvm::SmallSetVector<Identifier, 4> &spiGroups) const {};
/// Returns true if any import of \p importedModule has the `@preconcurrency`
/// attribute.
virtual bool
isModuleImportedPreconcurrency(const ModuleDecl *importedModule) const {
return false;
};
/// Find all availability domains defined in this module with the given
/// identifier.
///
/// This does a simple local lookup, not recursively looking through imports.
virtual void lookupAvailabilityDomains(
Identifier identifier,
SmallVectorImpl<AvailabilityDomain> &results) const {};
virtual std::optional<Fingerprint>
loadFingerprint(const IterableDeclContext *IDC) const {
return std::nullopt;
}
protected:
/// Look up an operator declaration. Do not call directly, use
/// \c DirectOperatorLookupRequest instead.
///
/// \param name The operator name ("+", ">>", etc.)
///
/// \param fixity One of Prefix, Infix, or Postfix.
virtual void
lookupOperatorDirect(Identifier name, OperatorFixity fixity,
TinyPtrVector<OperatorDecl *> &results) const {}
/// Look up a precedence group. Do not call directly, use
/// \c DirectPrecedenceGroupLookupRequest instead.
///
/// \param name The precedence group name.
virtual void lookupPrecedenceGroupDirect(
Identifier name, TinyPtrVector<PrecedenceGroupDecl *> &results) const {}
public:
/// Returns the comment attached to the given declaration.
///
/// This function is an implementation detail for comment serialization.
/// If you just want to get a comment attached to a decl, use
/// \c Decl::getRawComment() or \c Decl::getSemanticBriefComment().
virtual std::optional<CommentInfo> getCommentForDecl(const Decl *D) const {
return std::nullopt;
}
/// For a serialized AST file, returns \c true if an adjacent swiftdoc has been
/// loaded. Otherwise, returns \c false.
virtual bool hasLoadedSwiftDoc() const { return false; }
virtual std::optional<StringRef> getGroupNameForDecl(const Decl *D) const {
return std::nullopt;
}
virtual std::optional<StringRef>
getSourceFileNameForDecl(const Decl *D) const {
return std::nullopt;
}
virtual std::optional<unsigned> getSourceOrderForDecl(const Decl *D) const {
return std::nullopt;
}
virtual std::optional<StringRef> getGroupNameByUSR(StringRef USR) const {
return std::nullopt;
}
virtual std::optional<ExternalSourceLocs::RawLocs>
getExternalRawLocsForDecl(const Decl *D) const {
return std::nullopt;
}
virtual void collectAllGroups(SmallVectorImpl<StringRef> &Names) const {}
/// Returns an implementation-defined "discriminator" for \p D, which
/// distinguishes \p D from other declarations in the same module with the
/// same name.
///
/// Since this value is used in name mangling, it should be a valid ASCII-only
/// identifier.
virtual Identifier
getDiscriminatorForPrivateDecl(const Decl *D) const = 0;
/// Finds all top-level decls in this file.
///
/// This does a simple local lookup, not recursively looking through imports.
/// The order of the results is not guaranteed to be meaningful.
virtual void getTopLevelDecls(SmallVectorImpl<Decl*> &results) const {}
/// Finds all top-level decls in this file with their auxiliary decls such as
/// macro expansions.
///
/// This does a simple local lookup, not recursively looking through imports.
/// The order of the results is not guaranteed to be meaningful.
void getTopLevelDeclsWithAuxiliaryDecls(
SmallVectorImpl<Decl*> &results) const;
virtual void
getExportedPrespecializations(SmallVectorImpl<Decl *> &results) const {}
/// Finds top-level decls in this file filtered by their attributes.
///
/// This does a simple local lookup, not recursively looking through imports.
/// The order of the results is not guaranteed to be meaningful.
///
/// \param Results Vector collecting the decls.
///
/// \param matchAttributes Check on the attributes of a decl to keep only
/// decls with matching attributes. The subclass SerializedASTFile checks the
/// attributes first to only deserialize decls with accepted attributes,
/// limiting deserialization work.
virtual void
getTopLevelDeclsWhereAttributesMatch(
SmallVectorImpl<Decl*> &Results,
llvm::function_ref<bool(DeclAttributes)> matchAttributes) const;
/// Finds all operator decls in this file.
///
/// This does a simple local lookup, not recursively looking through imports.
/// The order of the results is not guaranteed to be meaningful.
virtual void
getOperatorDecls(SmallVectorImpl<OperatorDecl *> &results) const {}
/// Finds all precedence group decls in this file.
///
/// This does a simple local lookup, not recursively looking through imports.
/// The order of the results is not guaranteed to be meaningful.
virtual void
getPrecedenceGroups(SmallVectorImpl<PrecedenceGroupDecl*> &Results) const {}
/// Finds all local type decls in this file.
///
/// This does a simple local lookup, not recursively looking through imports.
/// The order of the results is not guaranteed to be meaningful.
virtual void getLocalTypeDecls(SmallVectorImpl<TypeDecl*> &results) const {}
virtual void
getOpaqueReturnTypeDecls(SmallVectorImpl<OpaqueTypeDecl*> &results) const {}
/// Adds all top-level decls to the given vector.
///
/// This includes all decls that should be displayed to clients of the module.
/// The order of the results is not guaranteed to be meaningful.
///
/// This can differ from \c getTopLevelDecls, e.g. it returns decls from a
/// shadowed clang module.
virtual void getDisplayDecls(SmallVectorImpl<Decl*> &results, bool recursive = false) const {
getTopLevelDecls(results);
}
/// Looks up which modules are imported by this file.
///
/// \p filter controls whether public, private, or any imports are included
/// in this list.
virtual void
getImportedModules(SmallVectorImpl<ImportedModule> &imports,
ModuleDecl::ImportFilter filter) const {}
/// Looks up which external macros are defined by this file.
virtual void
getExternalMacros(SmallVectorImpl<ExternalMacroPlugin> &macros) const {}
/// Lists modules that are not imported from this file and used in API.
virtual void getImplicitImportsForModuleInterface(
SmallVectorImpl<ImportedModule> &imports) const {}
/// \see ModuleDecl::getImportedModulesForLookup
virtual void getImportedModulesForLookup(
SmallVectorImpl<ImportedModule> &imports) const {
return getImportedModules(imports, ModuleDecl::ImportFilterKind::Exported);
}
/// Generates the list of libraries needed to link this file, based on its
/// imports.
virtual void
collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const {}
/// Load extra dependencies of this module to satisfy a testable import.
virtual void loadDependenciesForTestable(SourceLoc diagLoc) const {}
/// Returns the path of the file or directory that defines the module
/// represented by this \c FileUnit, or empty string if there is none.
/// Cross-import overlay specifiers are found relative to this path.
virtual StringRef getModuleDefiningPath() const {
return "";
}
/// True if this file contains the main class for the module.
bool hasMainClass() const {
return getMainClass();
}
ClassDecl *getMainClass() const {
return dyn_cast_or_null<ClassDecl>(getMainDecl());
}
bool hasMainDecl() const { return getMainDecl(); }
virtual ValueDecl *getMainDecl() const { return nullptr; }
FuncDecl *getMainFunc() const {
return dyn_cast_or_null<FuncDecl>(getMainDecl());
}
virtual bool hasEntryPoint() const {
return false;
}
virtual ModuleDecl *getUnderlyingModuleIfOverlay() const {
return nullptr;
}
/// Returns the associated clang module if one exists.
virtual const clang::Module *getUnderlyingClangModule() const {
return nullptr;
}
/// Returns the real name of the enclosing module to use when referencing entities in this file.
/// The 'real name' is the actual binary name of the module, which can be different from the 'name'
/// if module aliasing was used (via -module-alias flag).
///
/// This is usually the module real name which can be overriden by an
/// `export_as` definition of a clang module, or `-export-as` flag on an
/// imported Swift module. Swift modules built from source do not apply
/// their own `-export-as` flag, this way the swiftinterface can be
/// verified.
virtual StringRef getExportedModuleName() const {
return getParentModule()->getRealName().str();
}
/// Returns the public facing name of this module, only if it is set
/// explicitly.
virtual StringRef getPublicModuleName() const {
return {};
}
/// Returns the version of the Swift compiler used to create generate
/// .swiftinterface file if this file is produced from one.
virtual version::Version getSwiftInterfaceCompilerVersion() const {
return {};
}
SWIFT_DEBUG_DUMPER(dumpDisplayDecls());
SWIFT_DEBUG_DUMPER(dumpTopLevelDecls());
/// Traverse the decls within this file.
///
/// \returns true if traversal was aborted, false if it completed
/// successfully.
virtual bool walk(ASTWalker &walker);
// Efficiency override for DeclContext::getParentModule().
ModuleDecl *getParentModule() const {
return const_cast<ModuleDecl *>(cast<ModuleDecl>(getParent()));
}
static bool classof(const DeclContext *DC) {
return DC->getContextKind() == DeclContextKind::FileUnit;
}
using ASTAllocated<FileUnit>::operator new;
using ASTAllocated<FileUnit>::operator delete;
};
/// This represents the compiler's implicitly generated declarations in the
/// Builtin module.
class BuiltinUnit final : public FileUnit {
public:
class LookupCache;
private:
std::unique_ptr<LookupCache> Cache;
LookupCache &getCache() const;
friend ASTContext;
~BuiltinUnit() = default;
public:
explicit BuiltinUnit(ModuleDecl &M);
virtual void lookupValue(DeclName name, NLKind lookupKind,
OptionSet<ModuleLookupFlags> Flags,
SmallVectorImpl<ValueDecl*> &result) const override;
/// Find all Objective-C methods with the given selector.
void lookupObjCMethods(
ObjCSelector selector,
SmallVectorImpl<AbstractFunctionDecl *> &results) const override;
Identifier
getDiscriminatorForPrivateDecl(const Decl *D) const override {
llvm_unreachable("no private values in the Builtin module");
}
static bool classof(const FileUnit *file) {
return file->getKind() == FileUnitKind::Builtin;
}
static bool classof(const DeclContext *DC) {
return isa<FileUnit>(DC) && classof(cast<FileUnit>(DC));
}
};
/// Represents an externally-loaded file of some kind.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
class LoadedFile : public FileUnit {
#pragma clang diagnostic pop
protected:
LoadedFile(FileUnitKind Kind, ModuleDecl &M) noexcept
: FileUnit(Kind, M) {
assert(classof(this) && "invalid kind");
}
public:
/// Returns the language version that was used to compile the contents of this
/// file. An empty `Version` is returned if the information is not available.
virtual version::Version getLanguageVersionBuiltWith() const = 0;
/// Returns an arbitrary string representing the storage backing this file.
///
/// This is usually a filesystem path.
virtual StringRef getFilename() const;
/// Get the path to the file loaded by the compiler. Usually the binary
/// swiftmodule file or a pcm in the cache. Returns an empty string if not
/// applicable.
virtual StringRef getLoadedFilename() const { return StringRef(); }
/// Returns the path of the file for the module represented by this
/// \c FileUnit, or an empty string if there is none. For modules either
/// built by or adjacent to a module interface, returns the module
/// interface instead.
virtual StringRef getSourceFilename() const {
return getModuleDefiningPath();
}
virtual StringRef getFilenameForPrivateDecl(const Decl *decl) const {
return StringRef();
}
/// Returns the Swift module that overlays a Clang module.
virtual ModuleDecl *getOverlayModule() const { return nullptr; }
virtual bool isSystemModule() const { return false; }
/// Checks whether an error was encountered while loading the file.
virtual bool hadLoadError() const { return false; }
/// Retrieve the set of generic signatures stored within this module.
///
/// \returns \c true if this module file supports retrieving all of the
/// generic signatures, \c false otherwise.
virtual bool getAllGenericSignatures(
SmallVectorImpl<GenericSignature> &genericSignatures) {
return false;
}
virtual void collectBasicSourceFileInfo(
llvm::function_ref<void(const BasicSourceFileInfo &)> callback) const {}
virtual void collectSerializedSearchPath(
llvm::function_ref<void(StringRef)> callback) const {}
static bool classof(const FileUnit *file) {
return file->getKind() == FileUnitKind::SerializedAST ||
file->getKind() == FileUnitKind::ClangModule ||
file->getKind() == FileUnitKind::DWARFModule;
}
static bool classof(const DeclContext *DC) {
return isa<FileUnit>(DC) && classof(cast<FileUnit>(DC));
}
};
void simple_display(llvm::raw_ostream &out, const FileUnit *file);
inline FileUnit &ModuleDecl::getMainFile(FileUnitKind expectedKind) const {
assert(expectedKind != FileUnitKind::Source &&
"must use specific source kind; see getMainSourceFile");
auto files = getFiles();
assert(!files.empty() && "No files in module");
assert(files.front()->getKind() == expectedKind);
return *files.front();
}
} // end namespace swift
#endif