Skip to content
42 changes: 32 additions & 10 deletions include/swift/DependencyScan/ModuleDependencyScanner.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,19 @@ class ModuleDependencyScanningWorker {
llvm::PrefixMapper *mapper);

private:
/// Initialize/finalize the clang compiler scanning tool.
/// Behind the scenes, the clang scanning tool maintains
/// a single clang compiler instance to perform all by-name
/// dependency scans. initializeClangScanningTool() initializes
/// the clang compiler instance, and returns an error if the
/// initialization fails. Once successfully initialized,
/// the same clang compiler instance is reused whenever
/// scanFilesystemForClangModuleDependency is called,
/// throughout the lifetime of the ModuleDependencyScanningWorker
/// instance.
llvm::Error initializeClangScanningTool();
llvm::Error finalizeClangScanningTool();

/// Query dependency information for a named Clang module
///
/// \param moduleName moduel identifier for the query
Expand Down Expand Up @@ -241,16 +254,11 @@ class SwiftDependencyTracker {

class ModuleDependencyScanner {
public:
ModuleDependencyScanner(SwiftDependencyScanningService &ScanningService,
ModuleDependenciesCache &Cache,
const CompilerInvocation &ScanCompilerInvocation,
const SILOptions &SILOptions,
ASTContext &ScanASTContext,
DependencyTracker &DependencyTracker,
std::shared_ptr<llvm::cas::ObjectStore> CAS,
std::shared_ptr<llvm::cas::ActionCache> ActionCache,
DiagnosticEngine &Diagnostics, bool ParallelScan,
bool EmitScanRemarks);
static llvm::ErrorOr<std::unique_ptr<ModuleDependencyScanner>>
create(SwiftDependencyScanningService &service, CompilerInstance *instance,
ModuleDependenciesCache &cache);

~ModuleDependencyScanner();

/// Identify the scanner invocation's main module's dependencies
llvm::ErrorOr<ModuleDependencyInfo>
Expand Down Expand Up @@ -292,6 +300,20 @@ class ModuleDependencyScanner {
}

private:
// Private methods that create, initialize and finalize the scanner.
ModuleDependencyScanner(SwiftDependencyScanningService &ScanningService,
ModuleDependenciesCache &Cache,
const CompilerInvocation &ScanCompilerInvocation,
const SILOptions &SILOptions,
ASTContext &ScanASTContext,
DependencyTracker &DependencyTracker,
std::shared_ptr<llvm::cas::ObjectStore> CAS,
std::shared_ptr<llvm::cas::ActionCache> ActionCache,
DiagnosticEngine &Diagnostics, bool ParallelScan,
bool EmitScanRemarks);
llvm::Error initializeWorkerClangScanningTool();
llvm::Error finalizeWorkerClangScanningTool();

/// Main routine that computes imported module dependency transitive
/// closure for the given module.
/// 1. Swift modules imported directly or via another Swift dependency
Expand Down
81 changes: 70 additions & 11 deletions lib/DependencyScan/ModuleDependencyScanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,15 @@ ModuleDependencyScanningWorker::ModuleDependencyScanningWorker(
workerCompilerInvocation->getSearchPathOptions().ExplicitSwiftModuleInputs);
}

llvm::Error ModuleDependencyScanningWorker::initializeClangScanningTool() {
return clangScanningTool.initializeCompilerInstanceWithContext(
clangScanningWorkingDirectoryPath, clangScanningModuleCommandLineArgs);
}

llvm::Error ModuleDependencyScanningWorker::finalizeClangScanningTool() {
return clangScanningTool.finalizeCompilerInstanceWithContext();
}

SwiftModuleScannerQueryResult
ModuleDependencyScanningWorker::scanFilesystemForSwiftModuleDependency(
Identifier moduleName, bool isTestableImport) {
Expand All @@ -308,23 +317,23 @@ ModuleDependencyScanningWorker::scanFilesystemForSwiftModuleDependency(

std::optional<clang::tooling::dependencies::TranslationUnitDeps>
ModuleDependencyScanningWorker::scanFilesystemForClangModuleDependency(
Identifier moduleName,
LookupModuleOutputCallback lookupModuleOutput,
Identifier moduleName, LookupModuleOutputCallback lookupModuleOutput,
const llvm::DenseSet<clang::tooling::dependencies::ModuleID>
&alreadySeenModules) {
diagnosticReporter.registerNamedClangModuleQuery();
auto clangModuleDependencies = clangScanningTool.getModuleDependencies(
moduleName.str(), clangScanningModuleCommandLineArgs,
clangScanningWorkingDirectoryPath, alreadySeenModules,
lookupModuleOutput);
auto clangModuleDependencies =
clangScanningTool.computeDependenciesByNameWithContext(
moduleName.str(), alreadySeenModules, lookupModuleOutput);
if (!clangModuleDependencies) {
llvm::handleAllErrors(clangModuleDependencies.takeError(), [this, &moduleName](
const llvm::StringError &E) {
llvm::handleAllErrors(
clangModuleDependencies.takeError(),
[this, &moduleName](const llvm::StringError &E) {
auto &message = E.getMessage();
if (message.find("fatal error: module '" + moduleName.str().str() +
"' not found") == std::string::npos)
workerDiagnosticEngine->diagnose(SourceLoc(), diag::clang_dependency_scan_error, message);
});
"' not found") == std::string::npos)
workerDiagnosticEngine->diagnose(
SourceLoc(), diag::clang_dependency_scan_error, message);
});
return std::nullopt;
}
return clangModuleDependencies.get();
Expand Down Expand Up @@ -519,6 +528,35 @@ SwiftDependencyTracker::createTreeFromDependencies() {
return *includeTreeList;
}

llvm::ErrorOr<std::unique_ptr<ModuleDependencyScanner>>
ModuleDependencyScanner::create(SwiftDependencyScanningService &service,
CompilerInstance *instance,
ModuleDependenciesCache &cache) {
auto scanner =
std::unique_ptr<ModuleDependencyScanner>(new ModuleDependencyScanner(
service, cache, instance->getInvocation(), instance->getSILOptions(),
instance->getASTContext(), *instance->getDependencyTracker(),
instance->getSharedCASInstance(), instance->getSharedCacheInstance(),
instance->getDiags(),
instance->getInvocation().getFrontendOptions().ParallelDependencyScan,
instance->getInvocation()
.getFrontendOptions()
.EmitDependencyScannerRemarks));

auto initError = scanner->initializeWorkerClangScanningTool();

if (initError) {
llvm::handleAllErrors(
std::move(initError), [&](const llvm::StringError &E) {
instance->getDiags().diagnose(
SourceLoc(), diag::clang_dependency_scan_error, E.getMessage());
});
return std::make_error_code(std::errc::invalid_argument);
}

return scanner;
}

ModuleDependencyScanner::ModuleDependencyScanner(
SwiftDependencyScanningService &ScanningService,
ModuleDependenciesCache &Cache,
Expand Down Expand Up @@ -566,6 +604,27 @@ ModuleDependencyScanner::ModuleDependencyScanner(
PrefixMapper.get()));
}

ModuleDependencyScanner::~ModuleDependencyScanner() {
auto finError = finalizeWorkerClangScanningTool();
assert(!finError && "ClangScanningTool finalization must succeed.");
}

llvm::Error ModuleDependencyScanner::initializeWorkerClangScanningTool() {
for (auto &W : Workers) {
if (auto error = W->initializeClangScanningTool())
return error;
}
return llvm::Error::success();
}

llvm::Error ModuleDependencyScanner::finalizeWorkerClangScanningTool() {
for (auto &W : Workers) {
if (auto error = W->finalizeClangScanningTool())
return error;
}
return llvm::Error::success();
}

static std::set<ModuleDependencyID>
collectBinarySwiftDeps(const ModuleDependenciesCache &cache) {
std::set<ModuleDependencyID> binarySwiftModuleDepIDs;
Expand Down
28 changes: 14 additions & 14 deletions lib/DependencyScan/ScanDependencies.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1405,13 +1405,13 @@ performModuleScanImpl(
}
}

auto scanner = ModuleDependencyScanner(
service, cache, instance->getInvocation(), instance->getSILOptions(),
instance->getASTContext(), *instance->getDependencyTracker(),
instance->getSharedCASInstance(), instance->getSharedCacheInstance(),
instance->getDiags(),
instance->getInvocation().getFrontendOptions().ParallelDependencyScan,
instance->getInvocation().getFrontendOptions().EmitDependencyScannerRemarks);
auto expectedScannerPtr =
ModuleDependencyScanner::create(service, instance, cache);

if (!expectedScannerPtr)
return expectedScannerPtr.getError();

auto &scanner = **expectedScannerPtr;

// Identify imports of the main module and add an entry for it
// to the dependency graph.
Expand Down Expand Up @@ -1458,13 +1458,13 @@ static llvm::ErrorOr<swiftscan_import_set_t> performModulePrescanImpl(
ModuleDependenciesCache &cache,
DepScanInMemoryDiagnosticCollector *diagnosticCollector) {
// Setup the scanner
auto scanner = ModuleDependencyScanner(
service, cache, instance->getInvocation(), instance->getSILOptions(),
instance->getASTContext(), *instance->getDependencyTracker(),
instance->getSharedCASInstance(), instance->getSharedCacheInstance(),
instance->getDiags(),
instance->getInvocation().getFrontendOptions().ParallelDependencyScan,
instance->getInvocation().getFrontendOptions().EmitDependencyScannerRemarks);
auto expectedScannerPtr =
ModuleDependencyScanner::create(service, instance, cache);

if (!expectedScannerPtr)
return expectedScannerPtr.getError();

auto &scanner = **expectedScannerPtr;

// Execute import prescan, and write JSON output to the output stream
auto mainDependencies =
Expand Down
2 changes: 1 addition & 1 deletion unittests/DependencyScan/ModuleDeps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,6 @@ TEST_F(ScanTest, TestStressConcurrentDiagnostics) {
ASSERT_FALSE(DependenciesOrErr.getError());
auto Dependencies = DependenciesOrErr.get();
auto Diagnostics = Dependencies->diagnostics;
ASSERT_TRUE(Diagnostics->count > 100);
ASSERT_TRUE(Diagnostics->count >= 1);
swiftscan_dependency_graph_dispose(Dependencies);
}