Skip to content

Commit 90f2fba

Browse files
committed
[Dependency Scanning] On failure to locate a module, attempt to diagnose if binary dependencies contain search paths with this module.
Unlike with implicitly-built modules (prior to Swift 6 mode), explicitly-built modules require that all search paths be specified explicitly and no longer inherit search paths serialized into discovered Swift binary modules. This behavior was never intentional and is considered a bug. This change adds a diagnostic note to a scan failure: for each binary Swift module dependency, the scanner will attempt to execute a dependency scanning query for each serialized search path inside that module. If such diagnostic query returns a result, a diagnostic will be emitted to inform the user that the dependency may be found in the search path configuration of another Swift binary module dependency, specifying which search path contains the "missing" module, and stating that such search paths are not automatically inherited by the current compilation.
1 parent 47e5ede commit 90f2fba

File tree

8 files changed

+262
-85
lines changed

8 files changed

+262
-85
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2378,6 +2378,9 @@ NOTE(dependency_as_imported_by_main_module,none,
23782378
"a dependency of main module '%0'", (StringRef))
23792379
NOTE(dependency_as_imported_by, none,
23802380
"a dependency of %select{Swift|Clang}2 module '%0': '%1'", (StringRef, StringRef, bool))
2381+
NOTE(inherited_search_path_resolves_module,none,
2382+
"'%0' can be found on search path used to build module '%1': '%2'. "
2383+
"These search paths are not inherited by the current compilation.", (StringRef, StringRef, StringRef))
23812384
ERROR(clang_dependency_scan_error, none, "Clang dependency scanner failure: %0", (StringRef))
23822385
ERROR(clang_header_dependency_scan_error, none, "Bridging header dependency scan failure: %0", (StringRef))
23832386

include/swift/AST/ModuleDependencies.h

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/AST/LinkLibrary.h"
2323
#include "swift/Basic/CXXStdlibKind.h"
2424
#include "swift/Basic/LLVM.h"
25+
#include "swift/Serialization/Validation.h"
2526
#include "clang/CAS/CASOptions.h"
2627
#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
2728
#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
@@ -406,15 +407,18 @@ class SwiftBinaryModuleDependencyStorage
406407
StringRef sourceInfoPath,
407408
ArrayRef<ScannerImportStatementInfo> moduleImports,
408409
ArrayRef<ScannerImportStatementInfo> optionalModuleImports,
409-
ArrayRef<LinkLibrary> linkLibraries, StringRef headerImport,
410-
StringRef definingModuleInterface, bool isFramework, bool isStatic,
411-
StringRef moduleCacheKey, StringRef userModuleVersion)
410+
ArrayRef<LinkLibrary> linkLibraries,
411+
ArrayRef<serialization::SearchPath> serializedSearchPaths,
412+
StringRef headerImport, StringRef definingModuleInterface,
413+
bool isFramework, bool isStatic, StringRef moduleCacheKey,
414+
StringRef userModuleVersion)
412415
: ModuleDependencyInfoStorageBase(ModuleDependencyKind::SwiftBinary,
413416
moduleImports, optionalModuleImports,
414417
linkLibraries, moduleCacheKey),
415418
compiledModulePath(compiledModulePath), moduleDocPath(moduleDocPath),
416419
sourceInfoPath(sourceInfoPath), headerImport(headerImport),
417420
definingModuleInterfacePath(definingModuleInterface),
421+
serializedSearchPaths(serializedSearchPaths),
418422
isFramework(isFramework), isStatic(isStatic),
419423
userModuleVersion(userModuleVersion) {}
420424

@@ -441,6 +445,9 @@ class SwiftBinaryModuleDependencyStorage
441445
/// Source files on which the header inputs depend.
442446
std::vector<std::string> headerSourceFiles;
443447

448+
/// Search paths this module was built with which got serialized
449+
std::vector<serialization::SearchPath> serializedSearchPaths;
450+
444451
/// (Clang) modules on which the header inputs depend.
445452
std::vector<ModuleDependencyID> headerModuleDependencies;
446453

@@ -613,15 +620,17 @@ class ModuleDependencyInfo {
613620
StringRef sourceInfoPath,
614621
ArrayRef<ScannerImportStatementInfo> moduleImports,
615622
ArrayRef<ScannerImportStatementInfo> optionalModuleImports,
616-
ArrayRef<LinkLibrary> linkLibraries, StringRef headerImport,
617-
StringRef definingModuleInterface, bool isFramework,
618-
bool isStatic, StringRef moduleCacheKey, StringRef userModuleVer) {
623+
ArrayRef<LinkLibrary> linkLibraries,
624+
ArrayRef<serialization::SearchPath> serializedSearchPaths,
625+
StringRef headerImport, StringRef definingModuleInterface,
626+
bool isFramework, bool isStatic, StringRef moduleCacheKey,
627+
StringRef userModuleVer) {
619628
return ModuleDependencyInfo(
620629
std::make_unique<SwiftBinaryModuleDependencyStorage>(
621630
compiledModulePath, moduleDocPath, sourceInfoPath, moduleImports,
622-
optionalModuleImports, linkLibraries, headerImport,
623-
definingModuleInterface,isFramework, isStatic, moduleCacheKey,
624-
userModuleVer));
631+
optionalModuleImports, linkLibraries, serializedSearchPaths,
632+
headerImport, definingModuleInterface,isFramework, isStatic,
633+
moduleCacheKey, userModuleVer));
625634
}
626635

627636
/// Describe the main Swift module.

include/swift/DependencyScan/ModuleDependencyScanner.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,24 @@ class ModuleDependencyScanner {
190190
template <typename Function, typename... Args>
191191
auto withDependencyScanningWorker(Function &&F, Args &&...ArgList);
192192

193+
/// Use the scanner's ASTContext to construct an `Identifier`
194+
/// for a given module name.
193195
Identifier getModuleImportIdentifier(StringRef moduleName);
194196

197+
/// Diagnose scanner failure and attempt to reconstruct the dependency
198+
/// path from the main module to the missing dependency.
199+
void diagnoseScannerFailure(const ScannerImportStatementInfo &moduleImport,
200+
const ModuleDependenciesCache &cache,
201+
std::optional<ModuleDependencyID> dependencyOf);
202+
203+
/// Assuming the \c `moduleImport` failed to resolve,
204+
/// iterate over all binary Swift module dependencies with serialized
205+
/// search paths and attempt to diagnose if the failed-to-resolve module
206+
/// can be found on any of them.
207+
void attemptToFindResolvingSerializedSearchPath(
208+
const ScannerImportStatementInfo &moduleImport,
209+
const ModuleDependenciesCache &cache, const SourceLoc &importLoc);
210+
195211
private:
196212
const CompilerInvocation &ScanCompilerInvocation;
197213
ASTContext &ScanASTContext;

lib/DependencyScan/ModuleDependencyCacheSerialization.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,7 @@ bool ModuleDependenciesCacheDeserializer::readGraph(
690690
auto moduleDep = ModuleDependencyInfo::forSwiftBinaryModule(
691691
*compiledModulePath, *moduleDocPath, *moduleSourceInfoPath,
692692
importStatements, optionalImportStatements, linkLibraries,
693+
{}, // TODO: serialized search path serialization
693694
*headerImport, *definingInterfacePath, isFramework, isStatic,
694695
*moduleCacheKey, *userModuleVersion);
695696

lib/DependencyScan/ModuleDependencyScanner.cpp

Lines changed: 180 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -101,78 +101,6 @@ findPathToDependency(ModuleDependencyID dependency,
101101
return dependencyPath;
102102
}
103103

104-
// Diagnose scanner failure and attempt to reconstruct the dependency
105-
// path from the main module to the missing dependency.
106-
static void
107-
diagnoseScannerFailure(const ScannerImportStatementInfo &moduleImport,
108-
DiagnosticEngine &Diags,
109-
const ModuleDependenciesCache &cache,
110-
std::optional<ModuleDependencyID> dependencyOf) {
111-
SourceLoc importLoc = SourceLoc();
112-
if (!moduleImport.importLocations.empty()) {
113-
auto locInfo = moduleImport.importLocations[0];
114-
importLoc = Diags.SourceMgr.getLocFromExternalSource(locInfo.bufferIdentifier,
115-
locInfo.lineNumber,
116-
locInfo.columnNumber);
117-
}
118-
119-
Diags.diagnose(importLoc, diag::dependency_scan_module_not_found,
120-
moduleImport.importIdentifier);
121-
if (dependencyOf.has_value()) {
122-
auto path = findPathToDependency(dependencyOf.value(), cache);
123-
// We may fail to construct a path in some cases, such as a Swift overlay of
124-
// a Clang module dependnecy.
125-
if (path.empty())
126-
path = {dependencyOf.value()};
127-
128-
for (auto it = path.rbegin(), end = path.rend(); it != end; ++it) {
129-
const auto &entry = *it;
130-
auto optionalEntryNode = cache.findDependency(entry);
131-
assert(optionalEntryNode.has_value());
132-
auto entryNode = optionalEntryNode.value();
133-
std::string moduleFilePath = "";
134-
bool isClang = false;
135-
switch (entryNode->getKind()) {
136-
case swift::ModuleDependencyKind::SwiftSource:
137-
Diags.diagnose(importLoc, diag::dependency_as_imported_by_main_module,
138-
entry.ModuleName);
139-
continue;
140-
case swift::ModuleDependencyKind::SwiftInterface:
141-
moduleFilePath =
142-
entryNode->getAsSwiftInterfaceModule()->swiftInterfaceFile;
143-
break;
144-
case swift::ModuleDependencyKind::SwiftBinary:
145-
moduleFilePath =
146-
entryNode->getAsSwiftBinaryModule()->compiledModulePath;
147-
break;
148-
case swift::ModuleDependencyKind::SwiftPlaceholder:
149-
moduleFilePath =
150-
entryNode->getAsPlaceholderDependencyModule()->compiledModulePath;
151-
break;
152-
case swift::ModuleDependencyKind::Clang:
153-
moduleFilePath = entryNode->getAsClangModule()->moduleMapFile;
154-
isClang = true;
155-
break;
156-
default:
157-
llvm_unreachable("Unexpected dependency kind");
158-
}
159-
160-
Diags.diagnose(importLoc, diag::dependency_as_imported_by,
161-
entry.ModuleName, moduleFilePath, isClang);
162-
}
163-
}
164-
165-
if (moduleImport.importLocations.size() > 1) {
166-
for (size_t i = 1; i < moduleImport.importLocations.size(); ++i) {
167-
auto locInfo = moduleImport.importLocations[i];
168-
auto importLoc = Diags.SourceMgr.getLocFromExternalSource(locInfo.bufferIdentifier,
169-
locInfo.lineNumber,
170-
locInfo.columnNumber);
171-
Diags.diagnose(importLoc, diag::unresolved_import_location);
172-
}
173-
}
174-
}
175-
176104
static bool isSwiftDependencyKind(ModuleDependencyKind Kind) {
177105
return Kind == ModuleDependencyKind::SwiftInterface ||
178106
Kind == ModuleDependencyKind::SwiftSource ||
@@ -545,7 +473,7 @@ ModuleDependencyScanner::ModuleDependencyScanner(
545473

546474
/// Find all of the imported Clang modules starting with the given module name.
547475
static void findAllImportedClangModules(StringRef moduleName,
548-
ModuleDependenciesCache &cache,
476+
const ModuleDependenciesCache &cache,
549477
std::vector<std::string> &allModules,
550478
llvm::StringSet<> &knownModules) {
551479
if (!knownModules.insert(moduleName).second)
@@ -562,6 +490,16 @@ static void findAllImportedClangModules(StringRef moduleName,
562490
knownModules);
563491
}
564492

493+
static std::set<ModuleDependencyID>
494+
collectBinarySwiftDeps(const ModuleDependenciesCache &cache) {
495+
std::set<ModuleDependencyID> binarySwiftModuleDepIDs;
496+
auto binaryDepsMap = cache.getDependenciesMap(ModuleDependencyKind::SwiftBinary);
497+
for (const auto &binaryDepName : binaryDepsMap.keys())
498+
binarySwiftModuleDepIDs.insert(ModuleDependencyID{binaryDepName.str(),
499+
ModuleDependencyKind::SwiftBinary});
500+
return binarySwiftModuleDepIDs;
501+
}
502+
565503
llvm::ErrorOr<ModuleDependencyInfo>
566504
ModuleDependencyScanner::getMainModuleDependencyInfo(ModuleDecl *mainModule) {
567505
// Main module file name.
@@ -1154,7 +1092,7 @@ void ModuleDependencyScanner::resolveAllClangModuleDependencies(
11541092
if (optionalCachedModuleInfo.has_value())
11551093
importedClangDependencies.insert(unresolvedModuleID);
11561094
else
1157-
diagnoseScannerFailure(unresolvedImport, Diagnostics, cache, moduleID);
1095+
diagnoseScannerFailure(unresolvedImport, cache, moduleID);
11581096
}
11591097

11601098
if (!importedClangDependencies.empty())
@@ -1706,3 +1644,171 @@ llvm::Error ModuleDependencyScanner::performBridgingHeaderChaining(
17061644

17071645
return llvm::Error::success();
17081646
}
1647+
1648+
void ModuleDependencyScanner::diagnoseScannerFailure(
1649+
const ScannerImportStatementInfo &moduleImport,
1650+
const ModuleDependenciesCache &cache,
1651+
std::optional<ModuleDependencyID> dependencyOf) {
1652+
SourceLoc importLoc = SourceLoc();
1653+
if (!moduleImport.importLocations.empty()) {
1654+
auto locInfo = moduleImport.importLocations[0];
1655+
importLoc = Diagnostics.SourceMgr.getLocFromExternalSource(
1656+
locInfo.bufferIdentifier, locInfo.lineNumber, locInfo.columnNumber);
1657+
}
1658+
1659+
Diagnostics.diagnose(importLoc, diag::dependency_scan_module_not_found,
1660+
moduleImport.importIdentifier);
1661+
if (dependencyOf.has_value()) {
1662+
auto path = findPathToDependency(dependencyOf.value(), cache);
1663+
// We may fail to construct a path in some cases, such as a Swift overlay of
1664+
// a Clang module dependnecy.
1665+
if (path.empty())
1666+
path = {dependencyOf.value()};
1667+
1668+
for (auto it = path.rbegin(), end = path.rend(); it != end; ++it) {
1669+
const auto &entry = *it;
1670+
auto optionalEntryNode = cache.findDependency(entry);
1671+
assert(optionalEntryNode.has_value());
1672+
auto entryNode = optionalEntryNode.value();
1673+
std::string moduleFilePath = "";
1674+
bool isClang = false;
1675+
switch (entryNode->getKind()) {
1676+
case swift::ModuleDependencyKind::SwiftSource:
1677+
Diagnostics.diagnose(importLoc,
1678+
diag::dependency_as_imported_by_main_module,
1679+
entry.ModuleName);
1680+
continue;
1681+
case swift::ModuleDependencyKind::SwiftInterface:
1682+
moduleFilePath =
1683+
entryNode->getAsSwiftInterfaceModule()->swiftInterfaceFile;
1684+
break;
1685+
case swift::ModuleDependencyKind::SwiftBinary:
1686+
moduleFilePath =
1687+
entryNode->getAsSwiftBinaryModule()->compiledModulePath;
1688+
break;
1689+
case swift::ModuleDependencyKind::SwiftPlaceholder:
1690+
moduleFilePath =
1691+
entryNode->getAsPlaceholderDependencyModule()->compiledModulePath;
1692+
break;
1693+
case swift::ModuleDependencyKind::Clang:
1694+
moduleFilePath = entryNode->getAsClangModule()->moduleMapFile;
1695+
isClang = true;
1696+
break;
1697+
default:
1698+
llvm_unreachable("Unexpected dependency kind");
1699+
}
1700+
1701+
Diagnostics.diagnose(importLoc, diag::dependency_as_imported_by,
1702+
entry.ModuleName, moduleFilePath, isClang);
1703+
}
1704+
}
1705+
1706+
if (moduleImport.importLocations.size() > 1) {
1707+
for (size_t i = 1; i < moduleImport.importLocations.size(); ++i) {
1708+
auto locInfo = moduleImport.importLocations[i];
1709+
auto importLoc = Diagnostics.SourceMgr.getLocFromExternalSource(
1710+
locInfo.bufferIdentifier, locInfo.lineNumber, locInfo.columnNumber);
1711+
Diagnostics.diagnose(importLoc, diag::unresolved_import_location);
1712+
}
1713+
}
1714+
1715+
attemptToFindResolvingSerializedSearchPath(moduleImport, cache, importLoc);
1716+
}
1717+
1718+
static std::string getModuleDefiningPath(const ModuleDependencyInfo &info) {
1719+
std::string path = "";
1720+
switch (info.getKind()) {
1721+
case swift::ModuleDependencyKind::SwiftInterface:
1722+
path = info.getAsSwiftInterfaceModule()->swiftInterfaceFile;
1723+
break;
1724+
case swift::ModuleDependencyKind::SwiftBinary:
1725+
path = info.getAsSwiftBinaryModule()->compiledModulePath;
1726+
break;
1727+
case swift::ModuleDependencyKind::SwiftPlaceholder:
1728+
path = info.getAsPlaceholderDependencyModule()->compiledModulePath;
1729+
break;
1730+
case swift::ModuleDependencyKind::Clang:
1731+
path = info.getAsClangModule()->moduleMapFile;
1732+
break;
1733+
case swift::ModuleDependencyKind::SwiftSource:
1734+
default:
1735+
llvm_unreachable("Unexpected dependency kind");
1736+
}
1737+
1738+
// Relative to the `module.modulemap` or `.swiftinterface` or `.swiftmodule`,
1739+
// the defininig path is the parent directory of the file.
1740+
<<<<<<< Updated upstream
1741+
path = llvm::sys::path::parent_path(path);
1742+
1743+
// If the defining path is the top-level `.swiftmodule` directory,
1744+
// take one more step up.
1745+
if (llvm::sys::path::extension(path) == ".swiftmodule")
1746+
path = llvm::sys::path::parent_path(path);
1747+
1748+
// If the defining path is under `.framework/Modules/` directory,
1749+
// return the parent path containing the framework.
1750+
if (llvm::sys::path::filename(path) == "Modules" && llvm::sys::path::extension(llvm::sys::path::parent_path(path)) == ".framework")
1751+
path = llvm::sys::path::parent_path(llvm::sys::path::parent_path(path));
1752+
1753+
return path;
1754+
=======
1755+
return llvm::sys::path::parent_path(path).str();
1756+
>>>>>>> Stashed changes
1757+
}
1758+
1759+
void ModuleDependencyScanner::attemptToFindResolvingSerializedSearchPath(
1760+
const ScannerImportStatementInfo &moduleImport,
1761+
const ModuleDependenciesCache &cache, const SourceLoc &importLoc) {
1762+
std::set<ModuleDependencyID> binarySwiftModuleDepIDs =
1763+
collectBinarySwiftDeps(cache);
1764+
1765+
for (const auto &binaryDepID : binarySwiftModuleDepIDs) {
1766+
auto binaryModInfo =
1767+
cache.findKnownDependency(binaryDepID).getAsSwiftBinaryModule();
1768+
assert(binaryModInfo);
1769+
if (binaryModInfo->serializedSearchPaths.empty())
1770+
continue;
1771+
1772+
// Note: this will permanently mutate this worker with additional search
1773+
// paths. That's fine because we are diagnosing a scan failure here, but
1774+
// worth being aware of.
1775+
withDependencyScanningWorker(
1776+
[&binaryModInfo, &moduleImport, &cache, &binaryDepID, &importLoc,
1777+
this](ModuleDependencyScanningWorker *ScanningWorker) {
1778+
ModuleDependencyVector result;
1779+
for (const auto &sp : binaryModInfo->serializedSearchPaths)
1780+
ScanningWorker->workerASTContext->addSearchPath(
1781+
sp.Path, sp.IsFramework, sp.IsSystem);
1782+
1783+
result = ScanningWorker->scanFilesystemForSwiftModuleDependency(
1784+
getModuleImportIdentifier(moduleImport.importIdentifier),
1785+
cache.getModuleOutputPath(), cache.getSDKModuleOutputPath(),
1786+
cache.getScanService().getPrefixMapper());
1787+
if (!result.empty()) {
1788+
Diagnostics.diagnose(
1789+
importLoc, diag::inherited_search_path_resolves_module,
1790+
moduleImport.importIdentifier, binaryDepID.ModuleName,
1791+
getModuleDefiningPath(result[0].second));
1792+
}
1793+
1794+
result = ScanningWorker->scanFilesystemForClangModuleDependency(
1795+
getModuleImportIdentifier(moduleImport.importIdentifier),
1796+
cache.getModuleOutputPath(), cache.getSDKModuleOutputPath(), {},
1797+
cache.getScanService().getPrefixMapper());
1798+
<<<<<<< Updated upstream
1799+
if (!result.empty()) {
1800+
Diagnostics.diagnose(
1801+
importLoc, diag::inherited_search_path_resolves_module,
1802+
moduleImport.importIdentifier, binaryDepID.ModuleName,
1803+
getModuleDefiningPath(result[0].second));
1804+
}
1805+
return result;
1806+
=======
1807+
if (!result.empty())
1808+
return std::make_pair(binaryDepID,
1809+
getModuleDefiningPath(result[0].second));
1810+
return std::nullopt;
1811+
>>>>>>> Stashed changes
1812+
});
1813+
}
1814+
}

0 commit comments

Comments
 (0)