| //===--- 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) 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; |
| |
| /// 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); |
| |
| } // end namespace swift |
| |
| #endif |