mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
- Add CompilerInvocation::getPCHHash
This will be used when creating a unique filename for a persistent
precompiled bridging header.
- Automatically generate and use a precompiled briding header
When we're given both -import-objc-header and -pch-output-dir
arguments, we will try to:
- Validate what we think the PCH filename should be for the bridging
header, based on the Swift PCH hash and the clang module hash.
- If we're successful, we'll just use it.
- If it's out of date or something else is wrong, we'll try to
emit it.
- This gives us a single filename which we can `stat` to check for the
validity of our code completion cache, which is keyed off of module
name, module filename, and module file age.
- Cache code completion results from imported modules
If we just have a single .PCH file imported, we can use that file as
part of the key used to cache declarations in a module. Because
multiple files can contribute to the __ObjC module, we've always given
it the phony filename "<imports>", which never exists, so `stat`-ing it
always fails and we never cache declarations in it.
This is extremely problematic for projects with huge bridging headers.
In the case where we have a single PCH import, this can bring warm code
completion times down to about 500ms from over 2-3s, so it can provide a
nice performance win for IDEs.
- Add a new test that performs two code-completion requests with a bridging header.
- Add some -pch-output-dir flags to existing SourceKit tests that import a bridging
header.
rdar://problem/31198982
322 lines
12 KiB
C++
322 lines
12 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;
|
|
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 VisibleDeclConsumer;
|
|
class DeclarationName;
|
|
}
|
|
|
|
namespace swift {
|
|
class ASTContext;
|
|
class CompilerInvocation;
|
|
class ClangImporterOptions;
|
|
class ClangModuleUnit;
|
|
class ClangNode;
|
|
class Decl;
|
|
class DeclContext;
|
|
class ImportDecl;
|
|
class IRGenOptions;
|
|
class LazyResolver;
|
|
class ModuleDecl;
|
|
class NominalTypeDecl;
|
|
class VisibleDeclConsumer;
|
|
enum class SelectorSplitKind;
|
|
|
|
/// \brief 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, const ClangImporterOptions &clangImporterOpts,
|
|
DependencyTracker *tracker);
|
|
|
|
public:
|
|
/// \brief 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 importerOpts The options to use 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.
|
|
///
|
|
/// \returns a new Clang module importer, or null (with a diagnostic) if
|
|
/// an error occurred.
|
|
static std::unique_ptr<ClangImporter>
|
|
create(ASTContext &ctx,
|
|
const ClangImporterOptions &importerOpts,
|
|
std::string swiftPCHHash = "",
|
|
DependencyTracker *tracker = nullptr);
|
|
|
|
ClangImporter(const ClangImporter &) = delete;
|
|
ClangImporter(ClangImporter &&) = delete;
|
|
ClangImporter &operator=(const ClangImporter &) = delete;
|
|
ClangImporter &operator=(ClangImporter &&) = delete;
|
|
|
|
~ClangImporter();
|
|
|
|
/// \brief Create a new clang::DependencyCollector customized to
|
|
/// ClangImporter's specific uses.
|
|
static std::shared_ptr<clang::DependencyCollector>
|
|
createDependencyCollector();
|
|
|
|
/// \brief 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(std::pair<Identifier, SourceLoc> named) override;
|
|
|
|
/// \brief 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,
|
|
ArrayRef<std::pair<Identifier, SourceLoc>> path)
|
|
override;
|
|
|
|
/// \brief Look for declarations associated with the given name.
|
|
///
|
|
/// \param name The name we're searching for.
|
|
void lookupValue(DeclName name, VisibleDeclConsumer &consumer);
|
|
|
|
/// 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;
|
|
|
|
/// \brief 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;
|
|
|
|
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,
|
|
clang::DiagnosticConsumer *Diags = nullptr);
|
|
|
|
/// 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);
|
|
|
|
const clang::Module *getClangOwningModule(ClangNode Node) const;
|
|
bool hasTypedef(const clang::Decl *typeDecl) const;
|
|
|
|
void verifyAllModules() override;
|
|
|
|
void setTypeResolver(LazyResolver &resolver);
|
|
void clearTypeResolver();
|
|
|
|
clang::TargetInfo &getTargetInfo() const;
|
|
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;
|
|
|
|
using ClangModuleLoader::addDependency;
|
|
|
|
// 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(
|
|
ArrayRef<std::pair<Identifier, SourceLoc>> path,
|
|
std::vector<std::string> &names);
|
|
|
|
/// 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,
|
|
const std::string &SwiftPCHHash);
|
|
Optional<std::string>
|
|
getPCHFilename(const ClangImporterOptions &ImporterOptions,
|
|
const std::string &SwiftPCHHash);
|
|
};
|
|
|
|
ImportDecl *createImportDecl(ASTContext &Ctx, DeclContext *DC, ClangNode ClangN,
|
|
ArrayRef<clang::Module *> Exported);
|
|
}
|
|
|
|
#endif
|