Skip to content

Commit 6da780e

Browse files
committed
[Dependency Scanner] Diagnose failure to find a module
And produce a dependency path from the missing dependency to the main module being scanned.
1 parent 77502b5 commit 6da780e

File tree

12 files changed

+185
-16
lines changed

12 files changed

+185
-16
lines changed

include/swift/AST/ASTContext.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -989,7 +989,8 @@ class ASTContext final {
989989
bool isUnderlyingClangModule,
990990
ModuleDependenciesCache &cache,
991991
InterfaceSubContextDelegate &delegate,
992-
bool cacheOnly = false);
992+
bool cacheOnly = false,
993+
llvm::Optional<std::pair<std::string, swift::ModuleDependenciesKind>> dependencyOf = None);
993994

994995
/// Retrieve the module dependencies for the Swift module with the given name.
995996
Optional<ModuleDependencies> getSwiftModuleDependencies(

include/swift/AST/DiagnosticsSema.def

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,6 +1641,14 @@ ERROR(originally_definedin_must_not_before_available_version,none,
16411641
ERROR(alignment_not_power_of_two,none,
16421642
"alignment value must be a power of two", ())
16431643

1644+
// Dependency Scanning
1645+
ERROR(dependency_scan_module_not_found, none, "Unable to find module dependency: '%0'", (StringRef))
1646+
NOTE(dependency_as_imported_by_main_module,none,
1647+
"a dependency of main module '%0'", (StringRef))
1648+
NOTE(dependency_as_imported_by, none,
1649+
"a dependency of %select{Swift|Clang}2 module '%0': '%1'", (StringRef, StringRef, bool))
1650+
ERROR(clang_dependency_scan_error, none, "Clang dependency scanner failure: %0", (StringRef))
1651+
16441652
// Enum annotations
16451653
ERROR(indirect_case_without_payload,none,
16461654
"enum case %0 without associated value cannot be 'indirect'", (Identifier))

include/swift/AST/ModuleDependencies.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,9 @@ class ModuleDependenciesCache {
606606
/// `clangModuleDependencies` for Clang dependencies accimulated during
607607
/// the current scanning action.
608608
ModuleDependenciesKindRefMap ModuleDependenciesMap;
609+
610+
/// Name of the module under scan
611+
StringRef mainScanModuleName;
609612

610613
/// Discovered Clang modules are only cached locally.
611614
llvm::StringMap<ModuleDependenciesVector> clangModuleDependencies;
@@ -640,7 +643,8 @@ class ModuleDependenciesCache {
640643
Optional<ModuleDependenciesKind> kind) const;
641644

642645
public:
643-
ModuleDependenciesCache(GlobalModuleDependenciesCache &globalCache);
646+
ModuleDependenciesCache(GlobalModuleDependenciesCache &globalCache,
647+
StringRef mainScanModuleName);
644648
ModuleDependenciesCache(const ModuleDependenciesCache &) = delete;
645649
ModuleDependenciesCache &operator=(const ModuleDependenciesCache &) = delete;
646650
virtual ~ModuleDependenciesCache() { destroyClangImpl(); }
@@ -695,6 +699,10 @@ class ModuleDependenciesCache {
695699
const std::vector<ModuleDependencyID> &getAllSourceModules() const {
696700
return globalCache.getAllSourceModules();
697701
}
702+
703+
StringRef getMainModuleName() const {
704+
return mainScanModuleName;
705+
}
698706
};
699707

700708
} // namespace swift

lib/AST/ASTContext.cpp

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,13 @@
6363
#include "llvm/ADT/Statistic.h"
6464
#include "llvm/ADT/StringMap.h"
6565
#include "llvm/ADT/StringSwitch.h"
66+
#include "llvm/ADT/STLExtras.h"
6667
#include "llvm/IR/LLVMContext.h"
6768
#include "llvm/Support/Allocator.h"
6869
#include "llvm/Support/Compiler.h"
6970
#include "llvm/Support/FormatVariadic.h"
7071
#include <algorithm>
72+
#include <queue>
7173
#include <memory>
7274

7375
#include "RequirementMachine/RewriteContext.h"
@@ -1822,13 +1824,116 @@ Identifier ASTContext::getRealModuleName(Identifier key, ModuleAliasLookupOption
18221824
return value.first;
18231825
}
18241826

1827+
using ModuleDependencyIDSet = std::unordered_set<ModuleDependencyID, llvm::pair_hash<std::string, ModuleDependenciesKind>>;
1828+
static void findPath_dfs(ModuleDependencyID X,
1829+
ModuleDependencyID Y,
1830+
ModuleDependencyIDSet &visited,
1831+
std::vector<ModuleDependencyID> &stack,
1832+
std::vector<ModuleDependencyID> &result,
1833+
const ModuleDependenciesCache &cache,
1834+
const llvm::StringSet<> &searchPathSet) {
1835+
stack.push_back(X);
1836+
if (X == Y) {
1837+
copy(stack.begin(), stack.end(), std::back_inserter(result));
1838+
return;
1839+
}
1840+
visited.insert(X);
1841+
auto node = cache.findDependencies(X.first, {X.second, searchPathSet});
1842+
assert(node.hasValue() && "Expected cache value for dependency.");
1843+
for (const auto &dep : node->getModuleDependencies()) {
1844+
Optional<ModuleDependenciesKind> lookupKind = None;
1845+
// Underlying Clang module needs an explicit lookup to avoid confusing it
1846+
// with the parent Swift module.
1847+
if ((dep == X.first && node->isSwiftModule()) || node->isClangModule())
1848+
lookupKind = ModuleDependenciesKind::Clang;
1849+
1850+
auto depNode = cache.findDependencies(dep, {lookupKind, searchPathSet});
1851+
if (!depNode.hasValue())
1852+
continue;
1853+
auto depID = std::make_pair(dep, depNode->getKind());
1854+
if (!visited.count(depID)) {
1855+
findPath_dfs(depID, Y, visited, stack, result, cache, searchPathSet);
1856+
}
1857+
}
1858+
stack.pop_back();
1859+
}
1860+
1861+
static std::vector<ModuleDependencyID>
1862+
findPathToDependency(ModuleDependencyID dependency,
1863+
const ModuleDependenciesCache &cache,
1864+
const llvm::StringSet<> &searchPathSet) {
1865+
auto mainModuleDep = cache.findDependencies(cache.getMainModuleName(),
1866+
{ModuleDependenciesKind::SwiftSource,
1867+
searchPathSet});
1868+
// We may be in a batch scan instance which does not have this dependency
1869+
if (!mainModuleDep.hasValue())
1870+
return {};
1871+
auto mainModuleID = std::make_pair(cache.getMainModuleName().str(),
1872+
ModuleDependenciesKind::SwiftSource);
1873+
auto visited = ModuleDependencyIDSet();
1874+
auto stack = std::vector<ModuleDependencyID>();
1875+
auto dependencyPath = std::vector<ModuleDependencyID>();
1876+
findPath_dfs(mainModuleID, dependency, visited, stack, dependencyPath, cache, searchPathSet);
1877+
return dependencyPath;
1878+
}
1879+
1880+
// Diagnose scanner failure and attempt to reconstruct the dependency
1881+
// path from the main module to the missing dependency.
1882+
static void diagnoseScannerFailure(StringRef moduleName,
1883+
DiagnosticEngine &Diags,
1884+
const ModuleDependenciesCache &cache,
1885+
const llvm::StringSet<> &searchPathSet,
1886+
llvm::Optional<ModuleDependencyID> dependencyOf) {
1887+
Diags.diagnose(SourceLoc(), diag::dependency_scan_module_not_found, moduleName);
1888+
if (dependencyOf.hasValue()) {
1889+
auto path = findPathToDependency(dependencyOf.getValue(), cache, searchPathSet);
1890+
// We may fail to construct a path in some cases, such as a Swift overlay of a Clang
1891+
// module dependnecy.
1892+
if (path.empty())
1893+
path = {dependencyOf.getValue()};
1894+
1895+
for (auto it = path.rbegin(), end = path.rend(); it != end; ++it) {
1896+
const auto &entry = *it;
1897+
auto entryNode = cache.findDependencies(entry.first, {entry.second, searchPathSet});
1898+
assert(entryNode.hasValue());
1899+
std::string moduleFilePath = "";
1900+
bool isClang = false;
1901+
switch (entryNode->getKind()) {
1902+
case swift::ModuleDependenciesKind::SwiftSource:
1903+
Diags.diagnose(SourceLoc(), diag::dependency_as_imported_by_main_module, entry.first);
1904+
continue;
1905+
case swift::ModuleDependenciesKind::SwiftInterface:
1906+
moduleFilePath = entryNode->getAsSwiftInterfaceModule()->swiftInterfaceFile;
1907+
break;
1908+
case swift::ModuleDependenciesKind::SwiftBinary:
1909+
moduleFilePath = entryNode->getAsSwiftBinaryModule()->compiledModulePath;
1910+
break;
1911+
case swift::ModuleDependenciesKind::SwiftPlaceholder:
1912+
moduleFilePath = entryNode->getAsPlaceholderDependencyModule()->compiledModulePath;
1913+
break;
1914+
case swift::ModuleDependenciesKind::Clang:
1915+
moduleFilePath = entryNode->getAsClangModule()->moduleMapFile;
1916+
isClang = true;
1917+
break;
1918+
default:
1919+
llvm_unreachable("Unexpected dependency kind");
1920+
}
1921+
1922+
// TODO: Consider turning the module file (interface or modulemap) into the SourceLoc
1923+
// of this diagnostic instead. Ideally with the location of the `import` statement
1924+
// that this dependency originates from.
1925+
Diags.diagnose(SourceLoc(), diag::dependency_as_imported_by, entry.first, moduleFilePath, isClang);
1926+
}
1927+
}
1928+
}
1929+
18251930
Optional<ModuleDependencies> ASTContext::getModuleDependencies(
18261931
StringRef moduleName, bool isUnderlyingClangModule,
18271932
ModuleDependenciesCache &cache, InterfaceSubContextDelegate &delegate,
1828-
bool cacheOnly) {
1933+
bool cacheOnly, llvm::Optional<ModuleDependencyID> dependencyOf) {
1934+
auto searchPathSet = getAllModuleSearchPathsSet();
18291935
// Retrieve the dependencies for this module.
18301936
if (cacheOnly) {
1831-
auto searchPathSet = getAllModuleSearchPathsSet();
18321937
// Check whether we've cached this result.
18331938
if (!isUnderlyingClangModule) {
18341939
if (auto found = cache.findDependencies(
@@ -1860,6 +1965,9 @@ Optional<ModuleDependencies> ASTContext::getModuleDependencies(
18601965
loader->getModuleDependencies(moduleName, cache, delegate))
18611966
return dependencies;
18621967
}
1968+
1969+
diagnoseScannerFailure(moduleName, Diags, cache, searchPathSet,
1970+
dependencyOf);
18631971
}
18641972

18651973
return None;

lib/AST/ModuleDependencies.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -531,8 +531,9 @@ ModuleDependenciesCache::getDependencyReferencesMap(
531531
}
532532

533533
ModuleDependenciesCache::ModuleDependenciesCache(
534-
GlobalModuleDependenciesCache &globalCache)
535-
: globalCache(globalCache) {
534+
GlobalModuleDependenciesCache &globalCache,
535+
StringRef mainScanModuleName)
536+
: globalCache(globalCache), mainScanModuleName(mainScanModuleName) {
536537
for (auto kind = ModuleDependenciesKind::FirstKind;
537538
kind != ModuleDependenciesKind::LastKind; ++kind) {
538539
ModuleDependenciesMap.insert(

lib/ClangImporter/ClangModuleDependencyScanner.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
//
1515
//===----------------------------------------------------------------------===//
1616
#include "ImporterImpl.h"
17+
#include "swift/AST/DiagnosticsSema.h"
1718
#include "swift/AST/ModuleDependencies.h"
1819
#include "swift/Basic/SourceManager.h"
1920
#include "swift/ClangImporter/ClangImporter.h"
@@ -338,8 +339,14 @@ Optional<ModuleDependencies> ClangImporter::getModuleDependencies(
338339
auto clangDependencies = clangImpl->tool.getFullDependencies(
339340
commandLineArgs, workingDir, clangImpl->alreadySeen);
340341
if (!clangDependencies) {
341-
// FIXME: Route this to a normal diagnostic.
342-
llvm::logAllUnhandledErrors(clangDependencies.takeError(), llvm::errs());
342+
auto errorStr = toString(clangDependencies.takeError());
343+
// We ignore the "module 'foo' not found" error, the Swift dependency
344+
// scanner will report such an error only if all of the module loaders
345+
// fail as well.
346+
if (errorStr.find("fatal error: module '" + moduleName.str() + "' not found") == std::string::npos)
347+
ctx.Diags.diagnose(SourceLoc(),
348+
diag::clang_dependency_scan_error,
349+
errorStr);
343350
return None;
344351
}
345352

lib/DependencyScan/DependencyScanningTool.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ DependencyScanningTool::getDependencies(
7373
auto Instance = std::move(*InstanceOrErr);
7474

7575
// Local scan cache instance, wrapping the shared global cache.
76-
ModuleDependenciesCache cache(*SharedCache);
76+
ModuleDependenciesCache cache(*SharedCache,
77+
Instance->getMainModule()->getNameStr());
7778
// Execute the scanning action, retrieving the in-memory result
7879
auto DependenciesOrErr = performModuleScan(*Instance.get(), cache);
7980
if (DependenciesOrErr.getError())
@@ -113,7 +114,8 @@ DependencyScanningTool::getDependencies(
113114
auto Instance = std::move(*InstanceOrErr);
114115

115116
// Local scan cache instance, wrapping the shared global cache.
116-
ModuleDependenciesCache cache(*SharedCache);
117+
ModuleDependenciesCache cache(*SharedCache,
118+
Instance->getMainModule()->getNameStr());
117119
auto BatchScanResults = performBatchModuleScan(
118120
*Instance.get(), cache, VersionedPCMInstanceCacheCache.get(),
119121
Saver, BatchInput);

lib/DependencyScan/ScanDependencies.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "swift/AST/Decl.h"
1717
#include "swift/AST/DiagnosticEngine.h"
1818
#include "swift/AST/DiagnosticsFrontend.h"
19+
#include "swift/AST/DiagnosticsSema.h"
1920
#include "swift/AST/DiagnosticsDriver.h"
2021
#include "swift/AST/Module.h"
2122
#include "swift/AST/ModuleDependencies.h"
@@ -177,7 +178,8 @@ resolveDirectDependencies(CompilerInstance &instance, ModuleDependencyID module,
177178
// Figure out what kind of module we need.
178179
bool onlyClangModule = !isSwift || module.first == dependsOn;
179180
if (auto found = ctx.getModuleDependencies(dependsOn, onlyClangModule,
180-
cache, ASTDelegate, cacheOnly)) {
181+
cache, ASTDelegate, cacheOnly,
182+
module)) {
181183
result.insert({dependsOn, found->getKind()});
182184
}
183185
}
@@ -1108,8 +1110,10 @@ forEachBatchEntry(CompilerInstance &invocationInstance,
11081110
}
11091111
newGlobalCache->configureForTriple(
11101112
newInstance->getInvocation().getLangOptions().Target.str());
1113+
1114+
auto mainModuleName = newInstance->getMainModule()->getNameStr();
11111115
auto newLocalCache = std::make_unique<ModuleDependenciesCache>(
1112-
*newGlobalCache);
1116+
*newGlobalCache, mainModuleName);
11131117
pInstance = newInstance.get();
11141118
pCache = newLocalCache.get();
11151119
subInstanceMap->insert(
@@ -1253,7 +1257,8 @@ bool swift::dependencies::scanDependencies(CompilerInstance &instance) {
12531257
if (opts.ReuseDependencyScannerCache)
12541258
deserializeDependencyCache(instance, globalCache);
12551259

1256-
ModuleDependenciesCache cache(globalCache);
1260+
ModuleDependenciesCache cache(globalCache,
1261+
instance.getMainModule()->getNameStr());
12571262

12581263
// Execute scan
12591264
auto dependenciesOrErr = performModuleScan(instance, cache);
@@ -1288,7 +1293,8 @@ bool swift::dependencies::prescanDependencies(CompilerInstance &instance) {
12881293
GlobalModuleDependenciesCache singleUseGlobalCache;
12891294
singleUseGlobalCache.configureForTriple(instance.getInvocation()
12901295
.getLangOptions().Target.str());
1291-
ModuleDependenciesCache cache(singleUseGlobalCache);
1296+
ModuleDependenciesCache cache(singleUseGlobalCache,
1297+
instance.getMainModule()->getNameStr());
12921298
if (out.has_error() || EC) {
12931299
Context.Diags.diagnose(SourceLoc(), diag::error_opening_output, path,
12941300
EC.message());
@@ -1319,7 +1325,8 @@ bool swift::dependencies::batchScanDependencies(
13191325
GlobalModuleDependenciesCache singleUseGlobalCache;
13201326
singleUseGlobalCache.configureForTriple(instance.getInvocation()
13211327
.getLangOptions().Target.str());
1322-
ModuleDependenciesCache cache(singleUseGlobalCache);
1328+
ModuleDependenciesCache cache(singleUseGlobalCache,
1329+
instance.getMainModule()->getNameStr());
13231330
(void)instance.getMainModule();
13241331
llvm::BumpPtrAllocator alloc;
13251332
llvm::StringSaver saver(alloc);
@@ -1354,7 +1361,8 @@ bool swift::dependencies::batchPrescanDependencies(
13541361
GlobalModuleDependenciesCache singleUseGlobalCache;
13551362
singleUseGlobalCache.configureForTriple(instance.getInvocation()
13561363
.getLangOptions().Target.str());
1357-
ModuleDependenciesCache cache(singleUseGlobalCache);
1364+
ModuleDependenciesCache cache(singleUseGlobalCache,
1365+
instance.getMainModule()->getNameStr());
13581366
(void)instance.getMainModule();
13591367
llvm::BumpPtrAllocator alloc;
13601368
llvm::StringSaver saver(alloc);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// swift-interface-format-version: 1.0
2+
// swift-module-flags: -module-name P
3+
import Y
4+
public func funcP() { }
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// swift-interface-format-version: 1.0
2+
// swift-module-flags: -module-name Y
3+
import Z
4+
public func funcY() { }

0 commit comments

Comments
 (0)