Skip to content

[ParseableInterfaces] Handle swiftdoc files correctly #21512

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions include/swift/Basic/STLExtras.h
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,30 @@ inline T accumulate(const Container &C, T init, BinaryOperation op) {
return std::accumulate(C.begin(), C.end(), init, op);
}

/// Returns true if the range defined by \p mainBegin ..< \p mainEnd starts with
/// the same elements as the range defined by \p prefixBegin ..< \p prefixEnd.
///
/// This includes cases where the prefix range is empty, as well as when the two
/// ranges are the same length and contain the same elements.
template <typename MainInputIterator, typename PrefixInputIterator>
inline bool hasPrefix(MainInputIterator mainBegin,
const MainInputIterator mainEnd,
PrefixInputIterator prefixBegin,
const PrefixInputIterator prefixEnd) {
while (prefixBegin != prefixEnd) {
// If "main" is shorter than "prefix", it does not start with "prefix".
if (mainBegin == mainEnd)
return false;
// If there's a mismatch, "main" does not start with "prefix".
if (*mainBegin != *prefixBegin)
return false;
++prefixBegin;
++mainBegin;
}
// If we checked every element of "prefix", "main" does start with "prefix".
return true;
}

/// Provides default implementations of !=, <=, >, and >= based on == and <.
template <typename T>
class RelationalOperationsBase {
Expand Down
4 changes: 4 additions & 0 deletions include/swift/Frontend/FrontendOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ class FrontendOptions {
/// The path to which we should store indexing data, if any.
std::string IndexStorePath;

/// The path to look in when loading a parseable interface file, to see if a
/// binary module has already been built for use by the compiler.
std::string PrebuiltModuleCachePath;

/// Emit index data for imported serialized swift system modules.
bool IndexSystemModules = false;

Expand Down
23 changes: 12 additions & 11 deletions include/swift/Frontend/ParseableInterfaceSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,15 @@ getModuleCachePathFromClang(const clang::CompilerInstance &Instance);
/// directory, and loading the serialized .swiftmodules from there.
class ParseableInterfaceModuleLoader : public SerializedModuleLoaderBase {
explicit ParseableInterfaceModuleLoader(ASTContext &ctx, StringRef cacheDir,
StringRef prebuiltCacheDir,
DependencyTracker *tracker,
ModuleLoadingMode loadMode)
: SerializedModuleLoaderBase(ctx, tracker, loadMode),
CacheDir(cacheDir)
CacheDir(cacheDir), PrebuiltCacheDir(prebuiltCacheDir)
{}

std::string CacheDir;
std::string PrebuiltCacheDir;

/// Wire up the SubInvocation's InputsAndOutputs to contain both input and
/// output filenames.
Expand All @@ -77,20 +79,19 @@ class ParseableInterfaceModuleLoader : public SerializedModuleLoaderBase {
static void configureSubInvocationInputsAndOutputs(
CompilerInvocation &SubInvocation, StringRef InPath, StringRef OutPath);

std::error_code
openModuleFiles(AccessPathElem ModuleID, StringRef DirName,
StringRef ModuleFilename, StringRef ModuleDocFilename,
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
llvm::SmallVectorImpl<char> &Scratch) override;
std::error_code findModuleFilesInDirectory(
AccessPathElem ModuleID, StringRef DirPath, StringRef ModuleFilename,
StringRef ModuleDocFilename,
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer) override;

public:
static std::unique_ptr<ParseableInterfaceModuleLoader>
create(ASTContext &ctx, StringRef cacheDir,
DependencyTracker *tracker,
ModuleLoadingMode loadMode) {
create(ASTContext &ctx, StringRef cacheDir, StringRef prebuiltCacheDir,
DependencyTracker *tracker, ModuleLoadingMode loadMode) {
return std::unique_ptr<ParseableInterfaceModuleLoader>(
new ParseableInterfaceModuleLoader(ctx, cacheDir, tracker, loadMode));
new ParseableInterfaceModuleLoader(ctx, cacheDir, prebuiltCacheDir,
tracker, loadMode));
}

/// Unconditionally build \p InPath (a swiftinterface file) to \p OutPath (as
Expand Down
7 changes: 7 additions & 0 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,13 @@ def build_module_from_parseable_interface :
HelpText<"Treat the (single) input as a swiftinterface and produce a module">,
ModeOpt;

def prebuilt_module_cache_path :
Separate<["-"], "prebuilt-module-cache-path">,
HelpText<"Directory of prebuilt modules for loading parseable interfaces">;
def prebuilt_module_cache_path_EQ :
Joined<["-"], "prebuilt-module-cache-path=">,
Alias<prebuilt_module_cache_path>;

def enable_resilience_bypass : Flag<["-"], "enable-resilience-bypass">,
HelpText<"Completely bypass resilience when accessing types in resilient frameworks">;

Expand Down
26 changes: 15 additions & 11 deletions include/swift/Serialization/SerializedModuleLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,17 @@ class SerializedModuleLoaderBase : public ModuleLoader {
std::unique_ptr<llvm::MemoryBuffer> *moduleDocBuffer,
bool &isFramework);

virtual std::error_code
openModuleFiles(AccessPathElem ModuleID, StringRef DirName,
StringRef ModuleFilename, StringRef ModuleDocFilename,
virtual std::error_code findModuleFilesInDirectory(
AccessPathElem ModuleID, StringRef DirPath, StringRef ModuleFilename,
StringRef ModuleDocFilename,
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer) = 0;

std::error_code
openModuleFiles(AccessPathElem ModuleID,
StringRef ModulePath, StringRef ModuleDocPath,
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
llvm::SmallVectorImpl<char> &Scratch);
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer);

/// If the module loader subclass knows that all options have been tried for
/// loading an architecture-specific file out of a swiftmodule bundle, try
Expand Down Expand Up @@ -128,12 +133,11 @@ class SerializedModuleLoader : public SerializedModuleLoaderBase {
: SerializedModuleLoaderBase(ctx, tracker, loadMode)
{}

std::error_code
openModuleFiles(AccessPathElem ModuleID, StringRef DirName,
StringRef ModuleFilename, StringRef ModuleDocFilename,
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
llvm::SmallVectorImpl<char> &Scratch) override;
std::error_code findModuleFilesInDirectory(
AccessPathElem ModuleID, StringRef DirPath, StringRef ModuleFilename,
StringRef ModuleDocFilename,
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer) override;

bool maybeDiagnoseArchitectureMismatch(SourceLoc sourceLocation,
StringRef moduleName,
Expand Down
3 changes: 3 additions & 0 deletions lib/Frontend/ArgsToFrontendOptionsConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ bool ArgsToFrontendOptionsConverter::convert(
if (const Arg *A = Args.getLastArg(OPT_index_store_path)) {
Opts.IndexStorePath = A->getValue();
}
if (const Arg *A = Args.getLastArg(OPT_prebuilt_module_cache_path)) {
Opts.PrebuiltModuleCachePath = A->getValue();
}

Opts.IndexSystemModules |= Args.hasArg(OPT_index_system_modules);

Expand Down
3 changes: 3 additions & 0 deletions lib/Frontend/Frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,8 +331,11 @@ bool CompilerInstance::setUpModuleLoaders() {
if (MLM != ModuleLoadingMode::OnlySerialized) {
auto const &Clang = clangImporter->getClangInstance();
std::string ModuleCachePath = getModuleCachePathFromClang(Clang);
StringRef PrebuiltModuleCachePath =
Invocation.getFrontendOptions().PrebuiltModuleCachePath;
auto PIML = ParseableInterfaceModuleLoader::create(*Context,
ModuleCachePath,
PrebuiltModuleCachePath,
getDependencyTracker(),
MLM);
Context->addModuleLoader(std::move(PIML));
Expand Down
88 changes: 62 additions & 26 deletions lib/Frontend/ParseableInterfaceSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "swift/AST/FileSystem.h"
#include "swift/AST/Module.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/Basic/STLExtras.h"
#include "swift/Frontend/Frontend.h"
#include "swift/Frontend/ParseableInterfaceSupport.h"
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
Expand Down Expand Up @@ -167,7 +168,7 @@ createInvocationForBuildingFromInterface(ASTContext &Ctx, StringRef ModuleName,
static void computeCachedOutputPath(ASTContext &Ctx,
const CompilerInvocation &SubInvocation,
StringRef InPath,
llvm::SmallString<128> &OutPath) {
llvm::SmallString<256> &OutPath) {
OutPath = SubInvocation.getClangModuleCachePath();
llvm::sys::path::append(OutPath, SubInvocation.getModuleName());
OutPath.append("-");
Expand Down Expand Up @@ -436,28 +437,29 @@ static bool serializedASTLooksValidOrCannotBeRead(clang::vfs::FileSystem &FS,
/// Load a .swiftmodule associated with a .swiftinterface either from a
/// cache or by converting it in a subordinate \c CompilerInstance, caching
/// the results.
std::error_code ParseableInterfaceModuleLoader::openModuleFiles(
AccessPathElem ModuleID, StringRef DirName, StringRef ModuleFilename,
std::error_code ParseableInterfaceModuleLoader::findModuleFilesInDirectory(
AccessPathElem ModuleID, StringRef DirPath, StringRef ModuleFilename,
StringRef ModuleDocFilename,
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
llvm::SmallVectorImpl<char> &Scratch) {
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer) {

namespace path = llvm::sys::path;

// If running in OnlySerialized mode, ParseableInterfaceModuleLoader
// should not have been constructed at all.
assert(LoadMode != ModuleLoadingMode::OnlySerialized);

auto &FS = *Ctx.SourceMgr.getFileSystem();
auto &Diags = Ctx.Diags;
llvm::SmallString<128> ModPath, InPath, OutPath;
llvm::SmallString<256> ModPath, InPath, OutPath;

// First check to see if the .swiftinterface exists at all. Bail if not.
ModPath = DirName;
llvm::sys::path::append(ModPath, ModuleFilename);
ModPath = DirPath;
path::append(ModPath, ModuleFilename);

auto Ext = file_types::getExtension(file_types::TY_SwiftParseableInterfaceFile);
InPath = ModPath;
llvm::sys::path::replace_extension(InPath, Ext);
path::replace_extension(InPath, Ext);
if (!FS.exists(InPath))
return std::make_error_code(std::errc::no_such_file_or_directory);

Expand All @@ -472,32 +474,66 @@ std::error_code ParseableInterfaceModuleLoader::openModuleFiles(
return std::make_error_code(std::errc::not_supported);
}

// At this point we're either in PreferParseable mode or there's no credible
// adjacent .swiftmodule so we'll go ahead and start trying to convert the
// .swiftinterface.
// If we have a prebuilt cache path, check that too if the interface comes
// from the SDK.
if (!PrebuiltCacheDir.empty()) {
StringRef SDKPath = Ctx.SearchPathOpts.SDKPath;
if (!SDKPath.empty() && hasPrefix(path::begin(InPath),
path::end(InPath),
path::begin(SDKPath),
path::end(SDKPath))) {
// Assemble the expected path: $PREBUILT_CACHE/Foo.swiftmodule or
// $PREBUILT_CACHE/Foo.swiftmodule/arch.swiftmodule. Note that there's no
// cache key here.
OutPath = PrebuiltCacheDir;

// FIXME: Would it be possible to only have architecture-specific names
// here? Then we could skip this check.
StringRef InParentDirName = path::filename(path::parent_path(InPath));
if (path::extension(InParentDirName) == ".swiftmodule") {
assert(path::stem(InParentDirName) == ModuleID.first.str());
path::append(OutPath, InParentDirName);
}
path::append(OutPath, ModuleFilename);

// Set up a _potential_ sub-invocation to consume the .swiftinterface and emit
// the .swiftmodule.
CompilerInvocation SubInvocation =
createInvocationForBuildingFromInterface(Ctx, ModuleID.first.str(), CacheDir);
computeCachedOutputPath(Ctx, SubInvocation, InPath, OutPath);
configureSubInvocationInputsAndOutputs(SubInvocation, InPath, OutPath);
if (!swiftModuleIsUpToDate(FS, ModuleID, OutPath, Diags,
dependencyTracker)) {
OutPath.clear();
}
}
}

// Evaluate if we need to run this sub-invocation, and if so run it.
if (!swiftModuleIsUpToDate(FS, ModuleID, OutPath, Diags, dependencyTracker)) {
if (::buildSwiftModuleFromSwiftInterface(FS, Diags, ModuleID.second,
SubInvocation, CacheDir,
dependencyTracker))
return std::make_error_code(std::errc::invalid_argument);
if (OutPath.empty()) {
// At this point we're either in PreferParseable mode or there's no credible
// adjacent .swiftmodule so we'll go ahead and start trying to convert the
// .swiftinterface.

// Set up a _potential_ sub-invocation to consume the .swiftinterface and
// emit the .swiftmodule.
CompilerInvocation SubInvocation =
createInvocationForBuildingFromInterface(Ctx, ModuleID.first.str(),
CacheDir);
computeCachedOutputPath(Ctx, SubInvocation, InPath, OutPath);
configureSubInvocationInputsAndOutputs(SubInvocation, InPath, OutPath);

// Evaluate if we need to run this sub-invocation, and if so run it.
if (!swiftModuleIsUpToDate(FS, ModuleID, OutPath, Diags,
dependencyTracker)) {
if (::buildSwiftModuleFromSwiftInterface(FS, Diags, ModuleID.second,
SubInvocation, CacheDir,
dependencyTracker))
return std::make_error_code(std::errc::invalid_argument);
}
}

// Finish off by delegating back up to the SerializedModuleLoaderBase
// routine that can load the recently-manufactured serialized module.
LLVM_DEBUG(llvm::dbgs() << "Loading " << OutPath
<< " via normal module loader\n");
llvm::SmallString<256> DocPath{DirPath};
path::append(DocPath, ModuleDocFilename);
auto ErrorCode = SerializedModuleLoaderBase::openModuleFiles(
ModuleID, CacheDir, llvm::sys::path::filename(OutPath),
ModuleDocFilename, ModuleBuffer, ModuleDocBuffer, Scratch);
ModuleID, OutPath, DocPath, ModuleBuffer, ModuleDocBuffer);
LLVM_DEBUG(llvm::dbgs() << "Loaded " << OutPath
<< " via normal module loader");
if (ErrorCode) {
Expand Down
Loading