blob: 7f0588858152e35c4c18291f43a0b7441c4ad724 [file] [log] [blame]
//===--- ModuleDependencyScanner.cpp - Compute module dependencies --------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "swift/AST/ASTContext.h"
#include "swift/AST/DiagnosticSuppression.h"
#include "swift/AST/DiagnosticsFrontend.h"
#include "swift/AST/ModuleDependencies.h"
#include "swift/AST/SourceFile.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/Basic/FileTypes.h"
#include "swift/Frontend/ModuleInterfaceLoader.h"
#include "swift/Serialization/SerializedModuleLoader.h"
#include "swift/Serialization/ModuleDependencyScanner.h"
#include "swift/Subsystems.h"
using namespace swift;
using llvm::ErrorOr;
std::error_code ModuleDependencyScanner::findModuleFilesInDirectory(
AccessPathElem ModuleID,
const SerializedModuleBaseName &BaseName,
SmallVectorImpl<char> *ModuleInterfacePath,
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleSourceInfoBuffer,
bool IsFramework) {
using namespace llvm::sys;
auto &fs = *Ctx.SourceMgr.getFileSystem();
auto ModPath = BaseName.getName(file_types::TY_SwiftModuleFile);
auto InPath = BaseName.getName(file_types::TY_SwiftModuleInterfaceFile);
if (LoadMode == ModuleLoadingMode::OnlySerialized || !fs.exists(InPath)) {
if (fs.exists(ModPath)) {
// The module file will be loaded directly.
auto dependencies = scanModuleFile(ModPath);
if (dependencies) {
this->dependencies = std::move(dependencies.get());
return std::error_code();
}
return dependencies.getError();
} else {
return std::make_error_code(std::errc::no_such_file_or_directory);
}
}
assert(fs.exists(InPath));
// Use the private interface file if exits.
auto PrivateInPath =
BaseName.getName(file_types::TY_PrivateSwiftModuleInterfaceFile);
if (fs.exists(PrivateInPath)) {
InPath = PrivateInPath;
}
auto dependencies = scanInterfaceFile(InPath, IsFramework);
if (dependencies) {
this->dependencies = std::move(dependencies.get());
return std::error_code();
}
return dependencies.getError();
}
std::error_code PlaceholderSwiftModuleScanner::findModuleFilesInDirectory(
AccessPathElem ModuleID, const SerializedModuleBaseName &BaseName,
SmallVectorImpl<char> *ModuleInterfacePath,
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleSourceInfoBuffer,
bool IsFramework) {
StringRef moduleName = ModuleID.Item.str();
auto it = PlaceholderDependencyModuleMap.find(moduleName);
// If no placeholder module stub path is given matches the name, return with an
// error code.
if (it == PlaceholderDependencyModuleMap.end()) {
return std::make_error_code(std::errc::not_supported);
}
auto &moduleInfo = it->getValue();
assert(!moduleInfo.moduleBuffer &&
"Placeholder dependency module stubs cannot have an associated buffer");
auto dependencies = ModuleDependencies::forPlaceholderSwiftModuleStub(
moduleInfo.modulePath, moduleInfo.moduleDocPath,
moduleInfo.moduleSourceInfoPath);
this->dependencies = std::move(dependencies);
return std::error_code{};
}
static std::vector<std::string> getCompiledCandidates(ASTContext &ctx,
StringRef moduleName,
StringRef interfacePath) {
return static_cast<SerializedModuleLoaderBase*>(ctx
.getModuleInterfaceLoader())->getCompiledModuleCandidatesForInterface(
moduleName.str(), interfacePath);
}
ErrorOr<ModuleDependencies> ModuleDependencyScanner::scanInterfaceFile(
Twine moduleInterfacePath, bool isFramework) {
// Create a module filename.
// FIXME: Query the module interface loader to determine an appropriate
// name for the module, which includes an appropriate hash.
auto newExt = file_types::getExtension(file_types::TY_SwiftModuleFile);
llvm::SmallString<32> modulePath = moduleName.str();
llvm::sys::path::replace_extension(modulePath, newExt);
Optional<ModuleDependencies> Result;
std::error_code code =
astDelegate.runInSubContext(moduleName.str(),
moduleInterfacePath.str(),
StringRef(),
SourceLoc(),
[&](ASTContext &Ctx, ModuleDecl *mainMod,
ArrayRef<StringRef> Args,
ArrayRef<StringRef> PCMArgs, StringRef Hash) {
assert(mainMod);
std::string InPath = moduleInterfacePath.str();
auto compiledCandidates = getCompiledCandidates(Ctx, moduleName.str(),
InPath);
Result = ModuleDependencies::forSwiftInterface(InPath,
compiledCandidates,
Args,
PCMArgs,
Hash,
isFramework);
// Open the interface file.
auto &fs = *Ctx.SourceMgr.getFileSystem();
auto interfaceBuf = fs.getBufferForFile(moduleInterfacePath);
if (!interfaceBuf) {
return interfaceBuf.getError();
}
// Create a source file.
unsigned bufferID = Ctx.SourceMgr.addNewSourceBuffer(std::move(interfaceBuf.get()));
auto moduleDecl = ModuleDecl::create(moduleName, Ctx);
auto sourceFile = new (Ctx) SourceFile(
*moduleDecl, SourceFileKind::Interface, bufferID);
// Walk the source file to find the import declarations.
llvm::StringSet<> alreadyAddedModules;
Result->addModuleDependencies(*sourceFile, alreadyAddedModules);
// Collect implicitly imported modules in case they are not explicitly
// printed in the interface file, e.g. SwiftOnoneSupport.
auto &imInfo = mainMod->getImplicitImportInfo();
for (auto name: imInfo.ModuleNames) {
Result->addModuleDependency(name.str(), &alreadyAddedModules);
}
return std::error_code();
});
if (code) {
return code;
}
return *Result;
}
Optional<ModuleDependencies> SerializedModuleLoaderBase::getModuleDependencies(
StringRef moduleName, ModuleDependenciesCache &cache,
InterfaceSubContextDelegate &delegate) {
// Check whether we've cached this result.
if (auto found = cache.findDependencies(
moduleName, ModuleDependenciesKind::Swift))
return found;
if (auto found =
cache.findDependencies(moduleName, ModuleDependenciesKind::SwiftPlaceholder))
return found;
auto moduleId = Ctx.getIdentifier(moduleName);
// Instantiate dependency scanning "loaders".
SmallVector<std::unique_ptr<ModuleDependencyScanner>, 2> scanners;
// Placeholder dependencies must be resolved first, to prevent the ModuleDependencyScanner
// from first discovering artifacts of a previous build. Such artifacts are captured
// as compiledModuleCandidates in the dependency graph of the placeholder dependency module
// itself.
scanners.push_back(std::make_unique<PlaceholderSwiftModuleScanner>(
Ctx, LoadMode, moduleId, Ctx.SearchPathOpts.PlaceholderDependencyModuleMap,
delegate));
scanners.push_back(std::make_unique<ModuleDependencyScanner>(
Ctx, LoadMode, moduleId, delegate));
// Check whether there is a module with this name that we can import.
assert(isa<PlaceholderSwiftModuleScanner>(scanners[0].get()) &&
"Expected PlaceholderSwiftModuleScanner as the first dependency scanner loader.");
for (auto &scanner : scanners) {
if (scanner->canImportModule({moduleId, SourceLoc()})) {
// Record the dependencies.
cache.recordDependencies(moduleName, *(scanner->dependencies),
scanner->dependencyKind);
return std::move(scanner->dependencies);
}
}
return None;
}