Files
swift-mirror/include/swift/AST/ModuleLoader.h
Steven Wu 2a18922c4b [Caching] Move per-query CAS state out of the SwiftDependencyScanningService
Move per-query state out of ScanningService. There is still a check to
make sure the CASOptions are matching between queries because of the
requirement on clang scanner. Otherwise, the scanning service should
contain no per-query information anymore.

Resolves: https://github.com/swiftlang/swift/issues/82490
2025-06-26 17:03:27 -07:00

394 lines
14 KiB
C++

//===--- ModuleLoader.h - Module Loader Interface ---------------*- 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 implements an abstract interface for loading modules.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_AST_MODULE_LOADER_H
#define SWIFT_AST_MODULE_LOADER_H
#include "swift/AST/Identifier.h"
#include "swift/AST/Import.h"
#include "swift/Basic/ArrayRefView.h"
#include "swift/Basic/Fingerprint.h"
#include "swift/Basic/LLVM.h"
#include "swift/Basic/Located.h"
#include "swift/Basic/SourceLoc.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Support/VersionTuple.h"
#include <optional>
#include <system_error>
namespace llvm {
class FileCollectorBase;
class PrefixMapper;
namespace vfs {
class OutputBackend;
} // namespace vfs
} // namespace llvm
namespace clang {
class DependencyCollector;
namespace tooling {
namespace dependencies {
struct ModuleID;
class DependencyScanningTool;
}
}
}
namespace swift {
class AbstractFunctionDecl;
struct AutoDiffConfig;
class ClangImporterOptions;
class ClassDecl;
class FileUnit;
class ModuleDecl;
class ModuleDependencyInfo;
struct ModuleDependencyID;
class ModuleDependenciesCache;
class NominalTypeDecl;
class SourceFile;
class TypeDecl;
class CompilerInstance;
enum class ModuleDependencyKind : int8_t;
enum class KnownProtocolKind : uint8_t;
enum class Bridgeability : unsigned {
/// This context does not permit bridging at all. For example, the
/// target of a C pointer.
None,
/// This context permits all kinds of bridging. For example, the
/// imported result of a method declaration.
Full
};
/// Specifies which dependencies the intermodule dependency tracker records.
enum class IntermoduleDepTrackingMode {
/// Records both system and non-system dependencies.
IncludeSystem,
/// Records only non-system dependencies.
ExcludeSystem,
};
/// Records dependencies on files outside of the current module;
/// implemented in terms of a wrapped clang::DependencyCollector.
class DependencyTracker {
public:
/// A representation of a first-class incremental dependency known to the
/// Swift compiler.
struct IncrementalDependency {
std::string path;
Fingerprint fingerprint;
IncrementalDependency(std::string Path, Fingerprint FP)
: path(std::move(Path)), fingerprint(std::move(FP)) {}
};
struct MacroPluginDependency {
Identifier moduleName;
std::string path;
MacroPluginDependency(const Identifier &moduleName, const std::string &path)
: moduleName(moduleName), path(path) {}
};
template <typename Dep>
inline static const std::string getPath(const Dep &dep) {
return dep.path;
}
template <typename Dep>
using PathArrayRefView = ArrayRefView<Dep, const std::string, getPath>;
std::shared_ptr<clang::DependencyCollector> clangCollector;
SmallVector<IncrementalDependency, 8> incrementalDeps;
llvm::StringSet<> incrementalDepsUniquer;
llvm::SetVector<MacroPluginDependency> macroPluginDeps;
public:
explicit DependencyTracker(
IntermoduleDepTrackingMode Mode,
std::shared_ptr<llvm::FileCollectorBase> FileCollector = {});
/// Adds a file as a dependency.
///
/// The contents of \p File are taken literally, and should be appropriate
/// for appearing in a list of dependencies suitable for tooling like Make.
/// No path canonicalization is done.
void addDependency(StringRef File, bool IsSystem);
/// Adds a file as an incremental dependency.
///
/// No additional canonicalization or adulteration of the file path in
/// \p File is performed.
void addIncrementalDependency(StringRef File, Fingerprint FP);
/// Adds a macro plugin dependency.
///
/// No additional canonicalization or adulteration of the file path in
/// \p File is performed.
void addMacroPluginDependency(StringRef File, Identifier ModuleName);
/// Fetches the list of dependencies.
ArrayRef<std::string> getDependencies() const;
/// Fetches the list of dependencies that are known to have incremental swift
/// dependency information embedded inside of them.
ArrayRef<IncrementalDependency> getIncrementalDependencies() const;
/// A view of the paths of the dependencies known to have incremental swift
/// dependency information embedded inside of them.
PathArrayRefView<IncrementalDependency>
getIncrementalDependencyPaths() const {
return PathArrayRefView<IncrementalDependency>(
getIncrementalDependencies());
}
/// The list of macro plugin dependencies.
ArrayRef<MacroPluginDependency> getMacroPluginDependencies() const;
PathArrayRefView<MacroPluginDependency>
getMacroPluginDependencyPaths() const {
return PathArrayRefView<MacroPluginDependency>(
getMacroPluginDependencies());
}
/// Return the underlying clang::DependencyCollector that this
/// class wraps.
std::shared_ptr<clang::DependencyCollector> getClangCollector();
};
struct SubCompilerInstanceInfo {
StringRef CompilerVersion;
CompilerInstance* Instance;
StringRef Hash;
ArrayRef<StringRef> BuildArguments;
};
/// Abstract interface for a checker of module interfaces and prebuilt modules.
class ModuleInterfaceChecker {
public:
virtual std::vector<std::string>
getCompiledModuleCandidatesForInterface(StringRef moduleName,
StringRef interfacePath) = 0;
/// Given a list of potential ready-to-use compiled modules for \p interfacePath,
/// check if any one of them is up-to-date. If so, emit a forwarding module
/// to the candidate binary module to \p outPath.
virtual bool tryEmitForwardingModule(StringRef moduleName,
StringRef interfacePath,
ArrayRef<std::string> candidates,
llvm::vfs::OutputBackend &backend,
StringRef outPath) = 0;
virtual ~ModuleInterfaceChecker() = default;
};
/// Abstract interface to run an action in a sub ASTContext.
struct InterfaceSubContextDelegate {
virtual std::error_code runInSubContext(StringRef moduleName,
StringRef interfacePath,
StringRef sdkPath,
std::optional<StringRef> sysroot,
StringRef outputPath,
SourceLoc diagLoc,
llvm::function_ref<std::error_code(ASTContext&, ModuleDecl*,
ArrayRef<StringRef>, StringRef,
StringRef)> action) = 0;
virtual std::error_code runInSubCompilerInstance(StringRef moduleName,
StringRef interfacePath,
StringRef sdkPath,
std::optional<StringRef> sysroot,
StringRef outputPath,
SourceLoc diagLoc,
bool silenceErrors,
llvm::function_ref<std::error_code(SubCompilerInstanceInfo&)> action) = 0;
virtual ~InterfaceSubContextDelegate() = default;
};
/// Abstract interface that loads named modules into the AST.
class ModuleLoader {
virtual void anchor();
protected:
DependencyTracker * const dependencyTracker;
ModuleLoader(DependencyTracker *tracker) : dependencyTracker(tracker) {}
public:
virtual ~ModuleLoader() = default;
/// Collect visible module names.
///
/// Append visible module names to \p names. Note that names are possibly
/// duplicated, and not guaranteed to be ordered in any way.
virtual void collectVisibleTopLevelModuleNames(
SmallVectorImpl<Identifier> &names) const = 0;
/// The kind of source for a module's version.
///
/// NOTE: The order of the members is significant; they are declared in
/// ascending priority order.
enum class ModuleVersionSourceKind {
ClangModuleTBD,
SwiftBinaryModule,
SwiftInterface,
};
/// Represents a module version and the source it was parsed from.
class ModuleVersionInfo {
llvm::VersionTuple Version;
std::optional<ModuleVersionSourceKind> SourceKind;
public:
/// Returns true if the version has a valid source kind.
bool isValid() const { return SourceKind.has_value(); }
/// Returns the version, which may be empty if a version was not present or
/// was unparsable.
llvm::VersionTuple getVersion() const { return Version; }
/// Returns the kind of source of the module version. Do not call if
/// \c isValid() returns false.
ModuleVersionSourceKind getSourceKind() const {
return SourceKind.value();
}
void setVersion(llvm::VersionTuple version, ModuleVersionSourceKind kind) {
Version = version;
SourceKind = kind;
}
};
/// Check whether the module with a given name can be imported without
/// importing it.
///
/// Note that even if this check succeeds, errors may still occur if the
/// module is loaded in full.
///
/// If a non-null \p versionInfo is provided, the module version will be
/// parsed and populated.
virtual bool canImportModule(ImportPath::Module named, SourceLoc loc,
ModuleVersionInfo *versionInfo,
bool isTestableImport = false) = 0;
/// Import a module with the given module path.
///
/// \param importLoc The location of the 'import' keyword.
///
/// \param path A sequence of (identifier, location) pairs that denote
/// the dotted module name to load, e.g., AppKit.NSWindow.
///
/// \param AllowMemoryCache Enables preserving the loaded module in the
/// in-memory cache for the next loading attempt.
///
/// \returns the module referenced, if it could be loaded. Otherwise,
/// emits a diagnostic and returns NULL.
virtual
ModuleDecl *loadModule(SourceLoc importLoc, ImportPath::Module path,
bool AllowMemoryCache = true) = 0;
/// Load extensions to the given nominal type.
///
/// \param nominal The nominal type whose extensions should be loaded.
///
/// \param previousGeneration The previous generation number. The AST already
/// contains extensions loaded from any generation up to and including this
/// one.
virtual void loadExtensions(NominalTypeDecl *nominal,
unsigned previousGeneration) { }
/// Load the methods within the given type that produce
/// Objective-C class or instance methods with the given selector.
///
/// \param typeDecl The type in which we are searching for @objc methods.
/// The search only considers this type and its extensions; not any
/// superclasses.
///
/// \param selector The selector to search for.
///
/// \param isInstanceMethod Whether we are looking for an instance method
/// (vs. a class method).
///
/// \param previousGeneration The previous generation with which this
/// callback was invoked. The list of methods will already contain all of
/// the results from generations up and including \c previousGeneration.
///
/// \param methods The list of @objc methods in this class that have this
/// selector and are instance/class methods as requested. This list will be
/// extended with any methods found in subsequent generations.
virtual void loadObjCMethods(
NominalTypeDecl *typeDecl,
ObjCSelector selector,
bool isInstanceMethod,
unsigned previousGeneration,
llvm::TinyPtrVector<AbstractFunctionDecl *> &methods) = 0;
/// Load derivative function configurations for the given
/// AbstractFunctionDecl.
///
/// \param originalAFD The declaration whose derivative function
/// configurations should be loaded.
///
/// \param previousGeneration The previous generation number. The AST already
/// contains derivative function configurations loaded from any generation up
/// to and including this one.
///
/// \param results The result list of derivative function configurations.
/// This list will be extended with any methods found in subsequent
/// generations.
virtual void loadDerivativeFunctionConfigurations(
AbstractFunctionDecl *originalAFD, unsigned previousGeneration,
llvm::SetVector<AutoDiffConfig> &results) {};
/// Verify all modules loaded by this loader.
virtual void verifyAllModules() { }
/// Discover overlays declared alongside this file and add information about
/// them to it.
void findOverlayFiles(SourceLoc diagLoc, ModuleDecl *module, FileUnit *file);
};
} // namespace swift
namespace llvm {
template <>
struct DenseMapInfo<swift::DependencyTracker::MacroPluginDependency> {
using MacroPluginDependency = swift::DependencyTracker::MacroPluginDependency;
static MacroPluginDependency getEmptyKey() {
return {DenseMapInfo<swift::Identifier>::getEmptyKey(), ""};
}
static MacroPluginDependency getTombstoneKey() {
return {DenseMapInfo<swift::Identifier>::getTombstoneKey(), ""};
}
static unsigned getHashValue(MacroPluginDependency Val) {
return hash_combine(Val.moduleName, Val.path);
}
static bool isEqual(const MacroPluginDependency &LHS,
const MacroPluginDependency &RHS) {
return LHS.moduleName == RHS.moduleName && LHS.path == RHS.path;
}
};
} // namespace llvm
#endif