[Dependency Scanning] Specify Source Locations For Missing Module Dependencies

This change modifies the dependency scanner to keep track of source locations of each encountered 'import' statement, in order to be able to emit diagnostics with source locations if an import failed to resolve.

- Keep track of each 'import' statement's source buffer, line number, and column number when adding it. The dependency scanner utilizes separate compilation instances, and therefore separate Source Managers for scanning `import` statements of user sources and textual interfaces of Swift dependencies. Since import resolution may happen in the main scanner compilation instance while the `import` itself was found by an interface-scanning sub-instance, we cannot simply hold on to the import's `SourceLoc`.
- Add libSwiftScan API for diagnostics to carry above source locations to clients.
This commit is contained in:
artemcm
2024-05-10 16:23:49 -07:00
committed by Artem Chikin
parent 6edc0ad1e9
commit 9aeadd0507
16 changed files with 440 additions and 163 deletions

View File

@@ -155,9 +155,9 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi
bool hasCurrentModule = false;
std::string currentModuleName;
unsigned currentContextHashID;
std::optional<std::vector<std::string>> currentModuleImports;
std::optional<std::vector<std::string>> currentOptionalModuleImports;
std::optional<std::vector<ModuleDependencyID>> currentModuleDependencyIDs;
std::vector<ScannerImportStatementInfo> currentModuleImports;
std::vector<ScannerImportStatementInfo> currentOptionalModuleImports;
std::vector<ModuleDependencyID> currentModuleDependencyIDs;
auto getContextHash = [&]() {
assert(currentContextHashID &&
@@ -225,15 +225,22 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi
llvm::report_fatal_error("Bad module name");
currentModuleName = *moduleName;
currentContextHashID = contextHashID;
currentModuleImports = getStringArray(moduleImportsArrayID);
currentOptionalModuleImports = getStringArray(optionalModuleImportsArrayID);
currentModuleDependencyIDs = getModuleDependencyIDArray(moduleDependencyIDArrayID);
if (!currentModuleImports)
llvm::report_fatal_error("Bad direct dependencies: no imports");
if (!currentOptionalModuleImports)
llvm::report_fatal_error("Bad direct dependencies: no optional imports");
if (!currentModuleDependencyIDs)
auto importStrings = getStringArray(moduleImportsArrayID);
auto optionalImportStrings = getStringArray(optionalModuleImportsArrayID);
if (importStrings.has_value()) {
for (const auto &is : importStrings.value())
currentModuleImports.push_back(is);
}
if (optionalImportStrings.has_value()) {
for (const auto &ois : optionalImportStrings.value())
currentOptionalModuleImports.push_back(ois);
}
auto optionalCurrentModuleDependencyIDs = getModuleDependencyIDArray(moduleDependencyIDArrayID);
if (!optionalCurrentModuleDependencyIDs)
llvm::report_fatal_error("Bad direct dependencies: no qualified dependencies");
currentModuleDependencyIDs = optionalCurrentModuleDependencyIDs.value();
break;
}
@@ -301,14 +308,14 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi
*contextHash, isFramework, *rootFileSystemID, *moduleCacheKey);
// Add imports of this module
for (const auto &moduleName : *currentModuleImports)
moduleDep.addModuleImport(moduleName);
for (const auto &moduleName : currentModuleImports)
moduleDep.addModuleImport(moduleName.importIdentifier);
// Add optional imports of this module
for (const auto &moduleName : *currentOptionalModuleImports)
moduleDep.addOptionalModuleImport(moduleName);
for (const auto &moduleName : currentOptionalModuleImports)
moduleDep.addOptionalModuleImport(moduleName.importIdentifier);
// Add qualified dependencies of this module
moduleDep.resolveDirectDependencies(*currentModuleDependencyIDs);
moduleDep.resolveDirectDependencies(currentModuleDependencyIDs);
// Add bridging header file path
if (bridgingHeaderFileID != 0) {
@@ -412,11 +419,11 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi
extraPCMRefs);
// Add dependencies of this module
for (const auto &moduleName : *currentModuleImports)
moduleDep.addModuleImport(moduleName);
for (const auto &moduleName : currentModuleImports)
moduleDep.addModuleImport(moduleName.importIdentifier);
// Add optional imports of this module
for (const auto &moduleName : *currentOptionalModuleImports)
moduleDep.addOptionalModuleImport(moduleName);
for (const auto &moduleName : currentOptionalModuleImports)
moduleDep.addOptionalModuleImport(moduleName.importIdentifier);
// Add bridging header file path
if (bridgingHeaderFileID != 0) {
@@ -504,7 +511,7 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi
// Form the dependencies storage object
auto moduleDep = ModuleDependencyInfo::forSwiftBinaryModule(
*compiledModulePath, *moduleDocPath, *moduleSourceInfoPath,
*currentModuleImports, *currentOptionalModuleImports,
currentModuleImports, currentOptionalModuleImports,
*headerImport, isFramework, *moduleCacheKey);
auto headerModuleDependencies = getStringArray(headerModuleDependenciesArrayID);
@@ -555,12 +562,13 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi
// Form the dependencies storage object
auto moduleDep = ModuleDependencyInfo::forPlaceholderSwiftModuleStub(
*compiledModulePath, *moduleDocPath, *moduleSourceInfoPath);
// Add dependencies of this module
for (const auto &moduleName : *currentModuleImports)
moduleDep.addModuleImport(moduleName);
for (const auto &moduleName : currentModuleImports)
moduleDep.addModuleImport(moduleName.importIdentifier);
// Add optional imports of this module
for (const auto &moduleName : *currentOptionalModuleImports)
moduleDep.addOptionalModuleImport(moduleName);
for (const auto &moduleName : currentOptionalModuleImports)
moduleDep.addOptionalModuleImport(moduleName.importIdentifier);
cache.recordDependency(currentModuleName, std::move(moduleDep),
getContextHash());
@@ -618,11 +626,11 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi
*rootFileSystemID, *clangIncludeTreeRoot, *moduleCacheKey, isSystem);
// Add dependencies of this module
for (const auto &moduleName : *currentModuleImports)
moduleDep.addModuleImport(moduleName);
for (const auto &moduleName : currentModuleImports)
moduleDep.addModuleImport(moduleName.importIdentifier);
// Add optional imports of this module
for (const auto &moduleName : *currentOptionalModuleImports)
moduleDep.addOptionalModuleImport(moduleName);
for (const auto &moduleName : currentOptionalModuleImports)
moduleDep.addOptionalModuleImport(moduleName.importIdentifier);
cache.recordDependency(currentModuleName, std::move(moduleDep),
getContextHash());
@@ -1162,11 +1170,27 @@ void ModuleDependenciesCacheSerializer::collectStringsAndArrays(
auto dependencyInfo = optionalDependencyInfo.value();
// Add the module's name
addIdentifier(moduleID.ModuleName);
// Map import infos to their respective module identifiers
auto importInfoArrayToIdentifier =
[](const auto &importInfo) -> std::string {
return importInfo.importIdentifier;
};
// Add the module's dependencies
std::vector<std::string> importIdentifiers;
llvm::transform(dependencyInfo->getModuleImports(),
std::back_inserter(importIdentifiers),
importInfoArrayToIdentifier);
std::vector<std::string> optionalImportIdentifiers;
llvm::transform(dependencyInfo->getOptionalModuleImports(),
std::back_inserter(optionalImportIdentifiers),
importInfoArrayToIdentifier);
addStringArray(moduleID, ModuleIdentifierArrayKind::DependencyImports,
dependencyInfo->getModuleImports());
importIdentifiers);
addStringArray(moduleID, ModuleIdentifierArrayKind::OptionalDependencyImports,
dependencyInfo->getOptionalModuleImports());
optionalImportIdentifiers);
addDependencyIDArray(
moduleID, ModuleIdentifierArrayKind::QualifiedModuleDependencyIDs,
dependencyInfo->getDirectModuleDependencies());