mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Introduce a last resort check reporting references to implementation-only dependencies that would appear in the generated swiftmodule. This check is applied at serialization, long after exportability checking applied at typechecking. It should act as a back stop to references missed by typechecking or @_implementationOnly decls that should have been skipped. This check is gated behind CheckImplementationOnlyStrict and should be used with embedded only. rdar://160697599
1344 lines
50 KiB
C++
1344 lines
50 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/AttrKind.h"
|
|
#include "swift/AST/AvailabilityDomain.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/Assertions.h"
|
|
#include "swift/Basic/BasicSourceInfo.h"
|
|
#include "swift/Basic/CXXStdlibKind.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/SetVector.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/ADT/StringMap.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/MD5.h"
|
|
#include <optional>
|
|
#include <set>
|
|
#include <unordered_map>
|
|
|
|
namespace clang {
|
|
class Module;
|
|
}
|
|
|
|
namespace swift {
|
|
enum class ArtificialMainKind : uint8_t;
|
|
class ASTContext;
|
|
class ASTWalker;
|
|
class CustomAvailabilityDomain;
|
|
class Decl;
|
|
class DeclAttribute;
|
|
class TypeDecl;
|
|
enum class DeclKind : uint8_t;
|
|
class DebuggerClient;
|
|
class DeclName;
|
|
class FileUnit;
|
|
class FuncDecl;
|
|
enum class LibraryLevel : uint8_t;
|
|
class LinkLibrary;
|
|
class ModuleLoader;
|
|
class NominalTypeDecl;
|
|
class EnumElementDecl;
|
|
class OperatorDecl;
|
|
class PostfixOperatorDecl;
|
|
class PrefixOperatorDecl;
|
|
class ProtocolConformance;
|
|
struct PrintOptions;
|
|
class SourceLookupCache;
|
|
class Type;
|
|
class ValueDecl;
|
|
class VisibleDeclConsumer;
|
|
|
|
/// 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.
|
|
MacroExpansion, ///< Came from a macro expansion.
|
|
DefaultArgument, ///< Came from default argument at caller side
|
|
};
|
|
|
|
/// 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;
|
|
}
|
|
};
|
|
|
|
/// This is used to idenfity an external macro definition.
|
|
struct ExternalMacroPlugin {
|
|
std::string ModuleName;
|
|
|
|
enum Access {
|
|
Internal = 0,
|
|
Package,
|
|
Public,
|
|
};
|
|
|
|
Access MacroAccess;
|
|
};
|
|
|
|
/// 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;
|
|
|
|
/// A unit that allows grouping of modules by a package name.
|
|
///
|
|
/// PackageUnit is treated as an enclosing scope of ModuleDecl. Unlike other
|
|
/// DeclContext subclasses where a parent context is set in ctor, PackageUnit
|
|
/// (parent context) is set as a field in ModuleDecl (child context). It also has a
|
|
/// pointer back to the ModuleDecl, so that it can be used to return the module
|
|
/// in the existing DeclContext lookup functions, which assume ModuleDecl as
|
|
/// the top level context. Since both PackageUnit and ModuleDecl are created
|
|
/// in the ASTContext memory arena, i.e. they will be destroyed when the
|
|
/// ASTContext is destroyed, both pointng to each other is not considered risky.
|
|
///
|
|
/// See \c ModuleDecl
|
|
class PackageUnit: public DeclContext {
|
|
/// Identifies this package and used for the equality check
|
|
Identifier PackageName;
|
|
/// Non-null reference to ModuleDecl that points to this package.
|
|
/// Instead of having multiple ModuleDecls pointing to one PackageUnit, we
|
|
/// create one PackageUnit per ModuleDecl, to make it easier to look up the
|
|
/// module pointing to this package context, which is needed in the existing
|
|
/// DeclContext look up functions.
|
|
/// \see DeclContext::getModuleScopeContext
|
|
/// \see DeclContext::getParentModule
|
|
ModuleDecl &SourceModule;
|
|
|
|
PackageUnit(Identifier name, ModuleDecl &src)
|
|
: DeclContext(DeclContextKind::Package, nullptr), PackageName(name),
|
|
SourceModule(src) {}
|
|
|
|
public:
|
|
static PackageUnit *create(Identifier name, ModuleDecl &src,
|
|
ASTContext &ctx) {
|
|
return new (ctx) PackageUnit(name, src);
|
|
}
|
|
|
|
static bool classof(const DeclContext *DC) {
|
|
return DC->getContextKind() == DeclContextKind::Package;
|
|
}
|
|
|
|
static bool classof(const PackageUnit *PU) { return true; }
|
|
|
|
Identifier getName() const {
|
|
return PackageName;
|
|
}
|
|
|
|
ModuleDecl &getSourceModule() { return SourceModule; }
|
|
|
|
/// Equality check via package name instead of pointer comparison.
|
|
/// Returns false if the name is empty.
|
|
bool isSamePackageAs(PackageUnit *other) {
|
|
if (!other)
|
|
return false;
|
|
return !(getName().empty()) && getName() == other->getName();
|
|
}
|
|
};
|
|
|
|
/// 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;
|
|
friend class CustomDerivativesRequest;
|
|
|
|
/// The ABI name of the module, if it differs from the module name.
|
|
mutable Identifier ModuleABIName;
|
|
|
|
/// A package this module belongs to. It's set as a property instead of a
|
|
/// parent decl context; otherwise it will break the existing decl context
|
|
/// lookup functions that assume ModuleDecl as the top level context.
|
|
PackageUnit *Package = nullptr;
|
|
|
|
/// Module name to use when referenced in clients module interfaces.
|
|
mutable Identifier ExportAsName;
|
|
|
|
mutable Identifier PublicModuleName;
|
|
|
|
/// Indicates a version of the Swift compiler used to generate
|
|
/// .swiftinterface file that this module was produced from (if any).
|
|
mutable version::Version InterfaceCompilerVersion;
|
|
|
|
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;
|
|
|
|
/// The list of files in the module. This is guaranteed to be set once module
|
|
/// construction has completed. It must not be mutated afterwards.
|
|
std::optional<SmallVector<FileUnit *, 2>> Files;
|
|
|
|
llvm::SmallDenseMap<Identifier, SmallVector<OverlayFile *, 1>>
|
|
declaredCrossImports;
|
|
|
|
llvm::DenseMap<Identifier, SmallVector<Decl *, 2>> ObjCNameLookupCache;
|
|
|
|
/// 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;
|
|
|
|
/// Used by the debugger to bypass resilient access to fields.
|
|
bool BypassResilience = false;
|
|
|
|
using AvailabilityDomainMap =
|
|
llvm::SmallDenseMap<Identifier, const CustomAvailabilityDomain *>;
|
|
AvailabilityDomainMap AvailabilityDomains;
|
|
|
|
public:
|
|
using PopulateFilesFn = llvm::function_ref<void(
|
|
ModuleDecl *, llvm::function_ref<void(FileUnit *)>)>;
|
|
|
|
private:
|
|
ModuleDecl(Identifier name, ASTContext &ctx, ImplicitImportInfo importInfo,
|
|
PopulateFilesFn populateFiles, bool isMainModule);
|
|
|
|
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.
|
|
/// \param populateFiles A function which populates the files for the module.
|
|
/// Once called, the module's list of files may not change.
|
|
static ModuleDecl *create(Identifier name, ASTContext &ctx,
|
|
ImplicitImportInfo importInfo,
|
|
PopulateFilesFn populateFiles) {
|
|
return new (ctx) ModuleDecl(name, ctx, importInfo, populateFiles,
|
|
/*isMainModule*/ false);
|
|
}
|
|
|
|
/// Creates a new module with a given \p name.
|
|
///
|
|
/// \param populateFiles A function which populates the files for the module.
|
|
/// Once called, the module's list of files may not change.
|
|
static ModuleDecl *create(Identifier name, ASTContext &ctx,
|
|
PopulateFilesFn populateFiles) {
|
|
return new (ctx) ModuleDecl(name, ctx, ImplicitImportInfo(), populateFiles,
|
|
/*isMainModule*/ false);
|
|
}
|
|
|
|
/// Creates a new main module with a given \p name. The main module is the
|
|
/// module being built by the compiler, containing the primary source files.
|
|
///
|
|
/// \param importInfo Information about which modules should be implicitly
|
|
/// imported by each file of this module.
|
|
/// \param populateFiles A function which populates the files for the module.
|
|
/// Once called, the module's list of files may not change.
|
|
static ModuleDecl *createMainModule(ASTContext &ctx, Identifier name,
|
|
ImplicitImportInfo iinfo,
|
|
PopulateFilesFn populateFiles) {
|
|
return new (ctx) ModuleDecl(name, ctx, iinfo, populateFiles,
|
|
/*isMainModule*/ true);
|
|
}
|
|
|
|
/// Creates an empty module with a given \p name.
|
|
static ModuleDecl *createEmpty(Identifier name, ASTContext &ctx) {
|
|
return create(name, ctx, ImplicitImportInfo(), [](auto, auto) {});
|
|
}
|
|
|
|
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;
|
|
|
|
/// Retrieve the access notes to apply for the module, or \c nullptr if there
|
|
/// are no access notes.
|
|
const AccessNotesFile *getAccessNotes() const;
|
|
|
|
/// 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() const {
|
|
ASSERT(Files.has_value() &&
|
|
"Attempting to query files before setting them");
|
|
return *Files;
|
|
}
|
|
|
|
/// Produces the source file that contains the given source location, or
|
|
/// \c nullptr if the source location isn't in this module.
|
|
SourceFile *getSourceFileContainingLocation(SourceLoc loc);
|
|
|
|
/// 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);
|
|
|
|
/// Returns the name that should be used for this module in a module
|
|
/// selector. For separately-imported overlays, this will be the declaring
|
|
/// module's name.
|
|
Identifier getNameForModuleSelector();
|
|
|
|
/// 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);
|
|
|
|
/// Get the package name of this module
|
|
/// FIXME: remove this and bump module version rdar://104723918
|
|
Identifier getPackageName() const {
|
|
if (auto pkg = getPackage())
|
|
return pkg->getName();
|
|
return Identifier();
|
|
}
|
|
|
|
bool inSamePackage(ModuleDecl *other) {
|
|
return other != nullptr &&
|
|
!getPackageName().empty() &&
|
|
getPackageName() == other->getPackageName();
|
|
}
|
|
|
|
/// Get the package associated with this module
|
|
PackageUnit *getPackage() const { return Package; }
|
|
|
|
/// Set the package this module is associated with
|
|
/// FIXME: rename this with setPackage(name) rdar://104723918
|
|
void setPackageName(Identifier name);
|
|
|
|
Identifier getExportAsName() const { return ExportAsName; }
|
|
|
|
void setExportAsName(Identifier name) {
|
|
ExportAsName = name;
|
|
}
|
|
|
|
/// Public facing name for this module in diagnostics and documentation.
|
|
///
|
|
/// This always returns a valid name as it defaults to the module name if
|
|
/// no public module name is set.
|
|
///
|
|
/// If `onlyIfImported`, return the normal module name when the module
|
|
/// corresponding to the public module name isn't imported. Users working
|
|
/// in between both modules will then see the normal module name,
|
|
/// this may be more useful for diagnostics at that level.
|
|
Identifier getPublicModuleName(bool onlyIfImported) const;
|
|
|
|
void setPublicModuleName(Identifier name) {
|
|
PublicModuleName = name;
|
|
}
|
|
|
|
/// See \c InterfaceCompilerVersion
|
|
version::Version getSwiftInterfaceCompilerVersion() const {
|
|
return InterfaceCompilerVersion;
|
|
}
|
|
|
|
void setSwiftInterfaceCompilerVersion(version::Version version) {
|
|
InterfaceCompilerVersion = version;
|
|
}
|
|
|
|
/// 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;
|
|
}
|
|
|
|
void addAllowableClientName(Identifier name) {
|
|
allowableClientNames.push_back(name);
|
|
}
|
|
ArrayRef<Identifier> getAllowableClientNames() const {
|
|
return allowableClientNames;
|
|
}
|
|
bool allowImportedBy(ModuleDecl *importer) const;
|
|
private:
|
|
|
|
/// An array of module names that are allowed to import this one.
|
|
/// Any module can import this one if empty.
|
|
std::vector<Identifier> allowableClientNames;
|
|
|
|
/// A cache of this module's underlying module and required bystander if it's
|
|
/// an underscored cross-import overlay.
|
|
std::optional<std::pair<ModuleDecl *, Identifier>>
|
|
declaringModuleAndBystander;
|
|
|
|
/// A cache of this module's visible Clang modules
|
|
/// parameterized by the Swift interface print mode.
|
|
using VisibleClangModuleSet = llvm::DenseMap<const clang::Module *, ModuleDecl *>;
|
|
std::unordered_map<PrintOptions::InterfaceMode, VisibleClangModuleSet> CachedVisibleClangModuleSet;
|
|
|
|
/// 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();
|
|
|
|
public:
|
|
/// If this is a traditional (non-cross-import) overlay, get its underlying
|
|
/// module if one exists.
|
|
ModuleDecl *getUnderlyingModuleIfOverlay() const;
|
|
|
|
/// Returns true if this module is the Clang overlay of \p other.
|
|
bool isClangOverlayOf(ModuleDecl *other) const;
|
|
|
|
/// Returns true if this module is the same module or either module is a clang
|
|
/// overlay of the other.
|
|
bool isSameModuleLookingThroughOverlays(ModuleDecl *other);
|
|
|
|
/// 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);
|
|
|
|
/// Computes all Clang modules that are visible from this moule.
|
|
/// This includes any modules that are imported transitively through public
|
|
/// (`@_exported`) imports.
|
|
///
|
|
/// The computed map associates each visible Clang module with the
|
|
/// corresponding Swift module.
|
|
const VisibleClangModuleSet &
|
|
getVisibleClangModules(PrintOptions::InterfaceMode contentMode);
|
|
|
|
/// 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);
|
|
|
|
/// Returns true if this module is the Clang header import module.
|
|
bool isClangHeaderImportModule() const;
|
|
|
|
/// 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 was built with embedded Swift
|
|
bool isEmbeddedSwiftModule() const {
|
|
return Bits.ModuleDecl.IsEmbeddedSwiftModule;
|
|
}
|
|
void setIsEmbeddedSwiftModule(bool enabled = true) {
|
|
Bits.ModuleDecl.IsEmbeddedSwiftModule = enabled;
|
|
}
|
|
|
|
/// Returns true if this module was built with C++ interoperability enabled.
|
|
bool hasCxxInteroperability() const {
|
|
return Bits.ModuleDecl.HasCxxInteroperability;
|
|
}
|
|
void setHasCxxInteroperability(bool enabled = true) {
|
|
Bits.ModuleDecl.HasCxxInteroperability = enabled;
|
|
}
|
|
|
|
CXXStdlibKind getCXXStdlibKind() const {
|
|
return static_cast<CXXStdlibKind>(Bits.ModuleDecl.CXXStdlibKind);
|
|
}
|
|
void setCXXStdlibKind(CXXStdlibKind kind) {
|
|
Bits.ModuleDecl.CXXStdlibKind = static_cast<uint8_t>(kind);
|
|
}
|
|
|
|
/// \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);
|
|
|
|
/// \returns true if this module is part of the stdlib or contained within
|
|
/// the SDK. If no SDK was specified, falls back to whether the module was
|
|
/// specified as a system module (ie. it's on the system search path).
|
|
bool isNonUserModule() const;
|
|
|
|
public:
|
|
/// Returns true if the module was rebuilt from a module interface instead
|
|
/// of being built from the full source.
|
|
bool isBuiltFromInterface() const {
|
|
return Bits.ModuleDecl.IsBuiltFromInterface;
|
|
}
|
|
void setIsBuiltFromInterface(bool flag = true) {
|
|
Bits.ModuleDecl.IsBuiltFromInterface = flag;
|
|
}
|
|
|
|
/// Returns true if -allow-non-resilient-access was passed
|
|
/// and the module is built from source.
|
|
bool allowNonResilientAccess() const {
|
|
return Bits.ModuleDecl.AllowNonResilientAccess &&
|
|
!Bits.ModuleDecl.IsBuiltFromInterface;
|
|
}
|
|
void setAllowNonResilientAccess(bool flag = true) {
|
|
Bits.ModuleDecl.AllowNonResilientAccess = flag;
|
|
}
|
|
|
|
/// Returns true if -package-cmo was passed, which
|
|
/// enables serialization of package, public, and inlinable decls in a
|
|
/// package. This requires -allow-non-resilient-access.
|
|
bool serializePackageEnabled() const {
|
|
return Bits.ModuleDecl.SerializePackageEnabled &&
|
|
allowNonResilientAccess();
|
|
}
|
|
void setSerializePackageEnabled(bool flag = true) {
|
|
Bits.ModuleDecl.SerializePackageEnabled = 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;
|
|
}
|
|
|
|
/// Whether this module has enabled strict memory safety checking.
|
|
bool strictMemorySafety() const {
|
|
return Bits.ModuleDecl.StrictMemorySafety;
|
|
}
|
|
|
|
void setStrictMemorySafety(bool value = true) {
|
|
Bits.ModuleDecl.StrictMemorySafety = value;
|
|
}
|
|
|
|
/// Whether this module uses deferred code generation.
|
|
bool deferredCodeGen() const {
|
|
return Bits.ModuleDecl.DeferredCodeGen;
|
|
}
|
|
|
|
void setDeferredCodeGen(bool value = true) {
|
|
Bits.ModuleDecl.DeferredCodeGen = value;
|
|
}
|
|
|
|
bool isObjCNameLookupCachePopulated() const {
|
|
return Bits.ModuleDecl.ObjCNameLookupCachePopulated;
|
|
}
|
|
|
|
void setIsObjCNameLookupCachePopulated(bool value) {
|
|
Bits.ModuleDecl.ObjCNameLookupCachePopulated = 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);
|
|
|
|
/// Returns whether or not this module is a submodule of the given module.
|
|
/// If `this == M`, this returns false. If this is a submodule such as
|
|
/// `Foo.Bar.Baz`, and the given module is either `Foo` or `Foo.Bar`, this
|
|
/// returns true.
|
|
bool isSubmoduleOf(const ModuleDecl *M) const;
|
|
|
|
private:
|
|
std::string CacheKey;
|
|
|
|
public:
|
|
void setCacheKey(const std::string &key) { CacheKey = key; }
|
|
StringRef getCacheKey() const { return CacheKey; }
|
|
|
|
bool isResilient() const {
|
|
return getResilienceStrategy() != ResilienceStrategy::Default;
|
|
}
|
|
|
|
/// True if this module is resilient AND also does _not_ allow
|
|
/// non-resilient access; the module can allow such access if
|
|
/// package optimization is enabled so its client modules within
|
|
/// the same package can have a direct access to decls in this
|
|
/// module even if it's built resiliently.
|
|
bool isStrictlyResilient() const {
|
|
return isResilient() && !allowNonResilientAccess();
|
|
}
|
|
|
|
/// 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,
|
|
OptionSet<ModuleLookupFlags> Flags,
|
|
SmallVectorImpl<ValueDecl*> &Result) const;
|
|
|
|
/// 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 {
|
|
lookupValue(Name, LookupKind, {}, Result);
|
|
}
|
|
|
|
/// 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;
|
|
|
|
private:
|
|
void populateObjCNameLookupCache();
|
|
|
|
public:
|
|
/// Finds top-levels decls of this module by @objc provided name.
|
|
/// Decls that have no @objc attribute are not considered.
|
|
///
|
|
/// 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 name The @objc simple name to look for. Declarations with matching
|
|
/// name and "anonymous" @objc attribute, as well a matching named @objc
|
|
/// attribute will be added to Results.
|
|
void lookupTopLevelDeclsByObjCName(SmallVectorImpl<Decl *> &Results,
|
|
DeclName name);
|
|
|
|
/// 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;
|
|
|
|
/// 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;
|
|
|
|
/// Returns true if any import of \p importedModule has the `@preconcurrency`
|
|
/// attribute.
|
|
bool isModuleImportedPreconcurrency(const ModuleDecl *importedModule) const;
|
|
|
|
/// Finds the custom availability domain defined by this module with the
|
|
/// given identifier and if one exists adds it to results.
|
|
void
|
|
lookupAvailabilityDomains(Identifier identifier,
|
|
SmallVectorImpl<AvailabilityDomain> &results) const;
|
|
|
|
// Is \p attr accessible as an explicitly imported SPI from this module?
|
|
bool isImportedAsSPI(const AbstractSpecializeAttr *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;
|
|
|
|
/// Is \p module imported as \c @_weakLinked from this module?
|
|
bool isImportedAsWeakLinked(const ModuleDecl *module) const;
|
|
|
|
/// \sa getImportedModules
|
|
enum class ImportFilterKind {
|
|
/// Include imports declared with `@_exported`.
|
|
Exported = 1 << 0,
|
|
/// Include "regular" imports with an effective access level of `public`.
|
|
Default = 1 << 1,
|
|
/// Include imports declared with `@_implementationOnly`.
|
|
ImplementationOnly = 1 << 2,
|
|
/// Include imports declared with an access level of `package`.
|
|
PackageOnly = 1 << 3,
|
|
/// Include imports with an effective access level of `internal` or lower.
|
|
InternalOrBelow = 1 << 4,
|
|
/// Include imports declared with `@_spiOnly`.
|
|
SPIOnly = 1 << 5,
|
|
/// Include imports shadowed by a cross-import overlay. Unshadowed imports
|
|
/// are included whether or not this flag is specified.
|
|
ShadowedByCrossImportOverlay = 1 << 6
|
|
};
|
|
/// \sa getImportedModules
|
|
using ImportFilter = OptionSet<ImportFilterKind>;
|
|
|
|
/// Returns an \c ImportFilter with all elements of \c ImportFilterKind.
|
|
constexpr static ImportFilter getImportFilterAll() {
|
|
return {ImportFilterKind::Exported,
|
|
ImportFilterKind::Default,
|
|
ImportFilterKind::ImplementationOnly,
|
|
ImportFilterKind::PackageOnly,
|
|
ImportFilterKind::InternalOrBelow,
|
|
ImportFilterKind::SPIOnly,
|
|
ImportFilterKind::ShadowedByCrossImportOverlay};
|
|
}
|
|
|
|
/// Import kinds visible to the module declaring them.
|
|
///
|
|
/// This leaves out \c ShadowedByCrossImportOverlay as even if present in
|
|
/// the sources it's superseded by the cross-overlay as the local import.
|
|
constexpr static ImportFilter getImportFilterLocal() {
|
|
return {ImportFilterKind::Exported,
|
|
ImportFilterKind::Default,
|
|
ImportFilterKind::ImplementationOnly,
|
|
ImportFilterKind::PackageOnly,
|
|
ImportFilterKind::InternalOrBelow,
|
|
ImportFilterKind::SPIOnly};
|
|
}
|
|
|
|
/// 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) const;
|
|
|
|
/// Looks up which external macros are defined by this file.
|
|
void getExternalMacros(SmallVectorImpl<ExternalMacroPlugin> ¯os) const;
|
|
|
|
/// Lists modules that are not imported from a file and used in API.
|
|
void getImplicitImportsForModuleInterface(
|
|
SmallVectorImpl<ImportedModule> &imports) 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 and
|
|
/// not by anything more visible?
|
|
///
|
|
/// If \p assumeImported, assume that \p module was imported and avoid the
|
|
/// work to confirm it is imported at all. Transitive modules not reexported
|
|
/// are not considered imported here and may lead to false positive without
|
|
/// this setting.
|
|
bool isImportedImplementationOnly(const ModuleDecl *module,
|
|
bool assumeImported = true) 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;
|
|
|
|
/// Finds all top-level decls of this module including auxiliary decls.
|
|
void
|
|
getTopLevelDeclsWithAuxiliaryDecls(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;
|
|
|
|
/// 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;
|
|
|
|
struct ImportCollector {
|
|
SmallPtrSet<const ModuleDecl *, 4> imports;
|
|
llvm::SmallDenseMap<const ModuleDecl *, SmallPtrSet<Decl *, 4>, 4>
|
|
qualifiedImports;
|
|
AccessLevel minimumDocVisibility = AccessLevel::Private;
|
|
llvm::function_ref<bool(const ModuleDecl *)> importFilter = nullptr;
|
|
|
|
void collect(const ImportedModule &importedModule);
|
|
|
|
ImportCollector() = default;
|
|
ImportCollector(AccessLevel minimumDocVisibility)
|
|
: minimumDocVisibility(minimumDocVisibility) {}
|
|
};
|
|
|
|
void
|
|
getDisplayDeclsRecursivelyAndImports(SmallVectorImpl<Decl *> &results,
|
|
ImportCollector &importCollector) 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;
|
|
|
|
/// Get the path to the file defining this module, what we consider the
|
|
/// source of truth about the module. Usually a swiftinterface file for a
|
|
/// resilient module, a swiftmodule for a non-resilient module, or the
|
|
/// modulemap for a clang module. Returns an empty string if not applicable.
|
|
StringRef getModuleSourceFilename() 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.
|
|
StringRef getModuleLoadedFilename() const;
|
|
|
|
/// \returns true if this module is the "swift" standard library module.
|
|
bool isStdlibModule() const;
|
|
|
|
/// \returns true if this module is the "Cxx" module.
|
|
bool isCxxModule() const;
|
|
|
|
/// \returns true if this module is the "_Concurrency" standard library module.
|
|
bool isConcurrencyModule() 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,
|
|
std::optional<ArtificialMainKind> kind);
|
|
|
|
/// \returns true if this module has a main entry point.
|
|
bool hasEntryPoint() const {
|
|
return EntryPointInfo.hasEntryPoint();
|
|
}
|
|
|
|
NominalTypeDecl *getMainTypeDecl() const;
|
|
|
|
/// 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(); }
|
|
|
|
/// Returns the language version that was used to compile this module.
|
|
/// An empty `Version` is returned if the information is not available.
|
|
version::Version getLanguageVersionBuiltWith() const;
|
|
|
|
void setAvailabilityDomains(const AvailabilityDomainMap &&map) {
|
|
AvailabilityDomains = std::move(map);
|
|
}
|
|
|
|
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 isNonUserModule() 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();
|
|
}
|
|
|
|
inline bool DeclContext::isPackageContext() const {
|
|
return ParentAndKind.getInt() == ASTHierarchy::Package;
|
|
}
|
|
|
|
/// Extract the source location from the given module declaration.
|
|
inline SourceLoc extractNearestSourceLoc(const ModuleDecl *mod) {
|
|
return extractNearestSourceLoc(static_cast<const Decl *>(mod));
|
|
}
|
|
|
|
} // end namespace swift
|
|
|
|
#endif
|