Files
swift-mirror/lib/AST/ModuleDependencies.cpp
Doug Gregor 33cdd61835 Fast dependency scanning for Swift
Implement a new "fast" dependency scanning option,
`-scan-dependencies`, in the Swift frontend that determines all
of the source file and module dependencies for a given set of
Swift sources. It covers four forms of modules:

1) Swift (serialized) module files, by reading the module header
2) Swift interface files, by parsing the source code to find imports
3) Swift source modules, by parsing the source code to find imports
4) Clang modules, using Clang's fast dependency scanning tool

A single `-scan-dependencies` operation maps out the full
dependency graph for the given Swift source files, including all
of the Swift and Clang modules that may need to be built, such
that all of the work can be scheduled up front by the Swift
driver or any other build system that understands this
option. The dependency graph is emitted as JSON, which can be
consumed by these other tools.
2020-04-24 12:58:41 -07:00

144 lines
4.5 KiB
C++

//===--- ModuleDependencies.h - Module Dependencies -------------*- 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 data structures for capturing module dependencies.
//
//===----------------------------------------------------------------------===//
#include "swift/AST/ModuleDependencies.h"
#include "swift/AST/Decl.h"
#include "swift/AST/SourceFile.h"
using namespace swift;
ModuleDependenciesStorageBase::~ModuleDependenciesStorageBase() { }
bool ModuleDependencies::isSwiftModule() const {
return isa<SwiftModuleDependenciesStorage>(storage.get());
}
/// Retrieve the dependencies for a Swift module.
const SwiftModuleDependenciesStorage *
ModuleDependencies::getAsSwiftModule() const {
return dyn_cast<SwiftModuleDependenciesStorage>(storage.get());
}
/// Retrieve the dependencies for a Clang module.
const ClangModuleDependenciesStorage *
ModuleDependencies::getAsClangModule() const {
return dyn_cast<ClangModuleDependenciesStorage>(storage.get());
}
void ModuleDependencies::addModuleDependency(
StringRef module, llvm::StringSet<> &alreadyAddedModules) {
if (alreadyAddedModules.insert(module).second)
storage->moduleDependencies.push_back(module);
}
void ModuleDependencies::addModuleDependencies(
const SourceFile &sf, llvm::StringSet<> &alreadyAddedModules) {
// Add all of the module dependencies.
SmallVector<Decl *, 32> decls;
sf.getTopLevelDecls(decls);
for (auto decl : decls) {
auto importDecl = dyn_cast<ImportDecl>(decl);
if (!importDecl)
continue;
addModuleDependency(importDecl->getModulePath().front().Item.str(),
alreadyAddedModules);
}
auto fileName = sf.getFilename();
if (fileName.empty())
return;
// If the storage is for an interface file, the only source file we
// should see is that interface file.
auto swiftStorage = cast<SwiftModuleDependenciesStorage>(storage.get());
if (swiftStorage->swiftInterfaceFile) {
assert(fileName == *swiftStorage->swiftInterfaceFile);
return;
}
// Otherwise, record the source file.
swiftStorage->sourceFiles.push_back(fileName);
}
void ModuleDependencies::addBridgingHeader(StringRef bridgingHeader) {
auto swiftStorage = cast<SwiftModuleDependenciesStorage>(storage.get());
assert(!swiftStorage->bridgingHeaderFile);
swiftStorage->bridgingHeaderFile = bridgingHeader;
}
llvm::StringMap<ModuleDependencies> &
ModuleDependenciesCache::getDependenciesMap(ModuleDependenciesKind kind) {
switch (kind) {
case ModuleDependenciesKind::Swift:
return SwiftModuleDependencies;
case ModuleDependenciesKind::Clang:
return ClangModuleDependencies;
}
}
const llvm::StringMap<ModuleDependencies> &
ModuleDependenciesCache::getDependenciesMap(ModuleDependenciesKind kind) const {
switch (kind) {
case ModuleDependenciesKind::Swift:
return SwiftModuleDependencies;
case ModuleDependenciesKind::Clang:
return ClangModuleDependencies;
}
}
bool ModuleDependenciesCache::hasDependencies(
StringRef moduleName,
Optional<ModuleDependenciesKind> kind) const {
if (!kind) {
return hasDependencies(moduleName, ModuleDependenciesKind::Swift) ||
hasDependencies(moduleName, ModuleDependenciesKind::Clang);
}
const auto &map = getDependenciesMap(*kind);
return map.count(moduleName) > 0;
}
Optional<ModuleDependencies> ModuleDependenciesCache::findDependencies(
StringRef moduleName,
Optional<ModuleDependenciesKind> kind) const {
if (!kind) {
if (auto swiftDep = findDependencies(
moduleName, ModuleDependenciesKind::Swift))
return swiftDep;
return findDependencies(moduleName, ModuleDependenciesKind::Clang);
}
const auto &map = getDependenciesMap(*kind);
auto known = map.find(moduleName);
if (known != map.end())
return known->second;
return None;
}
void ModuleDependenciesCache::recordDependencies(
StringRef moduleName,
ModuleDependencies dependencies,
ModuleDependenciesKind kind) {
auto &map = getDependenciesMap(kind);
assert(map.count(moduleName) == 0 && "Already added to map");
map.insert({moduleName, std::move(dependencies)});
AllModules.push_back({moduleName, kind});
}