Files
swift-mirror/include/swift/ClangImporter/ClangImporter.h
Xi Ge bbe5b83de9 Parser: teach canImport to take an additional parameter indicating the minimum module version
canImport should be able to take an additional parameter labeled by either version or
underlyingVersion. We need underlyingVersion for clang modules with Swift overlays because they
have separate version numbers. The library users are usually interested in checking the importability
of the underlying clang module instead of its Swift overlay.

Part of rdar://73992299
2021-05-02 17:47:44 -07:00

502 lines
20 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/ClangModuleLoader.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 clang {
class ASTContext;
class CodeGenOptions;
class Decl;
class DependencyCollector;
class DiagnosticConsumer;
class EnumConstantDecl;
class EnumDecl;
class MacroInfo;
class Module;
class NamedDecl;
class Sema;
class TargetInfo;
class Type;
class VisibleDeclConsumer;
class DeclarationName;
class CompilerInvocation;
namespace tooling {
namespace dependencies {
struct FullDependenciesResult;
}
}
}
namespace swift {
class ASTContext;
class CompilerInvocation;
class ClangImporterOptions;
class ClangModuleUnit;
class ClangNode;
class Decl;
class DeclContext;
class EnumDecl;
class ImportDecl;
class IRGenOptions;
class ModuleDecl;
class NominalTypeDecl;
class StructDecl;
class TypeDecl;
class VisibleDeclConsumer;
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, llvm::Optional<ClangTypeKind> kind,
StringRef inModule,
SmallVectorImpl<clang::Decl *> &results) {}
/// vtable anchor.
virtual void anchor();
};
/// Class that imports Clang modules into Swift, mapping directly
/// from Clang ASTs over to Swift ASTs.
class ClangImporter final : public ClangModuleLoader {
friend class ClangModuleUnit;
public:
class Implementation;
private:
Implementation &Impl;
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);
static std::vector<std::string>
getClangArguments(ASTContext &ctx);
static std::unique_ptr<clang::CompilerInvocation>
createClangInvocation(ClangImporter *importer,
const ClangImporterOptions &importerOpts,
ArrayRef<std::string> invocationArgStrs,
std::vector<std::string> *CC1Args = nullptr);
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);
/// 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.
virtual bool canImportModule(ImportPath::Element named, llvm::VersionTuple version,
bool underlyingVersion) 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.
///
/// \returns the module referenced, if it could be loaded. Otherwise,
/// emits a diagnostic and returns NULL.
virtual ModuleDecl *loadModule(
SourceLoc importLoc,
ImportPath::Module path)
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;
/// Just like Decl::getClangNode() except we look through to the 'Code'
/// enum of an error wrapper struct.
ClangNode getEffectiveClangNode(const Decl *decl) const;
/// 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(
ClassDecl *classDecl,
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);
/// 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);
/// 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);
/// 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);
/// 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;
bool hasTypedef(const clang::Decl *typeDecl) const;
void verifyAllModules() override;
void recordModuleDependencies(
ModuleDependenciesCache &cache,
const clang::tooling::dependencies::FullDependenciesResult &clangDependencies);
Optional<ModuleDependencies> getModuleDependencies(
StringRef moduleName, ModuleDependenciesCache &cache,
InterfaceSubContextDelegate &delegate) override;
/// Add dependency information for the bridging header.
///
/// \param moduleName the name of the Swift module whose dependency
/// information will be augmented with information about the given
/// bridging header.
///
/// \param cache The module dependencies cache to update, with information
/// about new Clang modules discovered along the way.
///
/// \returns \c true if an error occurred, \c false otherwise
bool addBridgingHeaderDependencies(
StringRef moduleName, ModuleDependenciesCache &cache);
clang::TargetInfo &getTargetInfo() const override;
clang::ASTContext &getClangASTContext() const override;
clang::Preprocessor &getClangPreprocessor() const override;
clang::Sema &getClangSema() const override;
const clang::CompilerInstance &getClangInstance() const override;
clang::CodeGenOptions &getClangCodeGenOpts() const;
std::string getClangModuleHash() const;
/// If we already imported a given decl, return the corresponding Swift decl.
/// Otherwise, return nullptr.
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();
/// 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);
Optional<std::string>
getOrCreatePCH(const ClangImporterOptions &ImporterOptions,
StringRef SwiftPCHHash);
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;
};
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);
} // end namespace swift
#endif