mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Explicit module builds currently fail on Windows because direct-clang-cc1-module-build emit-pcm commands take overlaid system module map files as inputs but miss the clang VFS overlay. This change adds the overlay and fixes explicit module builds on Windows.
1036 lines
41 KiB
C++
1036 lines
41 KiB
C++
//===--- ClangImporter.h - Import Clang Modules -----------------*- 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 support for loading Clang modules into Swift.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#ifndef SWIFT_CLANG_IMPORTER_H
|
|
#define SWIFT_CLANG_IMPORTER_H
|
|
|
|
#include "swift/AST/Attr.h"
|
|
#include "swift/AST/AttrKind.h"
|
|
#include "swift/AST/ClangModuleLoader.h"
|
|
#include "clang/AST/Attr.h"
|
|
#include "clang/Basic/DiagnosticOptions.h"
|
|
#include "clang/Basic/Specifiers.h"
|
|
#include "llvm/Support/VirtualFileSystem.h"
|
|
|
|
/// The maximum number of SIMD vector elements we currently try to import.
|
|
#define SWIFT_MAX_IMPORTED_SIMD_ELEMENTS 4
|
|
|
|
namespace llvm {
|
|
class Triple;
|
|
class FileCollectorBase;
|
|
template<typename Fn> class function_ref;
|
|
namespace opt {
|
|
class InputArgList;
|
|
}
|
|
namespace vfs {
|
|
class FileSystem;
|
|
class OutputBackend;
|
|
}
|
|
}
|
|
|
|
namespace clang {
|
|
class ASTContext;
|
|
class CodeGenOptions;
|
|
class Decl;
|
|
class DependencyCollector;
|
|
class DiagnosticConsumer;
|
|
class EnumConstantDecl;
|
|
class EnumDecl;
|
|
class MacroInfo;
|
|
class Module;
|
|
class ModuleMacro;
|
|
class NamedDecl;
|
|
class Sema;
|
|
class TargetInfo;
|
|
class Type;
|
|
class VisibleDeclConsumer;
|
|
class DeclarationName;
|
|
class CompilerInvocation;
|
|
class TargetOptions;
|
|
namespace driver {
|
|
class Driver;
|
|
}
|
|
namespace tooling {
|
|
namespace dependencies {
|
|
struct ModuleDeps;
|
|
struct TranslationUnitDeps;
|
|
enum class ModuleOutputKind;
|
|
using ModuleDepsGraph = std::vector<ModuleDeps>;
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace swift {
|
|
enum class ResultConvention : uint8_t;
|
|
class ASTContext;
|
|
class CASOptions;
|
|
class CompilerInvocation;
|
|
class ClangImporterOptions;
|
|
class ClangInheritanceInfo;
|
|
class ClangModuleUnit;
|
|
class ClangNode;
|
|
class ConcreteDeclRef;
|
|
class Decl;
|
|
class DeclContext;
|
|
class DiagnosticEngine;
|
|
class EffectiveClangContext;
|
|
class EnumDecl;
|
|
class FuncDecl;
|
|
class ImportDecl;
|
|
class IRGenOptions;
|
|
class LangOptions;
|
|
class ModuleDecl;
|
|
struct ModuleDependencyID;
|
|
class NominalTypeDecl;
|
|
class SearchPathOptions;
|
|
class StructDecl;
|
|
class SwiftLookupTable;
|
|
class TypeDecl;
|
|
class ValueDecl;
|
|
class VisibleDeclConsumer;
|
|
using ModuleDependencyIDSetVector =
|
|
llvm::SetVector<ModuleDependencyID, std::vector<ModuleDependencyID>,
|
|
std::set<ModuleDependencyID>>;
|
|
enum class SelectorSplitKind;
|
|
|
|
/// Kinds of optional types.
|
|
enum OptionalTypeKind : unsigned {
|
|
/// The type is not an optional type.
|
|
OTK_None = 0,
|
|
|
|
/// The type is Optional<T>.
|
|
OTK_Optional,
|
|
|
|
/// The type is ImplicitlyUnwrappedOptional<T>.
|
|
OTK_ImplicitlyUnwrappedOptional
|
|
};
|
|
enum { NumOptionalTypeKinds = 2 };
|
|
|
|
/// This interface is implemented by LLDB to serve as a fallback when Clang
|
|
/// modules can't be imported from source in the debugger.
|
|
///
|
|
/// During compile time, ClangImporter-imported Clang modules are compiled with
|
|
/// -gmodules, which emits a DWARF rendition of all types defined in the module
|
|
/// into the .pcm file. On Darwin, these types can be collected by
|
|
/// dsymutil. This delegate allows DWARFImporter to ask LLDB to look up a Clang
|
|
/// type by name, synthesize a Clang AST from it. DWARFImporter then hands this
|
|
/// Clang AST to ClangImporter to import the type into Swift.
|
|
class DWARFImporterDelegate {
|
|
public:
|
|
virtual ~DWARFImporterDelegate() = default;
|
|
/// Perform a qualified lookup of a Clang type with this name.
|
|
/// \param kind Only return results with this type kind.
|
|
/// \param inModule only return results from this module.
|
|
virtual void lookupValue(StringRef name, std::optional<ClangTypeKind> kind,
|
|
StringRef inModule,
|
|
SmallVectorImpl<clang::Decl *> &results) {}
|
|
/// vtable anchor.
|
|
virtual void anchor();
|
|
};
|
|
|
|
// ⚠️ DANGER ⚠️
|
|
// Putting more than four types in this `PointerUnion` will break the build for
|
|
// 32-bit hosts. If we need five or more types in the future, we'll need to
|
|
// design a proper larger-than-word-sized type.
|
|
typedef llvm::PointerUnion<const clang::Decl *, const clang::MacroInfo *,
|
|
const clang::Type *, const clang::Token *>
|
|
ImportDiagnosticTarget;
|
|
|
|
/// Class that imports Clang modules into Swift, mapping directly
|
|
/// from Clang ASTs over to Swift ASTs.
|
|
class ClangImporter final : public ClangModuleLoader {
|
|
friend class ClangModuleUnit;
|
|
friend class SwiftDeclSynthesizer;
|
|
|
|
// Make requests in the ClangImporter zone friends so they can access `Impl`.
|
|
#define SWIFT_REQUEST(Zone, Name, Sig, Caching, LocOptions) \
|
|
friend class Name;
|
|
#include "swift/ClangImporter/ClangImporterTypeIDZone.def"
|
|
#undef SWIFT_REQUEST
|
|
|
|
public:
|
|
class Implementation;
|
|
|
|
private:
|
|
Implementation &Impl;
|
|
|
|
bool requiresBuiltinHeadersInSystemModules = false;
|
|
|
|
ClangImporter(ASTContext &ctx, DependencyTracker *tracker,
|
|
DWARFImporterDelegate *dwarfImporterDelegate);
|
|
|
|
/// Creates a clone of Clang importer's compiler instance that has been
|
|
/// configured for operations on precompiled outputs (either emitting a
|
|
/// precompiled header, emitting a precompiled module, or dumping a
|
|
/// precompiled module).
|
|
///
|
|
/// The caller of this method should set any action-specific invocation
|
|
/// options (like FrontendOptions::ProgramAction, input files, and output
|
|
/// paths), then create the appropriate FrontendAction and execute it.
|
|
std::unique_ptr<clang::CompilerInstance>
|
|
cloneCompilerInstanceForPrecompiling();
|
|
|
|
public:
|
|
/// Create a new Clang importer that can import a suitable Clang
|
|
/// module into the given ASTContext.
|
|
///
|
|
/// \param ctx The ASTContext into which the module will be imported.
|
|
/// The ASTContext's SearchPathOptions will be used for the Clang importer.
|
|
///
|
|
/// \param swiftPCHHash A hash of Swift's various options in a compiler
|
|
/// invocation, used to create a unique Bridging PCH if requested.
|
|
///
|
|
/// \param tracker The object tracking files this compilation depends on.
|
|
///
|
|
/// \param dwarfImporterDelegate A helper object that can synthesize
|
|
/// Clang Decls from debug info. Used by LLDB.
|
|
///
|
|
/// \returns a new Clang module importer, or null (with a diagnostic) if
|
|
/// an error occurred.
|
|
static std::unique_ptr<ClangImporter>
|
|
create(ASTContext &ctx, std::string swiftPCHHash = "",
|
|
DependencyTracker *tracker = nullptr,
|
|
DWARFImporterDelegate *dwarfImporterDelegate = nullptr,
|
|
bool ignoreFileMapping = false);
|
|
|
|
std::vector<std::string>
|
|
getClangDriverArguments(ASTContext &ctx, bool ignoreClangTarget = false);
|
|
|
|
std::optional<std::vector<std::string>>
|
|
getClangCC1Arguments(ASTContext &ctx,
|
|
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
|
|
bool ignoreClangTarget = false);
|
|
|
|
std::vector<std::string>
|
|
getClangDepScanningInvocationArguments(ASTContext &ctx);
|
|
|
|
static std::pair<std::unique_ptr<clang::CompilerInvocation>,
|
|
std::unique_ptr<clang::DiagnosticOptions>>
|
|
createClangInvocation(ClangImporter *importer,
|
|
const ClangImporterOptions &importerOpts,
|
|
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
|
|
const std::vector<std::string> &CC1Args);
|
|
|
|
/// Creates a Clang Driver based on the Swift compiler options.
|
|
///
|
|
/// \return a pair of the Clang Driver and the diagnostic engine, which needs
|
|
/// to be alive during the use of the Driver.
|
|
static std::tuple<clang::driver::Driver,
|
|
llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine>,
|
|
std::unique_ptr<clang::DiagnosticOptions>>
|
|
createClangDriver(
|
|
const LangOptions &LangOpts,
|
|
const ClangImporterOptions &ClangImporterOpts,
|
|
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs = nullptr);
|
|
|
|
static llvm::opt::InputArgList
|
|
createClangArgs(const ClangImporterOptions &ClangImporterOpts,
|
|
const SearchPathOptions &SearchPathOpts,
|
|
clang::driver::Driver &clangDriver);
|
|
|
|
ClangImporter(const ClangImporter &) = delete;
|
|
ClangImporter(ClangImporter &&) = delete;
|
|
ClangImporter &operator=(const ClangImporter &) = delete;
|
|
ClangImporter &operator=(ClangImporter &&) = delete;
|
|
|
|
~ClangImporter();
|
|
|
|
/// Only to be used by lldb-moduleimport-test.
|
|
void setDWARFImporterDelegate(DWARFImporterDelegate &delegate);
|
|
|
|
/// Create a new clang::DependencyCollector customized to
|
|
/// ClangImporter's specific uses.
|
|
static std::shared_ptr<clang::DependencyCollector> createDependencyCollector(
|
|
IntermoduleDepTrackingMode Mode,
|
|
std::shared_ptr<llvm::FileCollectorBase> FileCollector);
|
|
|
|
static bool isKnownCFTypeName(llvm::StringRef name);
|
|
|
|
/// Append visible module names to \p names. Note that names are possibly
|
|
/// duplicated, and not guaranteed to be ordered in any way.
|
|
void collectVisibleTopLevelModuleNames(
|
|
SmallVectorImpl<Identifier> &names) const override;
|
|
|
|
/// 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) override;
|
|
|
|
/// Import a module with the given module path.
|
|
///
|
|
/// Clang modules will be imported using the Objective-C ARC dialect,
|
|
/// with all warnings disabled.
|
|
///
|
|
/// \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 Affects only loading serialized Swift modules,
|
|
/// this parameter has no effect in the ClangImporter.
|
|
///
|
|
/// \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)
|
|
override;
|
|
|
|
/// Determine whether \c overlayDC is within an overlay module for the
|
|
/// imported context enclosing \c importedDC.
|
|
///
|
|
/// This routine is used for various hacks that are only permitted within
|
|
/// overlays of imported modules, e.g., Objective-C bridging conformances.
|
|
bool isInOverlayModuleForImportedModule(
|
|
const DeclContext *overlayDC,
|
|
const DeclContext *importedDC) override;
|
|
|
|
/// Look for declarations associated with the given name.
|
|
///
|
|
/// \param name The name we're searching for.
|
|
void lookupValue(DeclName name, VisibleDeclConsumer &consumer) override;
|
|
|
|
/// Look up a type declaration by its Clang name.
|
|
///
|
|
/// Note that this method does no filtering. If it finds the type in a loaded
|
|
/// module, it returns it. This is intended for use in reflection / debugging
|
|
/// contexts where access is not a problem.
|
|
void lookupTypeDecl(StringRef clangName, ClangTypeKind kind,
|
|
llvm::function_ref<void(TypeDecl *)> receiver) override;
|
|
|
|
/// Look up type a declaration synthesized by the Clang importer itself, using
|
|
/// a "related entity kind" to determine which type it should be. For example,
|
|
/// this can be used to find the synthesized error struct for an
|
|
/// NS_ERROR_ENUM.
|
|
///
|
|
/// Note that this method does no filtering. If it finds the type in a loaded
|
|
/// module, it returns it. This is intended for use in reflection / debugging
|
|
/// contexts where access is not a problem.
|
|
void
|
|
lookupRelatedEntity(StringRef clangName, ClangTypeKind kind,
|
|
StringRef relatedEntityKind,
|
|
llvm::function_ref<void(TypeDecl *)> receiver) override;
|
|
|
|
StructDecl *
|
|
instantiateCXXClassTemplate(clang::ClassTemplateDecl *decl,
|
|
ArrayRef<clang::TemplateArgument> arguments) override;
|
|
|
|
ConcreteDeclRef getCXXFunctionTemplateSpecialization(
|
|
SubstitutionMap subst, ValueDecl *decl) override;
|
|
|
|
FuncDecl *getCXXSynthesizedOperatorFunc(FuncDecl *decl);
|
|
|
|
/// Just like Decl::getClangNode() except we look through to the 'Code'
|
|
/// enum of an error wrapper struct.
|
|
ClangNode getEffectiveClangNode(const Decl *decl) const override;
|
|
|
|
/// Look for textually included declarations from the bridging header.
|
|
///
|
|
/// \param filter returns true if the given clang decl/macro should be
|
|
/// imported and fed to the consumer
|
|
/// \param receiver will be fed decls as they are found and imported.
|
|
///
|
|
/// \c receiver is not a VisibleDeclConsumer so that it is not limited to
|
|
/// accepting ValueDecls only.
|
|
void lookupBridgingHeaderDecls(llvm::function_ref<bool(ClangNode)> filter,
|
|
llvm::function_ref<void(Decl*)> receiver) const;
|
|
|
|
/// Look for declarations from a particular header. The header may be part of
|
|
/// a clang module or included from the bridging header.
|
|
///
|
|
/// \param filename path to the header
|
|
/// \param filter returns true if the given clang decl/macro should be
|
|
/// imported and fed to the consumer
|
|
/// \param receiver will be fed decls as they are found and imported.
|
|
///
|
|
/// \c receiver is not a VisibleDeclConsumer so that it is not limited to
|
|
/// accepting ValueDecls only.
|
|
///
|
|
/// \returns true if there was a problem, e.g. the file does not exist.
|
|
bool lookupDeclsFromHeader(StringRef filename,
|
|
llvm::function_ref<bool(ClangNode)> filter,
|
|
llvm::function_ref<void(Decl*)> receiver) const;
|
|
|
|
/// 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) override;
|
|
|
|
virtual void loadObjCMethods(
|
|
NominalTypeDecl *typeDecl,
|
|
ObjCSelector selector,
|
|
bool isInstanceMethod,
|
|
unsigned previousGeneration,
|
|
llvm::TinyPtrVector<AbstractFunctionDecl *> &methods) override;
|
|
|
|
/// Adds a new search path to the Clang CompilerInstance, as if specified with
|
|
/// -I or -F.
|
|
///
|
|
/// \returns true if there was an error adding the search path.
|
|
bool addSearchPath(StringRef newSearchPath, bool isFramework,
|
|
bool isSystem) override;
|
|
|
|
/// Imports an Objective-C header file into the shared imported header module.
|
|
///
|
|
/// \param header A header name or full path, to be used in a \#import
|
|
/// directive.
|
|
/// \param adapter The module that depends on the contents of this header.
|
|
/// \param expectedSize The size of the header when the module was compiled
|
|
/// against it.
|
|
/// \param expectedModTime The mtime of the header when the module was
|
|
/// compiled against it.
|
|
/// \param cachedContents A buffer to use if the header has been modified
|
|
/// since the module was compiled.
|
|
/// \param diagLoc A location to attach any diagnostics to if import fails.
|
|
///
|
|
/// \returns true if there was an error importing the header.
|
|
///
|
|
/// \sa getImportedHeaderModule
|
|
bool importHeader(StringRef header, ModuleDecl *adapter, off_t expectedSize,
|
|
time_t expectedModTime, StringRef cachedContents,
|
|
SourceLoc diagLoc);
|
|
|
|
/// Imports an Objective-C header file into the shared imported header module.
|
|
///
|
|
/// \param header A header name or full path, to be used in a \#import
|
|
/// directive.
|
|
/// \param adapter The module that depends on the contents of this header.
|
|
/// \param diagLoc A location to attach any diagnostics to if import fails.
|
|
/// \param trackParsedSymbols If true, tracks decls and macros that were
|
|
/// parsed from the bridging header.
|
|
/// \param implicitImport If true, indicates that this import was implicit
|
|
/// from a reference in a module file (deprecated behavior).
|
|
///
|
|
/// \returns true if there was an error importing the header.
|
|
///
|
|
/// \sa getImportedHeaderModule
|
|
bool importBridgingHeader(StringRef header, ModuleDecl *adapter,
|
|
SourceLoc diagLoc = {},
|
|
bool trackParsedSymbols = false,
|
|
bool implicitImport = false);
|
|
|
|
/// Bind the bridging header content to the module.
|
|
///
|
|
/// \param adapter The module that depends on the contents of this header.
|
|
/// \param diagLoc A location to attach any diagnostics to if import fails.
|
|
///
|
|
/// \returns true if there was an error importing the header.
|
|
///
|
|
/// \sa importBridgingHeader
|
|
bool bindBridgingHeader(ModuleDecl *adapter, SourceLoc diagLoc);
|
|
|
|
/// Returns the module that contains imports and declarations from all loaded
|
|
/// Objective-C header files.
|
|
///
|
|
/// \sa importHeader
|
|
ModuleDecl *getImportedHeaderModule() const override;
|
|
|
|
/// Retrieves the Swift wrapper for the given Clang module, creating
|
|
/// it if necessary.
|
|
ModuleDecl *
|
|
getWrapperForModule(const clang::Module *mod,
|
|
bool returnOverlayIfPossible = false) const override;
|
|
|
|
std::string
|
|
getBridgingHeaderContents(StringRef headerPath, off_t &fileSize,
|
|
time_t &fileModTime,
|
|
StringRef pchIncludeTree);
|
|
|
|
/// Makes a temporary replica of the ClangImporter's CompilerInstance, reads
|
|
/// an Objective-C header file into the replica and emits a PCH file of its
|
|
/// content. Delegates to clang for everything except construction of the
|
|
/// replica.
|
|
///
|
|
/// \sa clang::GeneratePCHAction
|
|
bool emitBridgingPCH(StringRef headerPath, StringRef outputPCHPath,
|
|
bool cached);
|
|
|
|
/// Returns true if a clang CompilerInstance can successfully read in a PCH,
|
|
/// assuming it exists, with the current options. This can be used to find out
|
|
/// if we need to persist a PCH for later reuse.
|
|
bool canReadPCH(StringRef PCHFilename);
|
|
|
|
/// Reads the original source file name from PCH.
|
|
std::string getOriginalSourceFile(StringRef PCHFilename);
|
|
|
|
/// Makes a temporary replica of the ClangImporter's CompilerInstance, reads a
|
|
/// module map into the replica and emits a PCM file for one of the modules it
|
|
/// declares. Delegates to clang for everything except construction of the
|
|
/// replica.
|
|
bool emitPrecompiledModule(StringRef moduleMapPath, StringRef moduleName,
|
|
StringRef outputPath);
|
|
|
|
/// Makes a temporary replica of the ClangImporter's CompilerInstance and
|
|
/// dumps information about a PCM file (assumed to be generated by -emit-pcm
|
|
/// or in the Swift module cache). Delegates to clang for everything except
|
|
/// construction of the replica.
|
|
bool dumpPrecompiledModule(StringRef modulePath, StringRef outputPath);
|
|
|
|
bool runPreprocessor(StringRef inputPath, StringRef outputPath);
|
|
const clang::Module *getClangOwningModule(ClangNode Node) const override;
|
|
bool hasTypedef(const clang::Decl *typeDecl) const;
|
|
|
|
void verifyAllModules() override;
|
|
|
|
static void getBridgingHeaderOptions(
|
|
const ASTContext &ctx,
|
|
const clang::tooling::dependencies::TranslationUnitDeps &deps,
|
|
std::vector<std::string> &swiftArgs);
|
|
|
|
clang::TargetInfo &getModuleAvailabilityTarget() const override;
|
|
clang::ASTContext &getClangASTContext() const override;
|
|
clang::Preprocessor &getClangPreprocessor() const override;
|
|
clang::Sema &getClangSema() const override;
|
|
const clang::CompilerInstance &getClangInstance() const override;
|
|
|
|
/// ClangImporter's Clang instance may be configured with a different
|
|
/// (higher) OS version than the compilation target itself in order to be able
|
|
/// to load pre-compiled Clang modules that are aligned with the broader SDK,
|
|
/// and match the SDK deployment target against which Swift modules are also
|
|
/// built.
|
|
///
|
|
/// In this case, we must use the Swift compiler's OS version triple when
|
|
/// performing codegen, and the importer's Clang instance OS version triple
|
|
/// during module loading.
|
|
///
|
|
/// `ClangImporter`'s `Implementation` keeps track of a distinct `TargetInfo`
|
|
/// and `CodeGenOpts` containers that are meant to be used by clients in
|
|
/// IRGen. When a separate `-clang-target` is not set, they are defined to be
|
|
/// copies of the `ClangImporter`'s built-in module-loading Clang instance.
|
|
/// When `-clang-target` is set, they are configured with the Swift
|
|
/// compilation's target triple and OS version (but otherwise identical)
|
|
/// instead. To distinguish IRGen clients from module loading clients,
|
|
/// `getModuleAvailabilityTarget` should be used instead by module-loading
|
|
/// clients.
|
|
clang::TargetInfo &getTargetInfo() const;
|
|
clang::CodeGenOptions &getCodeGenOpts() const;
|
|
|
|
std::string getClangModuleHash() const;
|
|
|
|
/// Get clang import creation cc1 args for swift explicit module build.
|
|
std::vector<std::string> getSwiftExplicitModuleDirectCC1Args() const;
|
|
|
|
/// If we already imported a given decl successfully, return the corresponding
|
|
/// Swift decl as an Optional<Decl *>, but if we previously tried and failed
|
|
/// to import said decl then return nullptr.
|
|
/// Otherwise, if we have never encountered this decl previously then return
|
|
/// None.
|
|
std::optional<Decl *> importDeclCached(const clang::NamedDecl *ClangDecl);
|
|
|
|
// Returns true if it is expected that the macro is ignored.
|
|
bool shouldIgnoreMacro(StringRef Name, const clang::MacroInfo *Macro);
|
|
|
|
/// Returns the name of the given enum element as it would be imported into
|
|
/// Swift.
|
|
///
|
|
/// The return value may be an empty identifier, in which case the enum would
|
|
/// not be imported.
|
|
///
|
|
/// This is not used by the importer itself, but is used by the debugger.
|
|
Identifier getEnumConstantName(const clang::EnumConstantDecl *enumConstant);
|
|
|
|
/// Writes the mangled name of \p clangDecl to \p os.
|
|
void getMangledName(raw_ostream &os, const clang::NamedDecl *clangDecl) const;
|
|
|
|
// Print statistics from the Clang AST reader.
|
|
void printStatistics() const override;
|
|
|
|
/// Dump Swift lookup tables.
|
|
void dumpSwiftLookupTables() const override;
|
|
|
|
/// Given the path of a Clang module, collect the names of all its submodules.
|
|
/// Calling this function does not load the module.
|
|
void collectSubModuleNames(
|
|
ImportPath::Module path,
|
|
std::vector<std::string> &names) const;
|
|
|
|
/// Given a Clang module, decide whether this module is imported already.
|
|
static bool isModuleImported(const clang::Module *M);
|
|
|
|
DeclName importName(
|
|
const clang::NamedDecl *D,
|
|
clang::DeclarationName givenName = clang::DeclarationName()) override;
|
|
|
|
std::optional<Type>
|
|
importFunctionReturnType(const clang::FunctionDecl *clangDecl,
|
|
DeclContext *dc) override;
|
|
|
|
Type importVarDeclType(const clang::VarDecl *clangDecl,
|
|
VarDecl *swiftDecl,
|
|
DeclContext *dc) override;
|
|
|
|
std::optional<std::string>
|
|
getOrCreatePCH(const ClangImporterOptions &ImporterOptions,
|
|
StringRef SwiftPCHHash, bool Cached);
|
|
std::optional<std::string>
|
|
/// \param isExplicit true if the PCH filename was passed directly
|
|
/// with -import-objc-header option.
|
|
getPCHFilename(const ClangImporterOptions &ImporterOptions,
|
|
StringRef SwiftPCHHash, bool &isExplicit);
|
|
|
|
const clang::Type *parseClangFunctionType(StringRef type,
|
|
SourceLoc loc) const override;
|
|
void printClangType(const clang::Type *type,
|
|
llvm::raw_ostream &os) const override;
|
|
|
|
StableSerializationPath
|
|
findStableSerializationPath(const clang::Decl *decl) const override;
|
|
|
|
const clang::Decl *
|
|
resolveStableSerializationPath(
|
|
const StableSerializationPath &path) const override;
|
|
|
|
bool isSerializable(const clang::Type *type,
|
|
bool checkCanonical) const override;
|
|
|
|
clang::FunctionDecl *
|
|
instantiateCXXFunctionTemplate(ASTContext &ctx,
|
|
clang::FunctionTemplateDecl *func,
|
|
SubstitutionMap subst) override;
|
|
|
|
bool isSynthesizedAndVisibleFromAllModules(const clang::Decl *decl);
|
|
|
|
bool isCXXMethodMutating(const clang::CXXMethodDecl *method) override;
|
|
|
|
bool isUnsafeCXXMethod(const FuncDecl *func) override;
|
|
|
|
FuncDecl *getDefaultArgGenerator(const clang::ParmVarDecl *param) override;
|
|
|
|
FuncDecl *getAvailabilityDomainPredicate(const clang::VarDecl *var) override;
|
|
|
|
bool isAnnotatedWith(const clang::CXXMethodDecl *method, StringRef attr);
|
|
|
|
/// Find the lookup table that corresponds to the given Clang module.
|
|
///
|
|
/// \param clangModule The module, or null to indicate that we're talking
|
|
/// about the directly-parsed headers.
|
|
SwiftLookupTable *findLookupTable(const clang::Module *clangModule) override;
|
|
|
|
/// Determine the effective Clang context for the given Swift nominal type.
|
|
EffectiveClangContext
|
|
getEffectiveClangContext(const NominalTypeDecl *nominal) override;
|
|
|
|
/// Imports a clang decl directly, rather than looking up it's name.
|
|
Decl *importDeclDirectly(const clang::NamedDecl *decl) override;
|
|
|
|
ValueDecl *importBaseMemberDecl(ValueDecl *decl, DeclContext *newContext,
|
|
ClangInheritanceInfo inheritance) override;
|
|
|
|
ValueDecl *getOriginalForClonedMember(const ValueDecl *decl) override;
|
|
|
|
/// Emits diagnostics for any declarations named name
|
|
/// whose direct declaration context is a TU.
|
|
void diagnoseTopLevelValue(const DeclName &name) override;
|
|
|
|
/// Emit diagnostics for declarations named name that are members
|
|
/// of the provided baseType.
|
|
void diagnoseMemberValue(const DeclName &name, const Type &baseType) override;
|
|
|
|
const clang::TypedefType *getTypeDefForCXXCFOptionsDefinition(
|
|
const clang::Decl *candidateDecl) override;
|
|
|
|
/// Create cache key for embedded bridging header.
|
|
static llvm::Expected<llvm::cas::ObjectRef>
|
|
createEmbeddedBridgingHeaderCacheKey(
|
|
llvm::cas::ObjectStore &CAS, llvm::cas::ObjectRef ChainedPCHIncludeTree);
|
|
|
|
SourceLoc importSourceLocation(clang::SourceLocation loc) override;
|
|
};
|
|
|
|
ImportDecl *createImportDecl(ASTContext &Ctx, DeclContext *DC, ClangNode ClangN,
|
|
ArrayRef<clang::Module *> Exported);
|
|
|
|
/// Extract the specified-or-defaulted -module-cache-path that winds up in
|
|
/// the clang importer, for reuse as the .swiftmodule cache path when
|
|
/// building a ModuleInterfaceLoader.
|
|
std::string
|
|
getModuleCachePathFromClang(const clang::CompilerInstance &Instance);
|
|
|
|
/// Whether the given parameter name identifies a completion handler.
|
|
bool isCompletionHandlerParamName(StringRef paramName);
|
|
|
|
namespace importer {
|
|
/// Returns true if the given C/C++ reference type uses "immortal"
|
|
/// retain/release functions.
|
|
bool hasImmortalAttrs(const clang::RecordDecl *decl);
|
|
|
|
struct ReturnOwnershipInfo {
|
|
ReturnOwnershipInfo(const clang::NamedDecl *decl);
|
|
|
|
bool hasRetainAttr() const {
|
|
return hasReturnsRetained || hasReturnsUnretained;
|
|
}
|
|
bool hasConflictingAttr() const {
|
|
return hasReturnsRetained && hasReturnsUnretained;
|
|
}
|
|
|
|
private:
|
|
bool hasReturnsRetained = false;
|
|
bool hasReturnsUnretained = false;
|
|
};
|
|
|
|
/// Returns true if the given module has a 'cplusplus' requirement.
|
|
bool requiresCPlusPlus(const clang::Module *module);
|
|
|
|
/// Returns true if the given module is one of the C++ standard library modules.
|
|
/// This could be the top-level std module, or any of the libc++ split modules
|
|
/// (std_vector, std_iosfwd, etc).
|
|
bool isCxxStdModule(const clang::Module *module);
|
|
|
|
/// Returns true if the given module is one of the C++ standard library modules.
|
|
/// This could be the top-level std module, or any of the libc++ split modules
|
|
/// (std_vector, std_iosfwd, etc).
|
|
bool isCxxStdModule(StringRef moduleName, bool IsSystem);
|
|
|
|
/// Returns the pointee type if the given type is a C++ `const`
|
|
/// reference type, `None` otherwise.
|
|
std::optional<clang::QualType>
|
|
getCxxReferencePointeeTypeOrNone(const clang::Type *type);
|
|
|
|
/// Returns true if the given type is a C++ `const` reference type.
|
|
bool isCxxConstReferenceType(const clang::Type *type);
|
|
|
|
/// Determine whether the given Clang record declaration has one of the
|
|
/// attributes that makes it import as a reference types.
|
|
bool hasImportAsRefAttr(const clang::RecordDecl *decl);
|
|
|
|
/// Determine whether this typedef is a CF type.
|
|
bool isCFTypeDecl(const clang::TypedefNameDecl *Decl);
|
|
|
|
/// Determine the imported CF type for the given typedef-name, or the empty
|
|
/// string if this is not an imported CF type name.
|
|
llvm::StringRef getCFTypeName(const clang::TypedefNameDecl *decl);
|
|
|
|
/// Lookup and return the synthesized conformance operator like '==' '-' or '+='
|
|
/// for the given type.
|
|
ValueDecl *getImportedMemberOperator(const DeclBaseName &name,
|
|
NominalTypeDecl *selfType,
|
|
std::optional<Type> parameterType);
|
|
|
|
/// Map the access specifier of a Clang record member to a Swift access level.
|
|
///
|
|
/// This mapping is conservative: the resulting Swift access should be at _most_
|
|
/// as permissive as the input C++ access.
|
|
AccessLevel convertClangAccess(clang::AccessSpecifier access);
|
|
|
|
/// Read file IDs from 'private_fileid' Swift attributes on a Clang decl.
|
|
///
|
|
/// May return >1 fileID when a decl is annotated more than once, which should
|
|
/// be treated as an error and appropriately diagnosed (using the included
|
|
/// SourceLocation).
|
|
///
|
|
/// The returned fileIDs may not be of a valid format (e.g., missing a '/'),
|
|
/// and should be parsed using swift::SourceFile::FileIDStr::parse().
|
|
SmallVector<std::pair<StringRef, clang::SourceLocation>, 1>
|
|
getPrivateFileIDAttrs(const clang::CXXRecordDecl *decl);
|
|
|
|
/// Use some heuristics to determine whether the clang::Decl associated with
|
|
/// \a decl would not exist without C++ interop.
|
|
///
|
|
/// For instance, a namespace is C++-only, but a plain struct is valid in both
|
|
/// C and C++.
|
|
///
|
|
/// Returns false if \a decl was not imported by ClangImporter.
|
|
bool declIsCxxOnly(const Decl *decl);
|
|
|
|
/// Is this DeclContext an `enum` that represents a C++ namespace?
|
|
bool isClangNamespace(const DeclContext *dc);
|
|
|
|
/// For some \a templatedClass that inherits from \a base, whether they are
|
|
/// derived from the same class template.
|
|
///
|
|
/// This kind of circular inheritance can happen when a templated class inherits
|
|
/// from a specialization of itself, e.g.:
|
|
///
|
|
/// template <typename T> class C;
|
|
/// template <> class C<void> { /* ... */ };
|
|
/// template <typename T> class C<T> : C<void> { /* ... */ };
|
|
///
|
|
/// Checking for this kind of scenario is necessary for avoiding infinite
|
|
/// recursion during symbolic imports (importSymbolicCXXDecls), where
|
|
/// specialized class templates are instead imported as unspecialized.
|
|
bool isSymbolicCircularBase(const clang::CXXRecordDecl *templatedClass,
|
|
const clang::RecordDecl *base);
|
|
|
|
/// Match a `[[swift_attr("...")]]` annotation on the given Clang decl.
|
|
///
|
|
/// \param decl The Clang declaration to inspect.
|
|
/// \param patterns List of (attribute name, value) pairs.
|
|
/// \returns The value for the first matching attribute, or `std::nullopt`.
|
|
template <typename T>
|
|
std::optional<T>
|
|
matchSwiftAttr(const clang::Decl *decl,
|
|
llvm::ArrayRef<std::pair<llvm::StringRef, T>> patterns) {
|
|
if (!decl || !decl->hasAttrs())
|
|
return std::nullopt;
|
|
|
|
for (const auto *attr : decl->getAttrs()) {
|
|
if (const auto *swiftAttr = llvm::dyn_cast<clang::SwiftAttrAttr>(attr)) {
|
|
for (const auto &p : patterns) {
|
|
if (swiftAttr->getAttribute() == p.first)
|
|
return p.second;
|
|
}
|
|
}
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
/// Like `matchSwiftAttr`, but also searches C++ base classes.
|
|
///
|
|
/// \param decl The Clang declaration to inspect.
|
|
/// \param patterns List of (attribute name, value) pairs.
|
|
/// \returns The matched value from this decl or its bases, or `std::nullopt`.
|
|
template <typename T>
|
|
std::optional<T> matchSwiftAttrConsideringInheritance(
|
|
const clang::Decl *decl,
|
|
llvm::ArrayRef<std::pair<llvm::StringRef, T>> patterns) {
|
|
if (!decl)
|
|
return std::nullopt;
|
|
|
|
if (auto match = matchSwiftAttr<T>(decl, patterns))
|
|
return match;
|
|
|
|
if (const auto *recordDecl = llvm::dyn_cast<clang::CXXRecordDecl>(decl)) {
|
|
std::optional<T> result;
|
|
if (recordDecl->isCompleteDefinition()) {
|
|
recordDecl->forallBases([&](const clang::CXXRecordDecl *base) -> bool {
|
|
if (auto baseMatch = matchSwiftAttr<T>(base, patterns)) {
|
|
result = baseMatch;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
});
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
/// Matches a `swift_attr("...")` on the record type pointed to by the given
|
|
/// Clang type, searching base classes if it's a C++ class.
|
|
///
|
|
/// \param type A Clang pointer or reference type.
|
|
/// \param patterns List of attribute name-value pairs to match.
|
|
/// \returns Matched value or std::nullopt.
|
|
template <typename T>
|
|
std::optional<T> matchSwiftAttrOnRecordPtr(
|
|
const clang::QualType &type,
|
|
llvm::ArrayRef<std::pair<llvm::StringRef, T>> patterns) {
|
|
clang::QualType pointeeType;
|
|
if (const auto *ptrType = type->getAs<clang::PointerType>()) {
|
|
pointeeType = ptrType->getPointeeType();
|
|
} else if (const auto *refType = type->getAs<clang::ReferenceType>()) {
|
|
pointeeType = refType->getPointeeType();
|
|
} else {
|
|
return std::nullopt;
|
|
}
|
|
|
|
if (const auto *recordDecl = pointeeType->getAsRecordDecl()) {
|
|
return matchSwiftAttrConsideringInheritance<T>(recordDecl, patterns);
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
/// Determines the C++ reference ownership convention for the return value
|
|
/// using `SWIFT_RETURNS_(UN)RETAINED` on the API; falls back to
|
|
/// `SWIFT_RETURNED_AS_(UN)RETAINED_BY_DEFAULT` on the pointee record type.
|
|
///
|
|
/// \param decl The Clang function or method declaration to inspect.
|
|
/// \returns Matched `ResultConvention`, or `std::nullopt` if none applies.
|
|
std::optional<ResultConvention>
|
|
getCxxRefConventionWithAttrs(const clang::Decl *decl);
|
|
} // namespace importer
|
|
|
|
struct ClangInvocationFileMapping {
|
|
/// Mapping from a file name to an existing file path.
|
|
SmallVector<std::pair<std::string, std::string>, 2> redirectedFiles;
|
|
|
|
/// Mapping from a file name to a string of characters that represents the
|
|
/// contents of the file.
|
|
SmallVector<std::pair<std::string, std::string>, 1> overridenFiles;
|
|
|
|
bool requiresBuiltinHeadersInSystemModules;
|
|
};
|
|
|
|
class ClangInvocationFileMappingContext {
|
|
public:
|
|
const LangOptions &LangOpts;
|
|
SearchPathOptions &SearchPathOpts;
|
|
ClangImporterOptions &ClangImporterOpts;
|
|
const CASOptions &CASOpts;
|
|
DiagnosticEngine &Diags;
|
|
|
|
ClangInvocationFileMappingContext(
|
|
const LangOptions &LangOpts, SearchPathOptions &SearchPathOpts,
|
|
ClangImporterOptions &ClangImporterOpts, const CASOptions &CASOpts,
|
|
DiagnosticEngine &Diags)
|
|
: LangOpts(LangOpts), SearchPathOpts(SearchPathOpts),
|
|
ClangImporterOpts(ClangImporterOpts), CASOpts(CASOpts),
|
|
Diags(Diags) {}
|
|
|
|
ClangInvocationFileMappingContext(const swift::ASTContext &Ctx);
|
|
};
|
|
|
|
/// On Linux, some platform libraries (glibc, libstdc++) are not modularized.
|
|
/// We inject modulemaps for those libraries into their include directories
|
|
/// to allow using them from Swift.
|
|
///
|
|
/// `suppressDiagnostic` prevents us from emitting warning messages when we
|
|
/// are unable to find headers.
|
|
ClangInvocationFileMapping getClangInvocationFileMapping(
|
|
const ClangInvocationFileMappingContext &ctx,
|
|
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs = nullptr,
|
|
bool suppressDiagnostic = false);
|
|
|
|
/// Apply the given file mapping to the specified 'fileSystem', used
|
|
/// primarily to inject modulemaps on platforms with non-modularized
|
|
/// platform libraries.
|
|
ClangInvocationFileMapping applyClangInvocationMapping(
|
|
const ClangInvocationFileMappingContext &ctx,
|
|
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> baseVFS,
|
|
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> &fileSystem,
|
|
bool suppressDiagnostics = false);
|
|
|
|
/// Information used to compute the access level of inherited C++ members.
|
|
class ClangInheritanceInfo {
|
|
/// The cumulative inheritance access specifier, that is used to compute the
|
|
/// effective access level of a particular inherited member.
|
|
///
|
|
/// When constructing ClangInheritanceInfo for nested inheritance, this field
|
|
/// gets clamped to the least permissive level between its current value and
|
|
/// the inheritance access specifier.
|
|
///
|
|
/// If we encounter \e nested private inheritance in the class hierarchy
|
|
/// (i.e., private inheritance beyond the first level of inheritance), we set
|
|
/// the access level to nullopt to indicate that none of the members from
|
|
/// classes beyond that point in the hierarchy should be accessible. This case
|
|
/// must be treated separately from non-nested private inheritance, where
|
|
/// inherited members are private but accessible from extensions.
|
|
///
|
|
/// See ClangInheritanceInfo::cumulativeInheritedAccess() for an example.
|
|
std::optional<clang::AccessSpecifier> access;
|
|
|
|
public:
|
|
/// Default constructor for this class that is used as the base case when
|
|
/// recursively walking up a class inheritance hierarchy.
|
|
ClangInheritanceInfo() : access(clang::AS_none) {}
|
|
|
|
/// Inductive case for this class that is used to accumulate inheritance
|
|
/// metadata for cases of (nested) inheritance.
|
|
ClangInheritanceInfo(ClangInheritanceInfo prev, clang::CXXBaseSpecifier base)
|
|
: access(computeAccess(prev, base)) {}
|
|
|
|
/// Whether this info represents a case of nested private inheritance.
|
|
bool isNestedPrivate() const { return !access.has_value(); }
|
|
|
|
/// Whether this info represents a case of C++ inheritance.
|
|
///
|
|
/// Returns \c false for the default instance of this class.
|
|
bool isInheriting() const {
|
|
return isNestedPrivate() || *access != clang::AS_none;
|
|
}
|
|
|
|
/// Whether this is info represents a case of C++ inheritance.
|
|
operator bool() const { return isInheriting(); }
|
|
|
|
/// Compute the (Swift) access level for inherited base member \param decl,
|
|
/// for when its inherited (cloned) member in the derived class.
|
|
///
|
|
/// This access level is determined by whichever is more restrictive: what the
|
|
/// \param decl was declared with (in its base class), or what it is being
|
|
/// inherited with (ClangInheritanceInfo::access).
|
|
///
|
|
/// Always returns swift::AccessLevel::Public (i.e., corresponding to
|
|
/// clang::AS_none) if this ClangInheritanceInfo::isInheriting() is \c false.
|
|
AccessLevel accessForBaseDecl(const ValueDecl *baseDecl) const;
|
|
|
|
/// Marks \param clonedDecl as unavailable (using \c @available) if it
|
|
/// cannot be accessed from the derived class, either because \param baseDecl
|
|
/// was declared as private in the base class, or because \param clonedDecl
|
|
/// was inherited with private inheritance.
|
|
///
|
|
/// Does nothing if this ClangInheritanceInfo::isInheriting() is \c false.
|
|
void setUnavailableIfNecessary(const ValueDecl *baseDecl,
|
|
ValueDecl *clonedDecl) const;
|
|
|
|
friend llvm::hash_code hash_value(const ClangInheritanceInfo &info) {
|
|
return llvm::hash_combine(info.access);
|
|
}
|
|
|
|
private:
|
|
/// An example of how ClangInheritanceInfo:access is accumulated while
|
|
/// recursively traversing the class hierarchy starting from \c E:
|
|
///
|
|
/// \code{.cpp}
|
|
/// struct A { ... }; // access = nullopt (nested private)
|
|
/// struct B : private A { ... }; // access = protected
|
|
/// struct C : public B { ... }; // access = protected
|
|
/// struct D : protected C { ... }; // access = public
|
|
/// struct E : public D { ... }; // access = none [base case]
|
|
/// \endcode
|
|
///
|
|
/// Another example, this time with non-nested private inheritance:
|
|
///
|
|
/// \code{.cpp}
|
|
/// struct A { ... }; // access = nullopt
|
|
/// struct B : public A { ... }; // access = nullopt
|
|
/// struct C : private B { ... }; // access = private
|
|
/// struct D : public C { ... }; // access = private
|
|
/// struct E : private D { ... }; // access = none [base case]
|
|
/// \endcode
|
|
static std::optional<clang::AccessSpecifier>
|
|
computeAccess(ClangInheritanceInfo prev, clang::CXXBaseSpecifier base) {
|
|
auto baseAccess = base.getAccessSpecifier();
|
|
assert(baseAccess != clang::AS_none &&
|
|
"this should always be public, protected, or private");
|
|
|
|
if (!prev.isInheriting())
|
|
// This is the first level of inheritance, so we just take the access
|
|
// specifier from CXXBaseSpecifier. Note that this is the only scenario
|
|
// where we can have access = private.
|
|
return {baseAccess};
|
|
|
|
if (prev.isNestedPrivate() || baseAccess == clang::AS_private)
|
|
// This is a case of nested inheritance, and either we encountered nested
|
|
// private inheritance before, or this is our first time encountering it.
|
|
return std::nullopt;
|
|
|
|
static_assert(clang::AS_private > clang::AS_protected &&
|
|
clang::AS_protected > clang::AS_public &&
|
|
"using std::max() relies on this ordering");
|
|
return {std::max(*prev.access, baseAccess)};
|
|
}
|
|
};
|
|
|
|
} // end namespace swift
|
|
|
|
#endif
|