mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Cache Code Completion results from PCH files
- 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
This commit is contained in:
@@ -209,6 +209,12 @@ public:
|
||||
return OutputKind == IRGenOutputKind::LLVMAssembly;
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a hash code of any components from these options that should
|
||||
/// contribute to a Swift Bridging PCH hash.
|
||||
llvm::hash_code getPCHHashComponents() const {
|
||||
return llvm::hash_value(0);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace swift
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#define SWIFT_AST_SILOPTIONS_H
|
||||
|
||||
#include "swift/Basic/Sanitizers.h"
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include <string>
|
||||
#include <climits>
|
||||
@@ -147,6 +148,11 @@ public:
|
||||
|
||||
SILOptions() : Sanitize(SanitizerKind::None) {}
|
||||
|
||||
/// Return a hash code of any components from these options that should
|
||||
/// contribute to a Swift Bridging PCH hash.
|
||||
llvm::hash_code getPCHHashComponents() const {
|
||||
return llvm::hash_value(0);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace swift
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#ifndef SWIFT_AST_SEARCHPATHOPTIONS_H
|
||||
#define SWIFT_AST_SEARCHPATHOPTIONS_H
|
||||
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -67,6 +69,26 @@ public:
|
||||
|
||||
/// Don't look in for compiler-provided modules.
|
||||
bool SkipRuntimeLibraryImportPath = false;
|
||||
|
||||
/// Return a hash code of any components from these options that should
|
||||
/// contribute to a Swift Bridging PCH hash.
|
||||
llvm::hash_code getPCHHashComponents() const {
|
||||
using llvm::hash_value;
|
||||
using llvm::hash_combine;
|
||||
auto Code = hash_value(SDKPath);
|
||||
for (auto Import : ImportSearchPaths) {
|
||||
Code = hash_combine(Code, Import);
|
||||
}
|
||||
for (const auto &FrameworkPath : FrameworkSearchPaths) {
|
||||
Code = hash_combine(Code, FrameworkPath.Path);
|
||||
}
|
||||
for (auto LibraryPath : LibrarySearchPaths) {
|
||||
Code = hash_combine(Code, LibraryPath);
|
||||
}
|
||||
Code = hash_combine(Code, RuntimeResourcePath);
|
||||
Code = hash_combine(Code, RuntimeLibraryImportPath);
|
||||
return Code;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -49,6 +49,13 @@ public:
|
||||
|
||||
/// Treat all warnings as errors
|
||||
bool WarningsAsErrors = false;
|
||||
|
||||
/// Return a hash code of any components from these options that should
|
||||
/// contribute to a Swift Bridging PCH hash.
|
||||
llvm::hash_code getPCHHashComponents() const {
|
||||
// Nothing here that contributes anything significant when emitting the PCH.
|
||||
return llvm::hash_value(0);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace swift
|
||||
|
||||
@@ -22,9 +22,12 @@
|
||||
#include "swift/Basic/Version.h"
|
||||
#include "clang/Basic/VersionTuple.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -278,6 +281,17 @@ namespace swift {
|
||||
PlatformConditionKind Kind, StringRef Value,
|
||||
std::vector<StringRef> &suggestions);
|
||||
|
||||
/// Return a hash code of any components from these options that should
|
||||
/// contribute to a Swift Bridging PCH hash.
|
||||
llvm::hash_code getPCHHashComponents() const {
|
||||
auto code = llvm::hash_value(Target.str());
|
||||
SmallString<16> Scratch;
|
||||
llvm::raw_svector_ostream OS(Scratch);
|
||||
OS << EffectiveLanguageVersion;
|
||||
code = llvm::hash_combine(code, OS.str());
|
||||
return code;
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::SmallVector<std::pair<PlatformConditionKind, std::string>,
|
||||
NumPlatformConditionKind>
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace clang {
|
||||
class CodeGenOptions;
|
||||
class Decl;
|
||||
class DependencyCollector;
|
||||
class DiagnosticConsumer;
|
||||
class EnumConstantDecl;
|
||||
class EnumDecl;
|
||||
class MacroInfo;
|
||||
@@ -44,6 +45,7 @@ namespace clang {
|
||||
|
||||
namespace swift {
|
||||
class ASTContext;
|
||||
class CompilerInvocation;
|
||||
class ClangImporterOptions;
|
||||
class ClangModuleUnit;
|
||||
class ClangNode;
|
||||
@@ -78,14 +80,19 @@ public:
|
||||
/// \param ctx The ASTContext into which the module will be imported.
|
||||
/// The ASTContext's SearchPathOptions will be used for the Clang importer.
|
||||
///
|
||||
/// \param clangImporterOpts The options to use 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 &clangImporterOpts,
|
||||
create(ASTContext &ctx,
|
||||
const ClangImporterOptions &importerOpts,
|
||||
std::string swiftPCHHash = "",
|
||||
DependencyTracker *tracker = nullptr);
|
||||
|
||||
ClangImporter(const ClangImporter &) = delete;
|
||||
@@ -234,7 +241,14 @@ public:
|
||||
/// replica.
|
||||
///
|
||||
/// \sa clang::GeneratePCHAction
|
||||
bool emitBridgingPCH(StringRef headerPath, StringRef outputPCHPath);
|
||||
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;
|
||||
@@ -291,6 +305,13 @@ public:
|
||||
|
||||
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,
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#ifndef SWIFT_CLANGIMPORTER_CLANGIMPORTEROPTIONS_H
|
||||
#define SWIFT_CLANGIMPORTER_CLANGIMPORTEROPTIONS_H
|
||||
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -43,7 +45,7 @@ public:
|
||||
std::string PrecompiledHeaderOutputDir;
|
||||
|
||||
/// \see Mode
|
||||
enum class Modes {
|
||||
enum class Modes : uint8_t {
|
||||
/// Set up Clang for importing modules into Swift and generating IR from
|
||||
/// Swift code.
|
||||
Normal,
|
||||
@@ -84,6 +86,28 @@ public:
|
||||
|
||||
/// When set, don't look for or load adapter modules.
|
||||
bool DisableAdapterModules = false;
|
||||
|
||||
/// Return a hash code of any components from these options that should
|
||||
/// contribute to a Swift Bridging PCH hash.
|
||||
llvm::hash_code getPCHHashComponents() const {
|
||||
using llvm::hash_value;
|
||||
using llvm::hash_combine;
|
||||
|
||||
auto Code = hash_value(ModuleCachePath);
|
||||
// ExtraArgs ignored - already considered in Clang's module hashing.
|
||||
Code = hash_combine(Code, OverrideResourceDir);
|
||||
Code = hash_combine(Code, TargetCPU);
|
||||
Code = hash_combine(Code, BridgingHeader);
|
||||
Code = hash_combine(Code, PrecompiledHeaderOutputDir);
|
||||
Code = hash_combine(Code, static_cast<uint8_t>(Mode));
|
||||
Code = hash_combine(Code, DetailedPreprocessingRecord);
|
||||
Code = hash_combine(Code, ImportForwardDeclarations);
|
||||
Code = hash_combine(Code, InferImportAsMember);
|
||||
Code = hash_combine(Code, DisableSwiftBridgeAttr);
|
||||
Code = hash_combine(Code, DisableModulesValidateSystemHeaders);
|
||||
Code = hash_combine(Code, DisableAdapterModules);
|
||||
return Code;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace swift
|
||||
|
||||
@@ -292,6 +292,11 @@ public:
|
||||
bool isDelayedFunctionBodyParsing() const {
|
||||
return FrontendOpts.DelayedFunctionBodyParsing;
|
||||
}
|
||||
|
||||
/// Retrieve a module hash string that is suitable for uniquely
|
||||
/// identifying the conditions under which the module was built, for use
|
||||
/// in generating a cached PCH file for the bridging header.
|
||||
std::string getPCHHash() const;
|
||||
};
|
||||
|
||||
/// A class which manages the state and execution of the compiler.
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#define SWIFT_FRONTEND_FRONTENDOPTIONS_H
|
||||
|
||||
#include "swift/AST/Module.h"
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -305,6 +306,12 @@ public:
|
||||
OutputFilenames.clear();
|
||||
OutputFilenames.push_back(FileName);
|
||||
}
|
||||
|
||||
/// Return a hash code of any components from these options that should
|
||||
/// contribute to a Swift Bridging PCH hash.
|
||||
llvm::hash_code getPCHHashComponents() const {
|
||||
return llvm::hash_value(0);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "swift/Basic/LangOptions.h"
|
||||
#include "swift/Basic/Range.h"
|
||||
#include "swift/Config.h"
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <limits.h>
|
||||
|
||||
@@ -145,27 +145,44 @@ namespace {
|
||||
ASTContext &Ctx;
|
||||
ClangImporter &Importer;
|
||||
ClangImporter::Implementation &Impl;
|
||||
const ClangImporterOptions &ImporterOpts;
|
||||
std::string SwiftPCHHash;
|
||||
public:
|
||||
explicit ParsingAction(ASTContext &ctx,
|
||||
ClangImporter &importer,
|
||||
ClangImporter::Implementation &impl)
|
||||
: Ctx(ctx), Importer(importer), Impl(impl) {}
|
||||
ClangImporter::Implementation &impl,
|
||||
const ClangImporterOptions &importerOpts,
|
||||
std::string swiftPCHHash)
|
||||
: Ctx(ctx), Importer(importer), Impl(impl), ImporterOpts(importerOpts),
|
||||
SwiftPCHHash(swiftPCHHash) {}
|
||||
std::unique_ptr<clang::ASTConsumer>
|
||||
CreateASTConsumer(clang::CompilerInstance &CI, StringRef InFile) override {
|
||||
return llvm::make_unique<HeaderParsingASTConsumer>(Impl);
|
||||
}
|
||||
bool BeginSourceFileAction(CompilerInstance &CI,
|
||||
bool BeginSourceFileAction(clang::CompilerInstance &CI,
|
||||
StringRef Filename) override {
|
||||
// Prefer frameworks over plain headers.
|
||||
// We add search paths here instead of when building the initial invocation
|
||||
// so that (a) we use the same code as search paths for imported modules,
|
||||
// and (b) search paths are always added after -Xcc options.
|
||||
SearchPathOptions &searchPathOpts = Ctx.SearchPathOpts;
|
||||
for (const auto &framepath : searchPathOpts.FrameworkSearchPaths)
|
||||
for (const auto &framepath : searchPathOpts.FrameworkSearchPaths) {
|
||||
Importer.addSearchPath(framepath.Path, /*isFramework*/true,
|
||||
framepath.IsSystem);
|
||||
for (auto path : searchPathOpts.ImportSearchPaths)
|
||||
}
|
||||
|
||||
for (auto path : searchPathOpts.ImportSearchPaths) {
|
||||
Importer.addSearchPath(path, /*isFramework*/false, /*isSystem=*/false);
|
||||
}
|
||||
|
||||
auto PCH = Importer.getOrCreatePCH(ImporterOpts, SwiftPCHHash);
|
||||
if (PCH.hasValue()) {
|
||||
Impl.getClangInstance()->getPreprocessorOpts().ImplicitPCHInclude =
|
||||
PCH.getValue();
|
||||
Impl.IsReadingBridgingPCH = true;
|
||||
Impl.setSinglePCHImport(PCH.getValue());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -692,11 +709,73 @@ addCommonInvocationArguments(std::vector<std::string> &invocationArgStrs,
|
||||
llvm::itostr(ctx.LangOpts.EffectiveLanguageVersion[0]));
|
||||
}
|
||||
|
||||
bool ClangImporter::canReadPCH(StringRef PCHFilename) {
|
||||
return clang::ASTReader::isAcceptableASTFile(PCHFilename,
|
||||
Impl.Instance->getFileManager(),
|
||||
Impl.Instance->getPCHContainerReader(),
|
||||
Impl.Instance->getLangOpts(),
|
||||
Impl.Instance->getTargetOpts(),
|
||||
Impl.Instance->getPreprocessorOpts(),
|
||||
Impl.Instance->getSpecificModuleCachePath());
|
||||
}
|
||||
|
||||
Optional<std::string>
|
||||
ClangImporter::getPCHFilename(const ClangImporterOptions &ImporterOptions,
|
||||
const std::string &SwiftPCHHash) {
|
||||
if (llvm::sys::path::extension(ImporterOptions.BridgingHeader)
|
||||
.endswith(PCH_EXTENSION)) {
|
||||
return ImporterOptions.BridgingHeader;
|
||||
}
|
||||
|
||||
const auto &BridgingHeader = ImporterOptions.BridgingHeader;
|
||||
const auto &PCHOutputDir = ImporterOptions.PrecompiledHeaderOutputDir;
|
||||
if (SwiftPCHHash.empty() || BridgingHeader.empty() || PCHOutputDir.empty()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
SmallString<256> PCHBasename { llvm::sys::path::filename(BridgingHeader) };
|
||||
llvm::sys::path::replace_extension(PCHBasename, "");
|
||||
PCHBasename.append("-swift_");
|
||||
PCHBasename.append(SwiftPCHHash);
|
||||
PCHBasename.append("-clang_");
|
||||
PCHBasename.append(getClangModuleHash());
|
||||
llvm::sys::path::replace_extension(PCHBasename, ".pch");
|
||||
SmallString<256> PCHFilename { PCHOutputDir };
|
||||
llvm::sys::path::append(PCHFilename, PCHBasename);
|
||||
return PCHFilename.str().str();
|
||||
}
|
||||
|
||||
|
||||
Optional<std::string>
|
||||
ClangImporter::getOrCreatePCH(const ClangImporterOptions &ImporterOptions,
|
||||
const std::string &SwiftPCHHash) {
|
||||
auto PCHFilename = getPCHFilename(ImporterOptions, SwiftPCHHash);
|
||||
if (!PCHFilename.hasValue()) {
|
||||
return None;
|
||||
}
|
||||
if (!canReadPCH(PCHFilename.getValue())) {
|
||||
SmallString<256> Message;
|
||||
llvm::raw_svector_ostream OS(Message);
|
||||
auto Diags = new clang::TextDiagnosticPrinter {
|
||||
llvm::errs(),
|
||||
&Impl.Instance->getDiagnosticOpts()
|
||||
};
|
||||
auto FailedToEmit = emitBridgingPCH(ImporterOptions.BridgingHeader,
|
||||
PCHFilename.getValue(),
|
||||
Diags);
|
||||
if (FailedToEmit) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
return PCHFilename.getValue();
|
||||
}
|
||||
|
||||
std::unique_ptr<ClangImporter>
|
||||
ClangImporter::create(ASTContext &ctx,
|
||||
const ClangImporterOptions &importerOpts,
|
||||
std::string swiftPCHHash,
|
||||
DependencyTracker *tracker) {
|
||||
|
||||
std::unique_ptr<ClangImporter> importer{
|
||||
new ClangImporter(ctx, importerOpts, tracker)
|
||||
};
|
||||
@@ -731,6 +810,7 @@ ClangImporter::create(ASTContext &ctx,
|
||||
|
||||
if (llvm::sys::path::extension(importerOpts.BridgingHeader).endswith(
|
||||
PCH_EXTENSION)) {
|
||||
importer->Impl.setSinglePCHImport(importerOpts.BridgingHeader);
|
||||
importer->Impl.IsReadingBridgingPCH = true;
|
||||
if (tracker) {
|
||||
// Currently ignoring dependency on bridging .pch files because they are
|
||||
@@ -751,7 +831,8 @@ ClangImporter::create(ASTContext &ctx,
|
||||
new ClangDiagnosticConsumer(importer->Impl, *diagnosticOpts,
|
||||
importerOpts.DumpClangDiagnostics)
|
||||
};
|
||||
auto clangDiags = CompilerInstance::createDiagnostics(diagnosticOpts.get(),
|
||||
auto clangDiags =
|
||||
clang::CompilerInstance::createDiagnostics(diagnosticOpts.get(),
|
||||
diagClient.release());
|
||||
|
||||
// Create a new Clang compiler invocation.
|
||||
@@ -794,7 +875,8 @@ ClangImporter::create(ASTContext &ctx,
|
||||
llvm::make_unique<clang::ObjectFilePCHContainerWriter>());
|
||||
PCHContainerOperations->registerReader(
|
||||
llvm::make_unique<clang::ObjectFilePCHContainerReader>());
|
||||
importer->Impl.Instance.reset(new CompilerInstance(PCHContainerOperations));
|
||||
importer->Impl.Instance.reset(
|
||||
new clang::CompilerInstance(PCHContainerOperations));
|
||||
auto &instance = *importer->Impl.Instance;
|
||||
if (tracker)
|
||||
instance.addDependencyCollector(tracker->getClangCollector());
|
||||
@@ -804,7 +886,9 @@ ClangImporter::create(ASTContext &ctx,
|
||||
|
||||
// Create the associated action.
|
||||
importer->Impl.Action.reset(new ParsingAction(ctx, *importer,
|
||||
importer->Impl));
|
||||
importer->Impl,
|
||||
importerOpts,
|
||||
swiftPCHHash));
|
||||
auto *action = importer->Impl.Action.get();
|
||||
|
||||
// Execute the action. We effectively inline most of
|
||||
@@ -934,6 +1018,7 @@ bool ClangImporter::Implementation::importHeader(
|
||||
bool trackParsedSymbols,
|
||||
std::unique_ptr<llvm::MemoryBuffer> sourceBuffer,
|
||||
bool implicitImport) {
|
||||
|
||||
// Don't even try to load the bridging header if the Clang AST is in a bad
|
||||
// state. It could cause a crash.
|
||||
auto &clangDiags = getClangASTContext().getDiagnostics();
|
||||
@@ -1061,6 +1146,11 @@ bool ClangImporter::importHeader(StringRef header, ModuleDecl *adapter,
|
||||
return importBridgingHeader(header, adapter, diagLoc, false, true);
|
||||
}
|
||||
|
||||
// If we've made it to here, this is some header other than the bridging
|
||||
// header, which means we can no longer rely on one file's modification time
|
||||
// to invalid code completion caches. :-(
|
||||
Impl.setSinglePCHImport(None);
|
||||
|
||||
if (!cachedContents.empty() && cachedContents.back() == '\0')
|
||||
cachedContents = cachedContents.drop_back();
|
||||
std::unique_ptr<llvm::MemoryBuffer> sourceBuffer{
|
||||
@@ -1082,6 +1172,7 @@ bool ClangImporter::importBridgingHeader(StringRef header, ModuleDecl *adapter,
|
||||
Impl.handleDeferredImports();
|
||||
return false;
|
||||
}
|
||||
|
||||
clang::FileManager &fileManager = Impl.Instance->getFileManager();
|
||||
const clang::FileEntry *headerFile = fileManager.getFile(header,
|
||||
/*OpenFile=*/true);
|
||||
@@ -1152,7 +1243,8 @@ std::string ClangImporter::getBridgingHeaderContents(StringRef headerPath,
|
||||
|
||||
bool
|
||||
ClangImporter::emitBridgingPCH(StringRef headerPath,
|
||||
StringRef outputPCHPath) {
|
||||
StringRef outputPCHPath,
|
||||
clang::DiagnosticConsumer *Diags) {
|
||||
auto invocation = std::make_shared<clang::CompilerInvocation>
|
||||
(clang::CompilerInvocation(*Impl.Invocation));
|
||||
invocation->getFrontendOpts().DisableFree = false;
|
||||
@@ -1165,8 +1257,12 @@ ClangImporter::emitBridgingPCH(StringRef headerPath,
|
||||
clang::CompilerInstance emitInstance(
|
||||
Impl.Instance->getPCHContainerOperations());
|
||||
emitInstance.setInvocation(std::move(invocation));
|
||||
emitInstance.createDiagnostics(&Impl.Instance->getDiagnosticClient(),
|
||||
false);
|
||||
|
||||
auto ReusingDiags = Diags == nullptr;
|
||||
if (ReusingDiags) {
|
||||
Diags = &Impl.Instance->getDiagnosticClient();
|
||||
}
|
||||
emitInstance.createDiagnostics(Diags, /*ShouldOwnDiags=*/!ReusingDiags);
|
||||
|
||||
clang::FileManager &fileManager = Impl.Instance->getFileManager();
|
||||
emitInstance.setFileManager(&fileManager);
|
||||
@@ -2446,8 +2542,14 @@ void ClangModuleUnit::collectLinkLibraries(
|
||||
}
|
||||
|
||||
StringRef ClangModuleUnit::getFilename() const {
|
||||
if (!clangModule)
|
||||
if (!clangModule) {
|
||||
auto SinglePCH = owner.getSinglePCHImport();
|
||||
if (SinglePCH.hasValue()) {
|
||||
return SinglePCH.getValue();
|
||||
} else {
|
||||
return "<imports>";
|
||||
}
|
||||
}
|
||||
if (const clang::FileEntry *F = clangModule->getASTFile())
|
||||
if (!F->getName().empty())
|
||||
return F->getName();
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "swift/AST/Type.h"
|
||||
#include "swift/AST/ForeignErrorConvention.h"
|
||||
#include "swift/Basic/StringExtras.h"
|
||||
#include "swift/Strings.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/DeclVisitor.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
@@ -40,6 +41,7 @@
|
||||
#include "llvm/ADT/SmallBitVector.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/TinyPtrVector.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include <set>
|
||||
|
||||
namespace llvm {
|
||||
@@ -386,6 +388,10 @@ public:
|
||||
llvm::DenseMap<std::pair<ObjCSelector, char>, unsigned>
|
||||
ActiveSelectors;
|
||||
|
||||
clang::CompilerInstance *getClangInstance() {
|
||||
return Instance.get();
|
||||
}
|
||||
|
||||
private:
|
||||
/// \brief Generation number that is used for crude versioning.
|
||||
///
|
||||
@@ -532,6 +538,11 @@ private:
|
||||
/// after having set up a suitable Clang instance.
|
||||
std::unique_ptr<importer::NameImporter> nameImporter = nullptr;
|
||||
|
||||
/// If there is a single .PCH file imported into the __ObjC module, this
|
||||
/// is the filename of that PCH. When other files are imported, this should
|
||||
/// be llvm::None.
|
||||
Optional<std::string> SinglePCHImport = None;
|
||||
|
||||
public:
|
||||
importer::NameImporter &getNameImporter() {
|
||||
assert(nameImporter && "haven't finished initialization");
|
||||
@@ -1158,6 +1169,22 @@ public:
|
||||
|
||||
/// Dump the Swift-specific name lookup tables we generate.
|
||||
void dumpSwiftLookupTables();
|
||||
|
||||
void setSinglePCHImport(Optional<std::string> PCHFilename) {
|
||||
if (PCHFilename.hasValue()) {
|
||||
assert(llvm::sys::path::extension(PCHFilename.getValue())
|
||||
.endswith(PCH_EXTENSION) &&
|
||||
"Single PCH imported filename doesn't have .pch extension!");
|
||||
}
|
||||
SinglePCHImport = PCHFilename;
|
||||
}
|
||||
|
||||
/// If there was is a single .pch bridging header without other imported
|
||||
/// files, we can provide the PCH filename for declaration caching,
|
||||
/// especially in code completion. If there are other
|
||||
Optional<std::string> getSinglePCHImport() const {
|
||||
return SinglePCHImport;
|
||||
}
|
||||
};
|
||||
|
||||
namespace importer {
|
||||
|
||||
@@ -1583,7 +1583,6 @@ bool CompilerInvocation::parseArgs(ArrayRef<const char *> Args,
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
serialization::Status
|
||||
CompilerInvocation::loadFromSerializedAST(StringRef data) {
|
||||
serialization::ExtendedValidationInfo extendedInfo;
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "swift/Parse/Lexer.h"
|
||||
#include "swift/SIL/SILModule.h"
|
||||
#include "swift/Serialization/SerializedModuleLoader.h"
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
@@ -35,6 +36,22 @@
|
||||
|
||||
using namespace swift;
|
||||
|
||||
std::string CompilerInvocation::getPCHHash() const {
|
||||
using llvm::hash_code;
|
||||
using llvm::hash_value;
|
||||
using llvm::hash_combine;
|
||||
|
||||
auto Code = hash_value(LangOpts.getPCHHashComponents());
|
||||
Code = hash_combine(Code, FrontendOpts.getPCHHashComponents());
|
||||
Code = hash_combine(Code, ClangImporterOpts.getPCHHashComponents());
|
||||
Code = hash_combine(Code, SearchPathOpts.getPCHHashComponents());
|
||||
Code = hash_combine(Code, DiagnosticOpts.getPCHHashComponents());
|
||||
Code = hash_combine(Code, SILOpts.getPCHHashComponents());
|
||||
Code = hash_combine(Code, IRGenOpts.getPCHHashComponents());
|
||||
|
||||
return llvm::APInt(64, Code).toString(36, /*Signed=*/false);
|
||||
}
|
||||
|
||||
void CompilerInstance::createSILModule(bool WholeModule) {
|
||||
assert(MainModule && "main module not created yet");
|
||||
TheSILModule = SILModule::createEmptyModule(getMainModule(),
|
||||
@@ -103,6 +120,7 @@ bool CompilerInstance::setup(const CompilerInvocation &Invok) {
|
||||
// knowledge.
|
||||
auto clangImporter =
|
||||
ClangImporter::create(*Context, Invocation.getClangImporterOptions(),
|
||||
Invocation.getPCHHash(),
|
||||
DepTracker);
|
||||
if (!clangImporter) {
|
||||
Diagnostics.diagnose(SourceLoc(), diag::error_clang_importer_create_fail);
|
||||
|
||||
@@ -367,7 +367,8 @@ static bool performCompile(std::unique_ptr<CompilerInstance> &Instance,
|
||||
auto clangImporter = static_cast<ClangImporter *>(
|
||||
Instance->getASTContext().getClangModuleLoader());
|
||||
return clangImporter->emitBridgingPCH(
|
||||
Invocation.getInputFilenames()[0], opts.getSingleOutputFilename());
|
||||
Invocation.getInputFilenames()[0],
|
||||
opts.getSingleOutputFilename());
|
||||
}
|
||||
|
||||
IRGenOptions &IRGenOpts = Invocation.getIRGenOptions();
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TOP -import-objc-header %S/Inputs/header.h | %FileCheck %s -check-prefix=CHECK-TOP
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=TYPE -import-objc-header %S/Inputs/header.h | %FileCheck %s -check-prefix=CHECK-TYPE
|
||||
// RUN: rm -rf %t && mkdir -p %t
|
||||
// RUN: %target-swift-ide-test -code-completion -pch-output-dir %t -source-filename %s -code-completion-token=TOP -import-objc-header %S/Inputs/header.h | %FileCheck %s -check-prefix=CHECK-TOP
|
||||
// RUN: %target-swift-ide-test -code-completion -pch-output-dir %t -source-filename %s -code-completion-token=TYPE -import-objc-header %S/Inputs/header.h | %FileCheck %s -check-prefix=CHECK-TYPE
|
||||
// RUN: stat %t/*.pch
|
||||
|
||||
// REQUIRES: objc_interop
|
||||
|
||||
|
||||
13
test/SourceKit/Mixed/complete_twice_bridging_header.swift
Normal file
13
test/SourceKit/Mixed/complete_twice_bridging_header.swift
Normal file
@@ -0,0 +1,13 @@
|
||||
// REQUIRES: objc_interop
|
||||
// RUN: rm -rf %t && mkdir -p %t
|
||||
// RUN: %sourcekitd-test -req=complete -pos=8:5 %s -- %s -module-name Mixed -pch-output-dir %t -import-objc-header %S/Inputs/header.h == -req=complete -pos=8:5 %s -- %s -module-name Mixed -pch-output-dir %t -import-objc-header %S/Inputs/header.h | %FileCheck %s --check-prefix=CHECK-MEMBERS
|
||||
// RUN: %sourcekitd-test -req=complete -pos=9:1 %s -- %s -module-name Mixed -pch-output-dir %t -import-objc-header %S/Inputs/header.h == -req=complete -pos=9:1 %s -- %s -module-name Mixed -pch-output-dir %t -import-objc-header %S/Inputs/header.h | %FileCheck %s --check-prefix=CHECK-GLOBALS
|
||||
// RUN: stat %t/*.pch
|
||||
|
||||
func foo(x: BaseInHead) {
|
||||
x.
|
||||
}
|
||||
|
||||
// CHECK-GLOBALS: doSomethingInHead(:)
|
||||
// CHECK-GLOBALS: test1(:)
|
||||
// CHECK-MEMBERS: doIt(:)
|
||||
@@ -10,6 +10,10 @@ func test(_ b : BaseInHead) {
|
||||
|
||||
// RUN: %sourcekitd-test -req=cursor -pos=3:7 %s -- %s %mcp_opt -module-name Mixed -import-objc-header %S/Inputs/header.h | %FileCheck %s
|
||||
|
||||
// RUN: rm -rf %t && mkdir -p %t
|
||||
// RUN: %sourcekitd-test -req=cursor -pos=3:7 %s -- %s %mcp_opt -module-name Mixed -pch-output-dir %t -import-objc-header %S/Inputs/header.h | %FileCheck %s
|
||||
// RUN: stat %t/*.pch
|
||||
|
||||
// CHECK: source.lang.swift.ref.function.method.instance ({{.*}}Inputs/header.h:4:9-4:23)
|
||||
// CHECK: doIt(_:)
|
||||
// CHECK: c:objc(cs)BaseInHead(im)doIt:
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/Mutex.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include <chrono>
|
||||
#include <xpc/xpc.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
@@ -250,6 +251,11 @@ static void handleInterruptedConnection(xpc_object_t event, xpc_connection_t con
|
||||
void sourcekitd::initialize() {
|
||||
initializeTracing();
|
||||
|
||||
llvm::InitializeAllTargets();
|
||||
llvm::InitializeAllTargetMCs();
|
||||
llvm::InitializeAllAsmPrinters();
|
||||
llvm::InitializeAllAsmParsers();
|
||||
|
||||
assert(!GlobalConn);
|
||||
GlobalConn = xpc_connection_create(SOURCEKIT_XPCSERVICE_IDENTIFIER, nullptr);
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include <mutex>
|
||||
|
||||
// FIXME: Portability.
|
||||
@@ -149,6 +150,11 @@ static void onDocumentUpdateNotification(StringRef DocumentName) {
|
||||
static SourceKit::Context *GlobalCtx = nullptr;
|
||||
|
||||
void sourcekitd::initialize() {
|
||||
llvm::InitializeAllTargets();
|
||||
llvm::InitializeAllTargetMCs();
|
||||
llvm::InitializeAllAsmPrinters();
|
||||
llvm::InitializeAllAsmParsers();
|
||||
|
||||
GlobalCtx = new SourceKit::Context(sourcekitd::getRuntimeLibPath(),
|
||||
SourceKit::createSwiftLangSupport);
|
||||
GlobalCtx->getNotificationCenter().addDocumentUpdateNotificationReceiver(
|
||||
|
||||
@@ -168,7 +168,7 @@ int modulewrap_main(ArrayRef<const char *> Args, const char *Argv0,
|
||||
LangOpts.Target = Invocation.getTargetTriple();
|
||||
ASTContext ASTCtx(LangOpts, SearchPathOpts, SrcMgr, Instance.getDiags());
|
||||
ClangImporterOptions ClangImporterOpts;
|
||||
ASTCtx.addModuleLoader(ClangImporter::create(ASTCtx, ClangImporterOpts),
|
||||
ASTCtx.addModuleLoader(ClangImporter::create(ASTCtx, ClangImporterOpts, ""),
|
||||
true);
|
||||
ModuleDecl *M = ModuleDecl::create(ASTCtx.getIdentifier("swiftmodule"), ASTCtx);
|
||||
SILOptions SILOpts;
|
||||
|
||||
@@ -243,6 +243,10 @@ SwiftVersion("swift-version", llvm::cl::desc("Swift version"));
|
||||
static llvm::cl::opt<std::string>
|
||||
ModuleCachePath("module-cache-path", llvm::cl::desc("Clang module cache path"));
|
||||
|
||||
static llvm::cl::opt<std::string>
|
||||
PCHOutputDir("pch-output-dir", llvm::cl::desc("place autogenerated PCH files in this directory"));
|
||||
|
||||
|
||||
static llvm::cl::opt<std::string>
|
||||
CompletionCachePath("completion-cache-path",
|
||||
llvm::cl::desc("Code completion cache path"),
|
||||
@@ -599,6 +603,7 @@ static int doCodeCompletion(const CompilerInvocation &InitInvok,
|
||||
<< " at offset " << CodeCompletionOffset << "\n";
|
||||
|
||||
CompilerInvocation Invocation(InitInvok);
|
||||
|
||||
Invocation.setCodeCompletionPoint(CleanFile.get(), CodeCompletionOffset);
|
||||
|
||||
|
||||
@@ -2973,6 +2978,8 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
InitInvok.getClangImporterOptions().ModuleCachePath =
|
||||
options::ModuleCachePath;
|
||||
InitInvok.getClangImporterOptions().PrecompiledHeaderOutputDir =
|
||||
options::PCHOutputDir;
|
||||
InitInvok.setImportSearchPaths(options::ImportPaths);
|
||||
std::vector<SearchPathOptions::FrameworkSearchPath> FramePaths;
|
||||
for (const auto &path : options::FrameworkPaths) {
|
||||
@@ -2986,6 +2993,8 @@ int main(int argc, char *argv[]) {
|
||||
options::EnableSourceImport;
|
||||
InitInvok.getFrontendOptions().ImplicitObjCHeaderPath =
|
||||
options::ImportObjCHeader;
|
||||
InitInvok.getClangImporterOptions().BridgingHeader =
|
||||
options::ImportObjCHeader;
|
||||
InitInvok.getLangOptions().EnableAccessControl =
|
||||
!options::DisableAccessControl;
|
||||
InitInvok.getLangOptions().CodeCompleteInitsInPostfixExpr |=
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "SourceKit/SwiftLang/Factory.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace SourceKit;
|
||||
@@ -102,6 +103,10 @@ public:
|
||||
LangSupport &getLang() { return Ctx.getSwiftLangSupport(); }
|
||||
|
||||
void SetUp() {
|
||||
llvm::InitializeAllTargets();
|
||||
llvm::InitializeAllTargetMCs();
|
||||
llvm::InitializeAllAsmPrinters();
|
||||
llvm::InitializeAllAsmParsers();
|
||||
NumTasks = 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user