Files
swift-mirror/include/swift/AST/Module.h
Robert Widmann 0d117c1345 Don't Mutate ModuleDecl's File List When Creating Synthesized Files
See #59144 for more on why this is a bad idea.

Patch out the synthesized file unit accessor to only clear the source cache, then patch up all the places that were assuming they could iterate over the module's file list and see synthesized files.

rdar://94164512
2022-06-11 11:07:05 -06:00

964 lines
36 KiB
C++

//===--- Module.h - Swift Language Module ASTs ------------------*- C++ -*-===//
//
// 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 defines the Module class and its subclasses.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_MODULE_H
#define SWIFT_MODULE_H
#include "swift/AST/AccessNotes.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DeclContext.h"
#include "swift/AST/Identifier.h"
#include "swift/AST/Import.h"
#include "swift/AST/LookupKinds.h"
#include "swift/AST/Type.h"
#include "swift/Basic/BasicSourceInfo.h"
#include "swift/Basic/Compiler.h"
#include "swift/Basic/Debug.h"
#include "swift/Basic/OptionSet.h"
#include "swift/Basic/STLExtras.h"
#include "swift/Basic/SourceLoc.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MD5.h"
#include <set>
namespace clang {
class Module;
}
namespace swift {
enum class ArtificialMainKind : uint8_t;
class ASTContext;
class ASTWalker;
class BraceStmt;
class Decl;
class DeclAttribute;
class TypeDecl;
enum class DeclKind : uint8_t;
class ExtensionDecl;
class DebuggerClient;
class DeclName;
class FileUnit;
class FuncDecl;
class InfixOperatorDecl;
enum class LibraryLevel : uint8_t;
class LinkLibrary;
class ModuleLoader;
class NominalTypeDecl;
class EnumElementDecl;
class OperatorDecl;
class PostfixOperatorDecl;
class PrefixOperatorDecl;
class ProtocolConformance;
class ProtocolDecl;
struct PrintOptions;
class Token;
class TupleType;
class Type;
class TypeRefinementContext;
class ValueDecl;
class VarDecl;
class VisibleDeclConsumer;
class SyntaxParsingCache;
class ASTScope;
class SourceLookupCache;
namespace syntax {
class SourceFileSyntax;
}
namespace ast_scope {
class ASTSourceFileScope;
}
/// Discriminator for file-units.
enum class FileUnitKind {
/// For a .swift source file.
Source,
/// For the compiler Builtin module.
Builtin,
/// A serialized Swift AST.
SerializedAST,
/// A synthesized file.
Synthesized,
/// An imported Clang module.
ClangModule,
/// A Clang module imported from DWARF.
DWARFModule
};
enum class SourceFileKind {
Library, ///< A normal .swift file.
Main, ///< A .swift file that can have top-level code.
SIL, ///< Came from a .sil file.
Interface ///< Came from a .swiftinterface file, representing another module.
};
/// Contains information about where a particular path is used in
/// \c SourceFiles.
struct SourceFilePathInfo {
struct Comparator {
bool operator () (SourceLoc lhs, SourceLoc rhs) const {
return lhs.getOpaquePointerValue() <
rhs.getOpaquePointerValue();
}
};
SourceLoc physicalFileLoc{};
std::set<SourceLoc, Comparator> virtualFileLocs{}; // std::set for sorting
SourceFilePathInfo() = default;
void merge(const SourceFilePathInfo &other) {
if (other.physicalFileLoc.isValid()) {
assert(!physicalFileLoc.isValid());
physicalFileLoc = other.physicalFileLoc;
}
for (auto &elem : other.virtualFileLocs) {
virtualFileLocs.insert(elem);
}
}
bool operator == (const SourceFilePathInfo &other) const {
return physicalFileLoc == other.physicalFileLoc &&
virtualFileLocs == other.virtualFileLocs;
}
};
/// Discriminator for resilience strategy.
enum class ResilienceStrategy : unsigned {
/// Public nominal types: fragile
/// Non-inlinable function bodies: resilient
///
/// This is the default behavior without any flags.
Default,
/// Public nominal types: resilient
/// Non-inlinable function bodies: resilient
///
/// This is the behavior with -enable-library-evolution.
Resilient
};
class OverlayFile;
/// The minimum unit of compilation.
///
/// A module is made up of several file-units, which are all part of the same
/// output binary and logical module (such as a single library or executable).
///
/// \sa FileUnit
class ModuleDecl
: public DeclContext, public TypeDecl, public ASTAllocated<ModuleDecl> {
friend class DirectOperatorLookupRequest;
friend class DirectPrecedenceGroupLookupRequest;
/// The ABI name of the module, if it differs from the module name.
mutable Identifier ModuleABIName;
public:
/// Produces the components of a given module's full name in reverse order.
///
/// For a Swift module, this will only ever have one component, but an
/// imported Clang module might actually be a submodule.
///
/// *Note: see `StringRef operator*()` for details on the returned name for printing
/// for a Swift module.
class ReverseFullNameIterator {
public:
// Make this look like a valid STL iterator.
using difference_type = int;
using value_type = StringRef;
using pointer = StringRef *;
using reference = StringRef;
using iterator_category = std::forward_iterator_tag;
private:
PointerUnion<const ModuleDecl *, const /* clang::Module */ void *> current;
public:
ReverseFullNameIterator() = default;
explicit ReverseFullNameIterator(const ModuleDecl *M);
explicit ReverseFullNameIterator(const clang::Module *clangModule) {
current = clangModule;
}
/// Returns the name of the current module.
/// Note that for a Swift module, it returns the current module's real (binary) name,
/// which can be different from the name if module aliasing was used (see `-module-alias`).
StringRef operator*() const;
ReverseFullNameIterator &operator++();
friend bool operator==(ReverseFullNameIterator left,
ReverseFullNameIterator right) {
return left.current == right.current;
}
friend bool operator!=(ReverseFullNameIterator left,
ReverseFullNameIterator right) {
return !(left == right);
}
/// This is a convenience function that writes the entire name, in forward
/// order, to \p out.
///
/// It calls `StringRef operator*()` under the hood (see for more detail on the
/// returned name for a Swift module).
void printForward(raw_ostream &out, StringRef delim = ".") const;
};
private:
/// If non-NULL, a plug-in that should be used when performing external
/// lookups.
// FIXME: Do we really need to bloat all modules with this?
DebuggerClient *DebugClient = nullptr;
SmallVector<FileUnit *, 2> Files;
llvm::SmallDenseMap<Identifier, SmallVector<OverlayFile *, 1>>
declaredCrossImports;
/// A description of what should be implicitly imported by each file of this
/// module.
const ImplicitImportInfo ImportInfo;
std::unique_ptr<SourceLookupCache> Cache;
SourceLookupCache &getSourceLookupCache() const;
/// Tracks the file that will generate the module's entry point, either
/// because it contains a class marked with \@UIApplicationMain
/// or \@NSApplicationMain, or because it is a script file.
class EntryPointInfoTy {
enum class Flags {
DiagnosedMultipleMainClasses = 1 << 0,
DiagnosedMainClassWithScript = 1 << 1
};
llvm::PointerIntPair<FileUnit *, 2, OptionSet<Flags>> storage;
public:
EntryPointInfoTy() = default;
FileUnit *getEntryPointFile() const;
void setEntryPointFile(FileUnit *file);
bool hasEntryPoint() const;
bool markDiagnosedMultipleMainClasses();
bool markDiagnosedMainClassWithScript();
};
/// Information about the file responsible for the module's entry point,
/// if any.
///
/// \see EntryPointInfoTy
EntryPointInfoTy EntryPointInfo;
AccessNotesFile accessNotes;
/// Used by the debugger to bypass resilient access to fields.
bool BypassResilience = false;
ModuleDecl(Identifier name, ASTContext &ctx, ImplicitImportInfo importInfo);
public:
/// Creates a new module with a given \p name.
///
/// \param importInfo Information about which modules should be implicitly
/// imported by each file of this module.
static ModuleDecl *
create(Identifier name, ASTContext &ctx,
ImplicitImportInfo importInfo = ImplicitImportInfo()) {
return new (ctx) ModuleDecl(name, ctx, importInfo);
}
static ModuleDecl *
createMainModule(ASTContext &ctx, Identifier name, ImplicitImportInfo iinfo) {
auto *Mod = ModuleDecl::create(name, ctx, iinfo);
Mod->Bits.ModuleDecl.IsMainModule = true;
return Mod;
}
using Decl::getASTContext;
/// Retrieves information about which modules are implicitly imported by
/// each file of this module.
const ImplicitImportInfo &getImplicitImportInfo() const { return ImportInfo; }
/// Retrieve a list of modules that each file of this module implicitly
/// imports.
ImplicitImportList getImplicitImports() const;
AccessNotesFile &getAccessNotes() { return accessNotes; }
const AccessNotesFile &getAccessNotes() const { return accessNotes; }
/// Return whether the module was imported with resilience disabled. The
/// debugger does this to access private fields.
bool getBypassResilience() const { return BypassResilience; }
/// Only to be called by MemoryBufferSerializedModuleLoader.
void setBypassResilience() { BypassResilience = true; }
ArrayRef<FileUnit *> getFiles() {
assert(!Files.empty() || failedToLoad());
return Files;
}
ArrayRef<const FileUnit *> getFiles() const {
return { Files.begin(), Files.size() };
}
/// Add the given file to this module.
///
/// FIXME: Remove this function from public view. Modules never need to add
/// files once they are created.
///
/// \warning There are very few safe points to call this function once a
/// \c ModuleDecl has been created. If you find yourself needing to insert
/// a file in the middle of e.g. semantic analysis, use a \c
/// SynthesizedFileUnit instead.
void addFile(FileUnit &newFile);
/// Creates a map from \c #filePath strings to corresponding \c #fileID
/// strings, diagnosing any conflicts.
///
/// A given \c #filePath string always maps to exactly one \c #fileID string,
/// but it is possible for \c #sourceLocation directives to introduce
/// duplicates in the opposite direction. If there are such conflicts, this
/// method will diagnose the conflict and choose a "winner" among the paths
/// in a reproducible way. The \c bool paired with the \c #fileID string is
/// \c true for paths which did not have a conflict or won a conflict, and
/// \c false for paths which lost a conflict. Thus, if you want to generate a
/// reverse mapping, you should drop or special-case the \c #fileID strings
/// that are paired with \c false.
llvm::StringMap<std::pair<std::string, /*isWinner=*/bool>>
computeFileIDMap(bool shouldDiagnose) const;
/// Add a file declaring a cross-import overlay.
void addCrossImportOverlayFile(StringRef file);
/// Collect cross-import overlay names from a given YAML file path.
static llvm::SmallSetVector<Identifier, 4>
collectCrossImportOverlay(ASTContext &ctx, StringRef file,
StringRef moduleName, StringRef& bystandingModule);
/// If this method returns \c false, the module does not declare any
/// cross-import overlays.
///
/// This is a quick check you can use to bail out of expensive logic early;
/// however, a \c true return doesn't guarantee that the module declares
/// cross-import overlays--it only means that it \em might declare some.
///
/// (Specifically, this method checks if the module loader found any
/// swiftoverlay files, but does not load the files to see if they list any
/// overlay modules.)
bool mightDeclareCrossImportOverlays() const;
/// Append to \p overlayNames the names of all modules that this module
/// declares should be imported when \p bystanderName is imported.
///
/// This operation is asymmetric: you will get different results if you
/// reverse the positions of the two modules involved in the cross-import.
void findDeclaredCrossImportOverlays(
Identifier bystanderName, SmallVectorImpl<Identifier> &overlayNames,
SourceLoc diagLoc) const;
/// Get the list of all modules this module declares a cross-import with.
void getDeclaredCrossImportBystanders(
SmallVectorImpl<Identifier> &bystanderNames);
/// Retrieve the ABI name of the module, which is used for metadata and
/// mangling.
Identifier getABIName() const;
/// Set the ABI name of the module;
void setABIName(Identifier name) {
ModuleABIName = name;
}
/// Retrieve the actual module name of an alias used for this module (if any).
///
/// For example, if '-module-alias Foo=Bar' is passed in when building the main module,
/// and this module is (a) not the main module and (b) is named Foo, then it returns
/// the real (physically on-disk) module name Bar.
///
/// If no module aliasing is set, it will return getName(), i.e. Foo.
Identifier getRealName() const;
/// User-defined module version number.
llvm::VersionTuple UserModuleVersion;
void setUserModuleVersion(llvm::VersionTuple UserVer) {
UserModuleVersion = UserVer;
}
llvm::VersionTuple getUserModuleVersion() const {
return UserModuleVersion;
}
private:
/// A cache of this module's underlying module and required bystander if it's
/// an underscored cross-import overlay.
Optional<std::pair<ModuleDecl *, Identifier>> declaringModuleAndBystander;
/// If this module is an underscored cross import overlay, gets the underlying
/// module that declared it (which may itself be a cross-import overlay),
/// along with the name of the required bystander module. Used by tooling to
/// present overlays as if they were part of their underlying module.
std::pair<ModuleDecl *, Identifier> getDeclaringModuleAndBystander();
/// If this is a traditional (non-cross-import) overlay, get its underlying
/// module if one exists.
ModuleDecl *getUnderlyingModuleIfOverlay() const;
public:
/// Returns true if this module is an underscored cross import overlay
/// declared by \p other or its underlying clang module, either directly or
/// transitively (via intermediate cross-import overlays - for cross-imports
/// involving more than two modules).
bool isCrossImportOverlayOf(ModuleDecl *other);
/// If this module is an underscored cross-import overlay, returns the
/// non-underscored underlying module that declares it as an overlay, either
/// directly or transitively (via intermediate cross-import overlays - for
/// cross-imports involving more than two modules).
ModuleDecl *getDeclaringModuleIfCrossImportOverlay();
/// If this module is an underscored cross-import overlay of \p declaring or
/// its underlying clang module, either directly or transitively, populates
/// \p bystanderNames with the set of bystander modules that must be present
/// alongside \p declaring for the overlay to be imported and returns true.
/// Returns false otherwise.
bool getRequiredBystandersIfCrossImportOverlay(
ModuleDecl *declaring, SmallVectorImpl<Identifier> &bystanderNames);
/// Walks and loads the declared, underscored cross-import overlays of this
/// module and its underlying clang module, transitively, to find all cross
/// import overlays this module underlies.
///
/// This is used by tooling to present these overlays as part of this module.
void findDeclaredCrossImportOverlaysTransitive(
SmallVectorImpl<ModuleDecl *> &overlays);
/// Convenience accessor for clients that know what kind of file they're
/// dealing with.
SourceFile &getMainSourceFile() const;
/// Convenience accessor for clients that know what kind of file they're
/// dealing with.
FileUnit &getMainFile(FileUnitKind expectedKind) const;
DebuggerClient *getDebugClient() const { return DebugClient; }
void setDebugClient(DebuggerClient *R) {
assert(!DebugClient && "Debugger client already set");
DebugClient = R;
}
/// Returns true if this module is compiled as static library.
bool isStaticLibrary() const {
return Bits.ModuleDecl.StaticLibrary;
}
void setStaticLibrary(bool isStatic = true) {
Bits.ModuleDecl.StaticLibrary = isStatic;
}
/// Returns true if this module was or is being compiled for testing.
bool isTestingEnabled() const {
return Bits.ModuleDecl.TestingEnabled;
}
void setTestingEnabled(bool enabled = true) {
Bits.ModuleDecl.TestingEnabled = enabled;
}
// Returns true if this module is compiled with implicit dynamic.
bool isImplicitDynamicEnabled() const {
return Bits.ModuleDecl.ImplicitDynamicEnabled;
}
void setImplicitDynamicEnabled(bool enabled = true) {
Bits.ModuleDecl.ImplicitDynamicEnabled = enabled;
}
/// Returns true if this module was or is begin compile with
/// `-enable-private-imports`.
bool arePrivateImportsEnabled() const {
return Bits.ModuleDecl.PrivateImportsEnabled;
}
void setPrivateImportsEnabled(bool enabled = true) {
Bits.ModuleDecl.PrivateImportsEnabled = true;
}
/// Returns true if there was an error trying to load this module.
bool failedToLoad() const {
return Bits.ModuleDecl.FailedToLoad;
}
void setFailedToLoad(bool failed = true) {
Bits.ModuleDecl.FailedToLoad = failed;
}
bool hasResolvedImports() const {
return Bits.ModuleDecl.HasResolvedImports;
}
void setHasResolvedImports() {
Bits.ModuleDecl.HasResolvedImports = true;
}
ResilienceStrategy getResilienceStrategy() const {
return ResilienceStrategy(Bits.ModuleDecl.RawResilienceStrategy);
}
void setResilienceStrategy(ResilienceStrategy strategy) {
Bits.ModuleDecl.RawResilienceStrategy = unsigned(strategy);
}
/// Distribution level of the module.
LibraryLevel getLibraryLevel() const;
/// Returns true if this module was or is being compiled for testing.
bool hasIncrementalInfo() const { return Bits.ModuleDecl.HasIncrementalInfo; }
void setHasIncrementalInfo(bool enabled = true) {
Bits.ModuleDecl.HasIncrementalInfo = enabled;
}
/// Returns true if this module was built with
/// -experimental-hermetic-seal-at-link.
bool hasHermeticSealAtLink() const {
return Bits.ModuleDecl.HasHermeticSealAtLink;
}
void setHasHermeticSealAtLink(bool enabled = true) {
Bits.ModuleDecl.HasHermeticSealAtLink = enabled;
}
/// \returns true if this module is a system module; note that the StdLib is
/// considered a system module.
bool isSystemModule() const {
return Bits.ModuleDecl.IsSystemModule;
}
void setIsSystemModule(bool flag = true) {
Bits.ModuleDecl.IsSystemModule = flag;
}
/// Returns true if this module is a non-Swift module that was imported into
/// Swift.
///
/// Right now that's just Clang modules.
bool isNonSwiftModule() const {
return Bits.ModuleDecl.IsNonSwiftModule;
}
/// \see #isNonSwiftModule
void setIsNonSwiftModule(bool flag = true) {
Bits.ModuleDecl.IsNonSwiftModule = flag;
}
bool isMainModule() const {
return Bits.ModuleDecl.IsMainModule;
}
/// Whether this module has been compiled with comprehensive checking for
/// concurrency, e.g., Sendable checking.
bool isConcurrencyChecked() const {
return Bits.ModuleDecl.IsConcurrencyChecked;
}
void setIsConcurrencyChecked(bool value = true) {
Bits.ModuleDecl.IsConcurrencyChecked = value;
}
/// For the main module, retrieves the list of primary source files being
/// compiled, that is, the files we're generating code for.
ArrayRef<SourceFile *> getPrimarySourceFiles() const;
/// Retrieve the top-level module. If this module is already top-level, this
/// returns itself. If this is a submodule such as \c Foo.Bar.Baz, this
/// returns the module \c Foo.
ModuleDecl *getTopLevelModule(bool overlay = false);
bool isResilient() const {
return getResilienceStrategy() != ResilienceStrategy::Default;
}
/// 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 the current module.
///
/// This does a simple local lookup, not recursively looking through imports.
void lookupValue(DeclName Name, NLKind LookupKind,
SmallVectorImpl<ValueDecl*> &Result) const;
/// Look up a local type declaration by its mangled name.
///
/// This does a simple local lookup, not recursively looking through imports.
TypeDecl *lookupLocalType(StringRef MangledName) const;
/// Look up an opaque return type by the mangled name of the declaration
/// that defines it.
OpaqueTypeDecl *lookupOpaqueResultType(StringRef MangledName);
/// Find ValueDecls in the module and pass them to the given consumer object.
///
/// This does a simple local lookup, not recursively looking through imports.
void lookupVisibleDecls(ImportPath::Access AccessPath,
VisibleDeclConsumer &Consumer,
NLKind LookupKind) const;
/// This is a hack for 'main' file parsing and the integrated REPL.
///
/// FIXME: Refactor main file parsing to not pump the parser incrementally.
/// FIXME: Remove the integrated REPL.
void clearLookupCache();
/// Finds all class members defined in this module.
///
/// This does a simple local lookup, not recursively looking through imports.
void lookupClassMembers(ImportPath::Access accessPath,
VisibleDeclConsumer &consumer) const;
/// Finds class members defined in this module with the given name.
///
/// This does a simple local lookup, not recursively looking through imports.
void lookupClassMember(ImportPath::Access accessPath,
DeclName name,
SmallVectorImpl<ValueDecl*> &results) const;
/// Look for the conformance of the given type to the given protocol.
///
/// This routine determines whether the given \c type conforms to the given
/// \c protocol.
///
/// \param type The type for which we are computing conformance.
///
/// \param protocol The protocol to which we are computing conformance.
///
/// \param allowMissing When \c true, the resulting conformance reference
/// might include "missing" conformances, which are synthesized for some
/// protocols as an error recovery mechanism.
///
/// \param allowUnavailable When \c true, the resulting conformance reference
/// might include "unavailable" conformances, meaning that the conformance
/// cannot actually be used and will be diagnosed if used later. Pass
/// \c false here for queries that want to determine whether the conformance
/// is likely to be usable.
///
/// \returns The result of the conformance search, which will be
/// None if the type does not conform to the protocol or contain a
/// ProtocolConformanceRef if it does conform.
ProtocolConformanceRef lookupConformance(Type type, ProtocolDecl *protocol,
bool allowMissing = false,
bool allowUnavailable = true);
/// Look for the conformance of the given existential type to the given
/// protocol.
ProtocolConformanceRef lookupExistentialConformance(Type type,
ProtocolDecl *protocol);
/// Exposes TypeChecker functionality for querying protocol conformance.
/// Returns a valid ProtocolConformanceRef only if all conditional
/// requirements are successfully resolved.
ProtocolConformanceRef conformsToProtocol(Type sourceTy,
ProtocolDecl *targetProtocol);
/// Find a member named \p name in \p container that was declared in this
/// module.
///
/// \p container may be \c this for a top-level lookup.
///
/// If \p privateDiscriminator is non-empty, only matching private decls are
/// returned; otherwise, only non-private decls are returned.
void lookupMember(SmallVectorImpl<ValueDecl*> &results,
DeclContext *container, DeclName name,
Identifier privateDiscriminator) const;
/// Find all Objective-C methods with the given selector.
void lookupObjCMethods(
ObjCSelector selector,
SmallVectorImpl<AbstractFunctionDecl *> &results) const;
/// Find all SPI names imported from \p importedModule by this module,
/// collecting the identifiers in \p spiGroups.
void lookupImportedSPIGroups(
const ModuleDecl *importedModule,
llvm::SmallSetVector<Identifier, 4> &spiGroups) const;
// Is \p attr accessible as an explicitly imported SPI from this module?
bool isImportedAsSPI(const SpecializeAttr *attr,
const ValueDecl *targetDecl) const;
// Is \p spiGroup accessible as an explicitly imported SPI from this module?
bool isImportedAsSPI(Identifier spiGroup, const ModuleDecl *fromModule) const;
/// \sa getImportedModules
enum class ImportFilterKind {
/// Include imports declared with `@_exported`.
Exported = 1 << 0,
/// Include "regular" imports with no special annotation.
Default = 1 << 1,
/// Include imports declared with `@_implementationOnly`.
ImplementationOnly = 1 << 2,
/// Include imports of SPIs declared with `@_spi`
SPIAccessControl = 1 << 3,
/// Include imports shadowed by a cross-import overlay. Unshadowed imports
/// are included whether or not this flag is specified.
ShadowedByCrossImportOverlay = 1 << 4
};
/// \sa getImportedModules
using ImportFilter = OptionSet<ImportFilterKind>;
/// Looks up which modules are imported by this module.
///
/// \p filter controls whether public, private, or any imports are included
/// in this list.
void getImportedModules(SmallVectorImpl<ImportedModule> &imports,
ImportFilter filter = ImportFilterKind::Exported) const;
/// Looks up which modules are imported by this module, ignoring any that
/// won't contain top-level decls.
///
/// This is a performance hack. Do not use for anything but name lookup.
/// May go away in the future.
void
getImportedModulesForLookup(SmallVectorImpl<ImportedModule> &imports) const;
/// Has \p module been imported via an '@_implementationOnly' import
/// instead of another kind of import?
///
/// This assumes that \p module was imported.
bool isImportedImplementationOnly(const ModuleDecl *module) const;
/// Returns true if decl context or its content can be serialized by
/// cross-module-optimization.
/// The \p ctxt can e.g. be a NominalType or the context of a function.
bool canBeUsedForCrossModuleOptimization(DeclContext *ctxt) const;
/// Finds all top-level decls of this module.
///
/// This does a simple local lookup, not recursively looking through imports.
/// The order of the results is not guaranteed to be meaningful.
void getTopLevelDecls(SmallVectorImpl<Decl*> &Results) const;
void getExportedPrespecializations(SmallVectorImpl<Decl *> &results) const;
/// Finds top-level decls of this module 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
/// filter which decls to fully deserialize. Only decls with accepted
/// attributes are deserialized and added to Results.
void getTopLevelDeclsWhereAttributesMatch(
SmallVectorImpl<Decl*> &Results,
llvm::function_ref<bool(DeclAttributes)> matchAttributes) const;
/// Finds all local type decls of this module.
///
/// This does a simple local lookup, not recursively looking through imports.
/// The order of the results is not guaranteed to be meaningful.
void getLocalTypeDecls(SmallVectorImpl<TypeDecl*> &Results) const;
/// Finds all operator decls of this module.
///
/// This does a simple local lookup, not recursively looking through imports.
/// The order of the results is not guaranteed to be meaningful.
void getOperatorDecls(SmallVectorImpl<OperatorDecl *> &results) const;
/// Finds all precedence group decls of this module.
///
/// This does a simple local lookup, not recursively looking through imports.
/// The order of the results is not guaranteed to be meaningful.
void getPrecedenceGroups(SmallVectorImpl<PrecedenceGroupDecl*> &Results) const;
/// Determines whether this module should be recursed into when calling
/// \c getDisplayDecls.
///
/// Some modules should not call \c getDisplayDecls, due to assertions
/// in their implementation. These are usually implicit imports that would be
/// recursed into for parsed modules. This function provides a guard against
/// recusing into modules that should not have decls collected.
bool shouldCollectDisplayDecls() const;
/// Finds all top-level decls that should be displayed to a client of this
/// module.
///
/// This includes types, variables, functions, and extensions.
/// This does a simple local lookup, not recursively looking through imports.
/// 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. It does not force synthesized top-level decls that
/// should be printed to be added; use \c swift::getTopLevelDeclsForDisplay()
/// for that.
void getDisplayDecls(SmallVectorImpl<Decl*> &results, bool recursive = false) const;
using LinkLibraryCallback = llvm::function_ref<void(LinkLibrary)>;
/// Generate the list of libraries needed to link this module, based on its
/// imports.
void collectLinkLibraries(LinkLibraryCallback callback) const;
/// Get the path for the file that this module came from, or an empty
/// string if this is not applicable.
StringRef getModuleFilename() const;
/// \returns true if this module is the "swift" standard library module.
bool isStdlibModule() const;
/// \returns true if this module has standard substitutions for mangling.
bool hasStandardSubstitutions() const;
/// \returns true if this module is the "SwiftShims" module;
bool isSwiftShimsModule() const;
/// \returns true if this module is the "builtin" module.
bool isBuiltinModule() const;
/// \returns true if this module is the "SwiftOnoneSupport" module;
bool isOnoneSupportModule() const;
/// \returns true if this module is the "Foundation" module;
bool isFoundationModule() const;
/// \returns true if traversal was aborted, false otherwise.
bool walk(ASTWalker &Walker);
/// Register the file responsible for generating this module's entry point.
///
/// \returns true if there was a problem adding this file.
bool registerEntryPointFile(FileUnit *file, SourceLoc diagLoc,
Optional<ArtificialMainKind> kind);
/// \returns true if this module has a main entry point.
bool hasEntryPoint() const {
return EntryPointInfo.hasEntryPoint();
}
/// Returns the associated clang module if one exists.
const clang::Module *findUnderlyingClangModule() const;
/// Returns a generator with the components of this module's full,
/// hierarchical name.
///
/// For a Swift module, this will only ever have one component, but an
/// imported Clang module might actually be a submodule.
///
/// *Note: see `StringRef operator*()` for details on the returned name for printing
/// for a Swift module.
ReverseFullNameIterator getReverseFullModuleName() const {
return ReverseFullNameIterator(this);
}
/// Calls \p callback for each source file of the module.
void collectBasicSourceFileInfo(
llvm::function_ref<void(const BasicSourceFileInfo &)> callback) const;
void collectSerializedSearchPath(
llvm::function_ref<void(StringRef)> callback) const;
/// Retrieve a fingerprint value that summarizes the contents of this module.
///
/// This interface hash a of a module is guaranteed to change if the interface
/// hash of any of its (primary) source files changes. For example, when
/// building incrementally, the interface hash of this module will change when
/// the primaries contributing to its content changes. In contrast, when
/// a module is deserialized, the hash of every source file contributes to
/// the module's interface hash. It therefore serves as an effective, if
/// coarse-grained, way of determining when top-level changes to a module's
/// contents have been made.
Fingerprint getFingerprint() const;
/// Returns an approximation of whether the given module could be
/// redistributed and consumed by external clients.
///
/// FIXME: The scope of this computation should be limited entirely to
/// RenamedDeclRequest. Unfortunately, it has been co-opted to support the
/// \c SerializeOptionsForDebugging hack. Once this information can be
/// transferred from module files to the dSYMs, remove this.
bool isExternallyConsumed() const;
SWIFT_DEBUG_DUMPER(dumpDisplayDecls());
SWIFT_DEBUG_DUMPER(dumpTopLevelDecls());
SourceRange getSourceRange() const { return SourceRange(); }
static bool classof(const DeclContext *DC) {
if (auto D = DC->getAsDecl())
return classof(D);
return false;
}
static bool classof(const Decl *D) {
return D->getKind() == DeclKind::Module;
}
using ASTAllocated<ModuleDecl>::operator new;
using ASTAllocated<ModuleDecl>::operator delete;
};
/// Wraps either a swift module or a clang one.
/// FIXME: Should go away once swift modules can support submodules natively.
class ModuleEntity {
llvm::PointerUnion<const ModuleDecl *, const /* clang::Module */ void *> Mod;
public:
ModuleEntity() = default;
ModuleEntity(const ModuleDecl *Mod) : Mod(Mod) {}
ModuleEntity(const clang::Module *Mod) : Mod(static_cast<const void *>(Mod)){}
/// @param useRealNameIfAliased Whether to use the module's real name in case
/// module aliasing is used. For example, if a file
/// has `import Foo` and `-module-alias Foo=Bar` is
/// passed, treat Foo as an alias and Bar as the real
/// module name as its dependency. This only applies
/// to Swift modules.
/// @return The module name; for Swift modules, the real module name could be
/// different from the name if module aliasing is used.
StringRef getName(bool useRealNameIfAliased = false) const;
/// For Swift modules, it returns the same result as \c ModuleEntity::getName(bool).
/// For Clang modules, it returns the result of \c clang::Module::getFullModuleName.
std::string getFullName(bool useRealNameIfAliased = false) const;
bool isSystemModule() const;
bool isBuiltinModule() const;
const ModuleDecl *getAsSwiftModule() const;
const clang::Module *getAsClangModule() const;
void *getOpaqueValue() const {
assert(!Mod.isNull());
return Mod.getOpaqueValue();
}
explicit operator bool() const { return !Mod.isNull(); }
};
inline bool DeclContext::isModuleContext() const {
if (auto D = getAsDecl())
return ModuleDecl::classof(D);
return false;
}
inline bool DeclContext::isModuleScopeContext() const {
if (ParentAndKind.getInt() == ASTHierarchy::FileUnit)
return true;
return isModuleContext();
}
/// Extract the source location from the given module declaration.
inline SourceLoc extractNearestSourceLoc(const ModuleDecl *mod) {
return extractNearestSourceLoc(static_cast<const Decl *>(mod));
}
/// Collects modules that this module imports via `@_exported import`.
void collectParsedExportedImports(const ModuleDecl *M, SmallPtrSetImpl<ModuleDecl *> &Imports);
} // end namespace swift
#endif