mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Rather than adding a ModuleFile to a parent module and then removing it afterwards if it fails to load, let's wait until we've loaded the file before deciding to add it to the parent module. This then allows us to get rid of `ModuleDecl::removeFile`. In addition, push down the calls to `addFile` into the callers of `loadAST` in preparation for `addFile` being replaced with a one-time-only call to a `setFiles` method.
888 lines
31 KiB
C++
888 lines
31 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/Decl.h"
|
|
#include "swift/AST/DeclContext.h"
|
|
#include "swift/AST/Identifier.h"
|
|
#include "swift/AST/LookupKinds.h"
|
|
#include "swift/AST/RawComment.h"
|
|
#include "swift/AST/Type.h"
|
|
#include "swift/Basic/Compiler.h"
|
|
#include "swift/Basic/OptionSet.h"
|
|
#include "swift/Basic/STLExtras.h"
|
|
#include "swift/Basic/SourceLoc.h"
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
#include "llvm/ADT/DenseSet.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/ADT/SetVector.h"
|
|
#include "llvm/ADT/SmallSet.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/ADT/StringMap.h"
|
|
#include "llvm/ADT/TinyPtrVector.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/MD5.h"
|
|
|
|
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;
|
|
class LinkLibrary;
|
|
struct ImplicitImport;
|
|
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
|
|
};
|
|
|
|
/// The kind of stdlib that should be imported.
|
|
enum class ImplicitStdlibKind {
|
|
/// No standard library should be implicitly imported.
|
|
None,
|
|
|
|
/// The Builtin module should be implicitly imported.
|
|
Builtin,
|
|
|
|
/// The regular Swift standard library should be implicitly imported.
|
|
Stdlib
|
|
};
|
|
|
|
struct ImplicitImportInfo {
|
|
/// The implicit stdlib to import.
|
|
ImplicitStdlibKind StdlibKind;
|
|
|
|
/// Whether we should attempt to import an underlying Clang half of this
|
|
/// module.
|
|
bool ShouldImportUnderlyingModule;
|
|
|
|
/// The bridging header path for this module, empty if there is none.
|
|
StringRef BridgingHeaderPath;
|
|
|
|
/// The names of additional modules to be implicitly imported.
|
|
SmallVector<Identifier, 4> ModuleNames;
|
|
|
|
/// An additional list of already-loaded modules which should be implicitly
|
|
/// imported.
|
|
SmallVector<std::pair<ModuleDecl *, /*exported*/ bool>, 4>
|
|
AdditionalModules;
|
|
|
|
ImplicitImportInfo()
|
|
: StdlibKind(ImplicitStdlibKind::None),
|
|
ShouldImportUnderlyingModule(false) {}
|
|
};
|
|
|
|
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 {
|
|
friend class DirectOperatorLookupRequest;
|
|
friend class DirectPrecedenceGroupLookupRequest;
|
|
|
|
public:
|
|
typedef ArrayRef<Located<Identifier>> AccessPathTy;
|
|
/// Convenience struct to keep track of a module along with its access path.
|
|
struct ImportedModule {
|
|
/// The access path from an import: `import Foo.Bar` -> `Foo.Bar`.
|
|
ModuleDecl::AccessPathTy accessPath;
|
|
/// The actual module corresponding to the import.
|
|
///
|
|
/// Invariant: The pointer is non-null.
|
|
ModuleDecl *importedModule;
|
|
|
|
ImportedModule(ModuleDecl::AccessPathTy accessPath,
|
|
ModuleDecl *importedModule)
|
|
: accessPath(accessPath), importedModule(importedModule) {
|
|
assert(this->importedModule);
|
|
}
|
|
|
|
bool operator==(const ModuleDecl::ImportedModule &other) const {
|
|
return (this->importedModule == other.importedModule) &&
|
|
(this->accessPath == other.accessPath);
|
|
}
|
|
};
|
|
|
|
static bool matchesAccessPath(AccessPathTy AccessPath, DeclName Name) {
|
|
assert(AccessPath.size() <= 1 && "can only refer to top-level decls");
|
|
|
|
return AccessPath.empty()
|
|
|| DeclName(AccessPath.front().Item).matchesRef(Name);
|
|
}
|
|
|
|
/// Arbitrarily orders ImportedModule records, for inclusion in sets and such.
|
|
class OrderImportedModules {
|
|
public:
|
|
bool operator()(const ImportedModule &lhs,
|
|
const ImportedModule &rhs) const {
|
|
if (lhs.importedModule != rhs.importedModule)
|
|
return std::less<const ModuleDecl *>()(lhs.importedModule,
|
|
rhs.importedModule);
|
|
if (lhs.accessPath.data() != rhs.accessPath.data())
|
|
return std::less<AccessPathTy::iterator>()(lhs.accessPath.begin(),
|
|
rhs.accessPath.begin());
|
|
return lhs.accessPath.size() < rhs.accessPath.size();
|
|
}
|
|
};
|
|
|
|
/// 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.
|
|
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;
|
|
}
|
|
|
|
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.
|
|
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;
|
|
|
|
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.
|
|
ArrayRef<ImplicitImport> getImplicitImports() const;
|
|
|
|
ArrayRef<FileUnit *> getFiles() {
|
|
return Files;
|
|
}
|
|
ArrayRef<const FileUnit *> getFiles() const {
|
|
return { Files.begin(), Files.size() };
|
|
}
|
|
|
|
bool isClangModule() const;
|
|
void addFile(FileUnit &newFile);
|
|
|
|
/// Creates a map from \c #filePath strings to corresponding \c #file
|
|
/// strings, diagnosing any conflicts.
|
|
///
|
|
/// A given \c #filePath string always maps to exactly one \c #file 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 #file 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 #file strings that
|
|
/// are paired with \c false.
|
|
///
|
|
/// Note that this returns an empty StringMap if concise \c #file strings are
|
|
/// disabled. Users should fall back to using the file path in this case.
|
|
llvm::StringMap<std::pair<std::string, /*isWinner=*/bool>>
|
|
computeMagicFileStringMap(bool shouldDiagnose) const;
|
|
|
|
/// Add a file declaring a cross-import overlay.
|
|
void addCrossImportOverlayFile(StringRef file);
|
|
|
|
/// 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);
|
|
|
|
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(SourceFileKind expectedKind) 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 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);
|
|
}
|
|
|
|
/// \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;
|
|
}
|
|
|
|
/// 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(AccessPathTy 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(AccessPathTy 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(AccessPathTy 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.
|
|
///
|
|
/// \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);
|
|
|
|
/// 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,
|
|
SmallVectorImpl<Identifier> &spiGroups) const;
|
|
|
|
/// \sa getImportedModules
|
|
enum class ImportFilterKind {
|
|
/// Include imports declared with `@_exported`.
|
|
Public = 1 << 0,
|
|
/// Include "regular" imports with no special annotation.
|
|
Private = 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 separately-imported overlay (i.e. a
|
|
/// cross-import overlay). Unshadowed imports are included whether or not
|
|
/// this flag is specified.
|
|
ShadowedBySeparateOverlay = 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::Public) 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;
|
|
|
|
/// Uniques the items in \p imports, ignoring the source locations of the
|
|
/// access paths.
|
|
///
|
|
/// The order of items in \p imports is \e not preserved.
|
|
static void removeDuplicateImports(SmallVectorImpl<ImportedModule> &imports);
|
|
|
|
/// 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 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.
|
|
void getDisplayDecls(SmallVectorImpl<Decl*> &results) 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;
|
|
|
|
/// Returns true if the two access paths contain the same chain of
|
|
/// identifiers.
|
|
///
|
|
/// Source locations are ignored here.
|
|
static bool isSameAccessPath(AccessPathTy lhs, AccessPathTy rhs);
|
|
|
|
/// 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 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 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.
|
|
ReverseFullNameIterator getReverseFullModuleName() const {
|
|
return ReverseFullNameIterator(this);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
private:
|
|
// Make placement new and vanilla new/delete illegal for Modules.
|
|
void *operator new(size_t Bytes) throw() = delete;
|
|
void operator delete(void *Data) throw() = delete;
|
|
void *operator new(size_t Bytes, void *Mem) throw() = delete;
|
|
public:
|
|
// Only allow allocation of Modules using the allocator in ASTContext
|
|
// or by doing a placement new.
|
|
void *operator new(size_t Bytes, const ASTContext &C,
|
|
unsigned Alignment = alignof(ModuleDecl));
|
|
};
|
|
|
|
/// 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)){}
|
|
|
|
StringRef getName() const;
|
|
std::string getFullName() 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));
|
|
}
|
|
|
|
} // end namespace swift
|
|
|
|
namespace llvm {
|
|
template <>
|
|
class DenseMapInfo<swift::ModuleDecl::ImportedModule> {
|
|
using ModuleDecl = swift::ModuleDecl;
|
|
public:
|
|
static ModuleDecl::ImportedModule getEmptyKey() {
|
|
return {{}, llvm::DenseMapInfo<ModuleDecl *>::getEmptyKey()};
|
|
}
|
|
static ModuleDecl::ImportedModule getTombstoneKey() {
|
|
return {{}, llvm::DenseMapInfo<ModuleDecl *>::getTombstoneKey()};
|
|
}
|
|
|
|
static unsigned getHashValue(const ModuleDecl::ImportedModule &val) {
|
|
auto pair = std::make_pair(val.accessPath.size(), val.importedModule);
|
|
return llvm::DenseMapInfo<decltype(pair)>::getHashValue(pair);
|
|
}
|
|
|
|
static bool isEqual(const ModuleDecl::ImportedModule &lhs,
|
|
const ModuleDecl::ImportedModule &rhs) {
|
|
return lhs.importedModule == rhs.importedModule &&
|
|
ModuleDecl::isSameAccessPath(lhs.accessPath, rhs.accessPath);
|
|
}
|
|
};
|
|
}
|
|
|
|
#endif
|