From 70debc1d8d34df0bbe36c52b1dc988218380a602 Mon Sep 17 00:00:00 2001 From: artemcm Date: Fri, 10 May 2024 16:23:49 -0700 Subject: [PATCH] [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. --- .../swift-c/DependencyScan/DependencyScan.h | 18 ++- include/swift/AST/DiagnosticsSema.def | 2 + include/swift/AST/ModuleDependencies.h | 114 +++++++++++------- .../swift/DependencyScan/DependencyScanImpl.h | 10 +- .../DependencyScan/DependencyScanningTool.h | 3 +- lib/AST/ModuleDependencies.cpp | 69 +++++++++-- lib/DependencyScan/DependencyScanningTool.cpp | 41 +++++-- .../ModuleDependencyCacheSerialization.cpp | 86 ++++++++----- .../ModuleDependencyScanner.cpp | 110 +++++++++++------ lib/DependencyScan/ScanDependencies.cpp | 42 ++++++- lib/Serialization/ScanningLoaders.cpp | 5 +- lib/Serialization/SerializedModuleLoader.cpp | 23 ++-- test/ScanDependencies/error_path.swift | 17 +-- .../error_source_locations.swift | 27 +++++ tools/libSwiftScan/libSwiftScan.cpp | 32 ++++- tools/libSwiftScan/libSwiftScan.exports | 4 + 16 files changed, 440 insertions(+), 163 deletions(-) create mode 100644 test/ScanDependencies/error_source_locations.swift diff --git a/include/swift-c/DependencyScan/DependencyScan.h b/include/swift-c/DependencyScan/DependencyScan.h index c8e48b1ace62f..8320435945672 100644 --- a/include/swift-c/DependencyScan/DependencyScan.h +++ b/include/swift-c/DependencyScan/DependencyScan.h @@ -25,7 +25,7 @@ /// SWIFTSCAN_VERSION_MINOR should increase when there are API additions. /// SWIFTSCAN_VERSION_MAJOR is intended for "major" source/ABI breaking changes. #define SWIFTSCAN_VERSION_MAJOR 0 -#define SWIFTSCAN_VERSION_MINOR 8 +#define SWIFTSCAN_VERSION_MINOR 9 SWIFTSCAN_BEGIN_DECLS @@ -55,6 +55,9 @@ typedef struct swiftscan_import_set_s *swiftscan_import_set_t; /// Opaque container to contain the info of a diagnostics emitted by the scanner. typedef struct swiftscan_diagnostic_info_s *swiftscan_diagnostic_info_t; +/// Opaque container to contain the info of a source location. +typedef struct swiftscan_source_location_s *swiftscan_source_location_t; + /// Full Dependency Graph (Result) typedef struct { swiftscan_dependency_info_t *modules; @@ -419,9 +422,22 @@ swiftscan_diagnostic_get_message(swiftscan_diagnostic_info_t diagnostic); SWIFTSCAN_PUBLIC swiftscan_diagnostic_severity_t swiftscan_diagnostic_get_severity(swiftscan_diagnostic_info_t diagnostic); +SWIFTSCAN_PUBLIC swiftscan_source_location_t +swiftscan_diagnostic_get_source_location(swiftscan_diagnostic_info_t diagnostic); + SWIFTSCAN_PUBLIC void swiftscan_diagnostics_set_dispose(swiftscan_diagnostic_set_t* diagnostics); +//=== Source Location -----------------------------------------------------===// +SWIFTSCAN_PUBLIC swiftscan_string_ref_t +swiftscan_source_location_get_buffer_identifier(swiftscan_source_location_t source_location); + +SWIFTSCAN_PUBLIC int64_t +swiftscan_source_location_get_line_number(swiftscan_source_location_t source_location); + +SWIFTSCAN_PUBLIC int64_t +swiftscan_source_location_get_column_number(swiftscan_source_location_t source_location); + //=== Scanner Cache Operations --------------------------------------------===// // The following operations expose an implementation detail of the dependency // scanner: its module dependencies cache. This is done in order diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 9d6ff5e972266..9252d1e91eb81 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -2206,6 +2206,8 @@ ERROR(alignment_not_power_of_two,none, // Dependency Scanning ERROR(dependency_scan_module_not_found, none, "Unable to find module dependency: '%0'", (StringRef)) +NOTE(unresolved_import_location,none, + "also imported here", ()) NOTE(dependency_as_imported_by_main_module,none, "a dependency of main module '%0'", (StringRef)) NOTE(dependency_as_imported_by, none, diff --git a/include/swift/AST/ModuleDependencies.h b/include/swift/AST/ModuleDependencies.h index a952243fb9e1d..edcf07d957cc5 100644 --- a/include/swift/AST/ModuleDependencies.h +++ b/include/swift/AST/ModuleDependencies.h @@ -129,6 +129,39 @@ namespace dependencies { bool); } +struct ScannerImportStatementInfo { + struct ImportDiagnosticLocationInfo { + ImportDiagnosticLocationInfo() = delete; + ImportDiagnosticLocationInfo(std::string bufferIdentifier, + uint32_t lineNumber, + uint32_t columnNumber) + : bufferIdentifier(bufferIdentifier), + lineNumber(lineNumber), + columnNumber(columnNumber) {} + std::string bufferIdentifier; + uint32_t lineNumber; + uint32_t columnNumber; + }; + + ScannerImportStatementInfo(std::string importIdentifier) + : importLocations(), + importIdentifier(importIdentifier) {} + + ScannerImportStatementInfo(std::string importIdentifier, + ImportDiagnosticLocationInfo location) + : importLocations({location}), + importIdentifier(importIdentifier) {} + + void addImportLocation(ImportDiagnosticLocationInfo location) { + importLocations.push_back(location); + } + + // Buffer, line & column number of the import statement + SmallVector importLocations; + // Imported module string. e.g. "Foo.Bar" in 'import Foo.Bar' + std::string importIdentifier; +}; + /// Base class for the variant storage of ModuleDependencyInfo. /// /// This class is mostly an implementation detail for \c ModuleDependencyInfo. @@ -141,25 +174,27 @@ class ModuleDependencyInfoStorageBase { : dependencyKind(dependencyKind), moduleCacheKey(moduleCacheKey.str()), resolved(false), finalized(false) {} - ModuleDependencyInfoStorageBase(ModuleDependencyKind dependencyKind, - const std::vector &moduleImports, - const std::vector &optionalModuleImports, - StringRef moduleCacheKey = "") + ModuleDependencyInfoStorageBase( + ModuleDependencyKind dependencyKind, + const std::vector &moduleImports, + const std::vector &optionalModuleImports, + StringRef moduleCacheKey = "") : dependencyKind(dependencyKind), moduleImports(moduleImports), optionalModuleImports(optionalModuleImports), - moduleCacheKey(moduleCacheKey.str()), resolved(false), finalized(false) {} + moduleCacheKey(moduleCacheKey.str()), resolved(false), + finalized(false) {} virtual ModuleDependencyInfoStorageBase *clone() const = 0; virtual ~ModuleDependencyInfoStorageBase(); /// The set of modules on which this module depends. - std::vector moduleImports; + std::vector moduleImports; /// The set of modules which constitute optional module /// dependencies for this module, such as `@_implementationOnly` /// or `internal` imports. - std::vector optionalModuleImports; + std::vector optionalModuleImports; /// The set of modules on which this module depends, resolved /// to Module IDs, qualified by module kind: Swift, Clang, etc. @@ -320,21 +355,23 @@ class SwiftSourceModuleDependenciesStorage : } }; -/// Describes the dependencies of a pre-built Swift module (with no .swiftinterface). +/// Describes the dependencies of a pre-built Swift module (with no +/// .swiftinterface). /// /// This class is mostly an implementation detail for \c ModuleDependencyInfo. -class SwiftBinaryModuleDependencyStorage : public ModuleDependencyInfoStorageBase { +class SwiftBinaryModuleDependencyStorage + : public ModuleDependencyInfoStorageBase { public: - SwiftBinaryModuleDependencyStorage(const std::string &compiledModulePath, - const std::string &moduleDocPath, - const std::string &sourceInfoPath, - const std::vector &moduleImports, - const std::vector &optionalModuleImports, - const std::string &headerImport, - const bool isFramework, - const std::string &moduleCacheKey) + SwiftBinaryModuleDependencyStorage( + const std::string &compiledModulePath, const std::string &moduleDocPath, + const std::string &sourceInfoPath, + const std::vector &moduleImports, + const std::vector &optionalModuleImports, + const std::string &headerImport, const bool isFramework, + const std::string &moduleCacheKey) : ModuleDependencyInfoStorageBase(ModuleDependencyKind::SwiftBinary, - moduleImports, optionalModuleImports, moduleCacheKey), + moduleImports, optionalModuleImports, + moduleCacheKey), compiledModulePath(compiledModulePath), moduleDocPath(moduleDocPath), sourceInfoPath(sourceInfoPath), headerImport(headerImport), isFramework(isFramework) {} @@ -520,8 +557,8 @@ class ModuleDependencyInfo { const std::string &compiledModulePath, const std::string &moduleDocPath, const std::string &sourceInfoPath, - const std::vector &moduleImports, - const std::vector &optionalModuleImports, + const std::vector &moduleImports, + const std::vector &optionalModuleImports, const std::string &headerImport, bool isFramework, const std::string &moduleCacheKey) { return ModuleDependencyInfo( @@ -572,12 +609,12 @@ class ModuleDependencyInfo { } /// Retrieve the module-level imports. - ArrayRef getModuleImports() const { + ArrayRef getModuleImports() const { return storage->moduleImports; } /// Retrieve the module-level optional imports. - ArrayRef getOptionalModuleImports() const { + ArrayRef getOptionalModuleImports() const { return storage->optionalModuleImports; } @@ -754,31 +791,24 @@ class ModuleDependencyInfo { void addOptionalModuleImport(StringRef module, llvm::StringSet<> *alreadyAddedModules = nullptr); + /// Add all of the module imports in the given source + /// file to the set of module imports. + void addModuleImports(const SourceFile &sourceFile, + llvm::StringSet<> &alreadyAddedModules, + const SourceManager *sourceManager); /// Add a dependency on the given module, if it was not already in the set. - void addModuleImport(StringRef module, - llvm::StringSet<> *alreadyAddedModules = nullptr); + void addModuleImport(ImportPath::Module module, + llvm::StringSet<> *alreadyAddedModules = nullptr, + const SourceManager *sourceManager = nullptr, + SourceLoc sourceLocation = SourceLoc()); /// Add a dependency on the given module, if it was not already in the set. - void addModuleImport(ImportPath::Module module, - llvm::StringSet<> *alreadyAddedModules = nullptr) { - std::string ImportedModuleName = module.front().Item.str().str(); - auto submodulePath = module.getSubmodulePath(); - if (submodulePath.size() > 0 && !submodulePath[0].Item.empty()) { - auto submoduleComponent = submodulePath[0]; - // Special case: a submodule named "Foo.Private" can be moved to a top-level - // module named "Foo_Private". ClangImporter has special support for this. - if (submoduleComponent.Item.str() == "Private") - addOptionalModuleImport(ImportedModuleName + "_Private", alreadyAddedModules); - } - - addModuleImport(ImportedModuleName, alreadyAddedModules); - } + void addModuleImport(StringRef module, + llvm::StringSet<> *alreadyAddedModules = nullptr, + const SourceManager *sourceManager = nullptr, + SourceLoc sourceLocation = SourceLoc()); - /// Add all of the module imports in the given source - /// file to the set of module imports. - void addModuleImport(const SourceFile &sf, - llvm::StringSet<> &alreadyAddedModules); /// Add a kind-qualified module dependency ID to the set of /// module dependencies. void addModuleDependency(ModuleDependencyID dependencyID); diff --git a/include/swift/DependencyScan/DependencyScanImpl.h b/include/swift/DependencyScan/DependencyScanImpl.h index 857501548cab6..a00dff1d6749a 100644 --- a/include/swift/DependencyScan/DependencyScanImpl.h +++ b/include/swift/DependencyScan/DependencyScanImpl.h @@ -21,7 +21,7 @@ namespace swift { namespace dependencies { class DependencyScanningTool; -} +} // namespace dependencies } // namespace swift struct swiftscan_dependency_graph_s { @@ -212,7 +212,13 @@ struct swiftscan_scan_invocation_s { struct swiftscan_diagnostic_info_s { swiftscan_string_ref_t message; swiftscan_diagnostic_severity_t severity; - // TODO: SourceLoc + swiftscan_source_location_t source_location; +}; + +struct swiftscan_source_location_s { + swiftscan_string_ref_t buffer_identifier; + uint32_t line_number; + uint32_t column_number; }; #endif // SWIFT_C_DEPENDENCY_SCAN_IMPL_H diff --git a/include/swift/DependencyScan/DependencyScanningTool.h b/include/swift/DependencyScan/DependencyScanningTool.h index 1709365ba46b9..6ec5b1f75170e 100644 --- a/include/swift/DependencyScan/DependencyScanningTool.h +++ b/include/swift/DependencyScan/DependencyScanningTool.h @@ -37,10 +37,11 @@ class DependencyScanDiagnosticCollector : public DiagnosticConsumer { struct ScannerDiagnosticInfo { std::string Message; llvm::SourceMgr::DiagKind Severity; + std::optional ImportLocation; }; + std::vector Diagnostics; void handleDiagnostic(SourceManager &SM, const DiagnosticInfo &Info) override; - std::vector Diagnostics; protected: virtual void addDiagnostic(SourceManager &SM, const DiagnosticInfo &Info); diff --git a/lib/AST/ModuleDependencies.cpp b/lib/AST/ModuleDependencies.cpp index eeee5b0f92eeb..03284d448fbd6 100644 --- a/lib/AST/ModuleDependencies.cpp +++ b/lib/AST/ModuleDependencies.cpp @@ -121,16 +121,67 @@ void ModuleDependencyInfo::addOptionalModuleImport( } void ModuleDependencyInfo::addModuleImport( - StringRef module, llvm::StringSet<> *alreadyAddedModules) { - if (!alreadyAddedModules || alreadyAddedModules->insert(module).second) - storage->moduleImports.push_back(module.str()); + StringRef module, llvm::StringSet<> *alreadyAddedModules, + const SourceManager *sourceManager, SourceLoc sourceLocation) { + auto scannerImportLocToDiagnosticLocInfo = + [&sourceManager](SourceLoc sourceLocation) { + auto lineAndColumnNumbers = + sourceManager->getLineAndColumnInBuffer(sourceLocation); + return ScannerImportStatementInfo::ImportDiagnosticLocationInfo( + sourceManager->getDisplayNameForLoc(sourceLocation).str(), + lineAndColumnNumbers.first, lineAndColumnNumbers.second); + }; + bool validSourceLocation = sourceManager && sourceLocation.isValid() && + sourceManager->isOwning(sourceLocation); + + if (alreadyAddedModules && alreadyAddedModules->contains(module)) { + if (validSourceLocation) { + // Find a prior import of this module and add import location + for (auto &existingImport : storage->moduleImports) { + if (existingImport.importIdentifier == module) { + existingImport.addImportLocation( + scannerImportLocToDiagnosticLocInfo(sourceLocation)); + break; + } + } + } + } else { + if (alreadyAddedModules) + alreadyAddedModules->insert(module); + + if (validSourceLocation) + storage->moduleImports.push_back(ScannerImportStatementInfo( + module.str(), scannerImportLocToDiagnosticLocInfo(sourceLocation))); + else + storage->moduleImports.push_back( + ScannerImportStatementInfo(module.str())); + } } void ModuleDependencyInfo::addModuleImport( - const SourceFile &sf, llvm::StringSet<> &alreadyAddedModules) { + ImportPath::Module module, llvm::StringSet<> *alreadyAddedModules, + const SourceManager *sourceManager, SourceLoc sourceLocation) { + std::string ImportedModuleName = module.front().Item.str().str(); + auto submodulePath = module.getSubmodulePath(); + if (submodulePath.size() > 0 && !submodulePath[0].Item.empty()) { + auto submoduleComponent = submodulePath[0]; + // Special case: a submodule named "Foo.Private" can be moved to a top-level + // module named "Foo_Private". ClangImporter has special support for this. + if (submoduleComponent.Item.str() == "Private") + addOptionalModuleImport(ImportedModuleName + "_Private", + alreadyAddedModules); + } + + addModuleImport(ImportedModuleName, alreadyAddedModules, + sourceManager, sourceLocation); +} + +void ModuleDependencyInfo::addModuleImports( + const SourceFile &sourceFile, llvm::StringSet<> &alreadyAddedModules, + const SourceManager *sourceManager) { // Add all of the module dependencies. SmallVector decls; - sf.getTopLevelDecls(decls); + sourceFile.getTopLevelDecls(decls); for (auto decl : decls) { auto importDecl = dyn_cast(decl); if (!importDecl) @@ -149,10 +200,12 @@ void ModuleDependencyInfo::addModuleImport( // Ignore/diagnose tautological imports akin to import resolution if (!swift::dependencies::checkImportNotTautological( - realPath, importDecl->getLoc(), sf, importDecl->isExported())) + realPath, importDecl->getLoc(), sourceFile, + importDecl->isExported())) continue; - addModuleImport(realPath, &alreadyAddedModules); + addModuleImport(realPath, &alreadyAddedModules, + sourceManager, importDecl->getLoc()); // Additionally, keep track of which dependencies of a Source // module are `@Testable`. @@ -161,7 +214,7 @@ void ModuleDependencyInfo::addModuleImport( addTestableImport(realPath); } - auto fileName = sf.getFilename(); + auto fileName = sourceFile.getFilename(); if (fileName.empty()) return; diff --git a/lib/DependencyScan/DependencyScanningTool.cpp b/lib/DependencyScan/DependencyScanningTool.cpp index 04f6fbce34f52..10cb1359cb6cd 100644 --- a/lib/DependencyScan/DependencyScanningTool.cpp +++ b/lib/DependencyScan/DependencyScanningTool.cpp @@ -10,14 +10,15 @@ // //===----------------------------------------------------------------------===// -#include "swift/DependencyScan/DependencyScanningTool.h" -#include "swift/DependencyScan/SerializedModuleDependencyCacheFormat.h" -#include "swift/DependencyScan/StringUtils.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticsFrontend.h" #include "swift/Basic/LLVMInitialize.h" #include "swift/Basic/TargetInfo.h" +#include "swift/Basic/ColorUtils.h" +#include "swift/DependencyScan/DependencyScanningTool.h" #include "swift/DependencyScan/DependencyScanImpl.h" +#include "swift/DependencyScan/SerializedModuleDependencyCacheFormat.h" +#include "swift/DependencyScan/StringUtils.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/VirtualOutputBackends.h" @@ -94,25 +95,43 @@ void DependencyScanDiagnosticCollector::addDiagnostic( SMKind = llvm::SourceMgr::DK_Remark; break; } + // Translate ranges. SmallVector Ranges; for (auto R : Info.Ranges) Ranges.push_back(getRawRange(SM, R)); + // Translate fix-its. SmallVector FixIts; for (DiagnosticInfo::FixIt F : Info.FixIts) FixIts.push_back(getRawFixIt(SM, F)); - std::string ResultingMessage; - llvm::raw_string_ostream Stream(ResultingMessage); - + // Display the diagnostic. + std::string FormattedMessage; + llvm::raw_string_ostream Stream(FormattedMessage); // Actually substitute the diagnostic arguments into the diagnostic text. llvm::SmallString<256> Text; - llvm::raw_svector_ostream Out(Text); - DiagnosticEngine::formatDiagnosticText(Out, Info.FormatString, - Info.FormatArgs); - auto Msg = SM.GetMessage(Info.Loc, SMKind, Text, Ranges, FixIts); - Diagnostics.push_back(ScannerDiagnosticInfo{Msg.getMessage().str(), SMKind}); + { + llvm::raw_svector_ostream Out(Text); + DiagnosticEngine::formatDiagnosticText(Out, Info.FormatString, + Info.FormatArgs); + auto Msg = SM.GetMessage(Info.Loc, SMKind, Text, Ranges, FixIts, true); + Msg.print(nullptr, Stream, false, false, false); + Stream.flush(); + } + + if (Info.Loc && Info.Loc.isValid()) { + auto bufferIdentifier = SM.getDisplayNameForLoc(Info.Loc); + auto lineAndColumnNumbers = SM.getLineAndColumnInBuffer(Info.Loc); + auto importLocation = ScannerImportStatementInfo::ImportDiagnosticLocationInfo( + bufferIdentifier.str(), lineAndColumnNumbers.first, + lineAndColumnNumbers.second); + Diagnostics.push_back( + ScannerDiagnosticInfo{FormattedMessage, SMKind, importLocation}); + } else { + Diagnostics.push_back( + ScannerDiagnosticInfo{FormattedMessage, SMKind, std::nullopt}); + } } void LockingDependencyScanDiagnosticCollector::addDiagnostic( diff --git a/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp b/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp index aa3801c9344d1..3783957c3099c 100644 --- a/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp +++ b/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp @@ -155,9 +155,9 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi bool hasCurrentModule = false; std::string currentModuleName; unsigned currentContextHashID; - std::optional> currentModuleImports; - std::optional> currentOptionalModuleImports; - std::optional> currentModuleDependencyIDs; + std::vector currentModuleImports; + std::vector currentOptionalModuleImports; + std::vector 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 importIdentifiers; + llvm::transform(dependencyInfo->getModuleImports(), + std::back_inserter(importIdentifiers), + importInfoArrayToIdentifier); + std::vector 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()); diff --git a/lib/DependencyScan/ModuleDependencyScanner.cpp b/lib/DependencyScan/ModuleDependencyScanner.cpp index 19454b3972e7c..179bbceb91d13 100644 --- a/lib/DependencyScan/ModuleDependencyScanner.cpp +++ b/lib/DependencyScan/ModuleDependencyScanner.cpp @@ -54,14 +54,15 @@ static void findPath_dfs(ModuleDependencyID X, ModuleDependencyID Y, std::optional lookupKind = std::nullopt; // Underlying Clang module needs an explicit lookup to avoid confusing it // with the parent Swift module. - if ((dep == X.ModuleName && node->isSwiftModule()) || node->isClangModule()) + if ((dep.importIdentifier == X.ModuleName && node->isSwiftModule()) || + node->isClangModule()) lookupKind = ModuleDependencyKind::Clang; - auto optionalDepNode = cache.findDependency(dep, lookupKind); + auto optionalDepNode = cache.findDependency(dep.importIdentifier, lookupKind); if (!optionalDepNode.has_value()) continue; auto depNode = optionalDepNode.value(); - auto depID = ModuleDependencyID{dep, depNode->getKind()}; + auto depID = ModuleDependencyID{dep.importIdentifier, depNode->getKind()}; if (!visited.count(depID)) { findPath_dfs(depID, Y, visited, stack, result, cache); } @@ -89,11 +90,20 @@ findPathToDependency(ModuleDependencyID dependency, // Diagnose scanner failure and attempt to reconstruct the dependency // path from the main module to the missing dependency. static void -diagnoseScannerFailure(StringRef moduleName, DiagnosticEngine &Diags, +diagnoseScannerFailure(const ScannerImportStatementInfo &moduleImport, + DiagnosticEngine &Diags, const ModuleDependenciesCache &cache, std::optional dependencyOf) { - Diags.diagnose(SourceLoc(), diag::dependency_scan_module_not_found, - moduleName); + SourceLoc importLoc = SourceLoc(); + if (!moduleImport.importLocations.empty()) { + auto locInfo = moduleImport.importLocations[0]; + importLoc = Diags.SourceMgr.getLocFromExternalSource(locInfo.bufferIdentifier, + locInfo.lineNumber, + locInfo.columnNumber); + } + + Diags.diagnose(importLoc, diag::dependency_scan_module_not_found, + moduleImport.importIdentifier); if (dependencyOf.has_value()) { auto path = findPathToDependency(dependencyOf.value(), cache); // We may fail to construct a path in some cases, such as a Swift overlay of @@ -110,7 +120,7 @@ diagnoseScannerFailure(StringRef moduleName, DiagnosticEngine &Diags, bool isClang = false; switch (entryNode->getKind()) { case swift::ModuleDependencyKind::SwiftSource: - Diags.diagnose(SourceLoc(), diag::dependency_as_imported_by_main_module, + Diags.diagnose(importLoc, diag::dependency_as_imported_by_main_module, entry.ModuleName); continue; case swift::ModuleDependencyKind::SwiftInterface: @@ -133,13 +143,20 @@ diagnoseScannerFailure(StringRef moduleName, DiagnosticEngine &Diags, llvm_unreachable("Unexpected dependency kind"); } - // TODO: Consider turning the module file (interface or modulemap) into - // the SourceLoc of this diagnostic instead. Ideally with the location of - // the `import` statement that this dependency originates from. - Diags.diagnose(SourceLoc(), diag::dependency_as_imported_by, + Diags.diagnose(importLoc, diag::dependency_as_imported_by, entry.ModuleName, moduleFilePath, isClang); } } + + if (moduleImport.importLocations.size() > 1) { + for (size_t i = 1; i < moduleImport.importLocations.size(); ++i) { + auto locInfo = moduleImport.importLocations[i]; + auto importLoc = Diags.SourceMgr.getLocFromExternalSource(locInfo.bufferIdentifier, + locInfo.lineNumber, + locInfo.columnNumber); + Diags.diagnose(importLoc, diag::unresolved_import_location); + } + } } ModuleDependencyScanningWorker::ModuleDependencyScanningWorker( @@ -391,13 +408,15 @@ ModuleDependencyScanner::getMainModuleDependencyInfo(ModuleDecl *mainModule) { // Add any implicit module names. for (const auto &import : importInfo.AdditionalUnloadedImports) { mainDependencies.addModuleImport(import.module.getModulePath(), - &alreadyAddedModules); + &alreadyAddedModules, + &ScanASTContext.SourceMgr); } // Already-loaded, implicitly imported module names. for (const auto &import : importInfo.AdditionalImports) { mainDependencies.addModuleImport( - import.module.importedModule->getNameStr(), &alreadyAddedModules); + import.module.importedModule->getNameStr(), + &alreadyAddedModules); } // Add the bridging header. @@ -417,18 +436,21 @@ ModuleDependencyScanner::getMainModuleDependencyInfo(ModuleDecl *mainModule) { // to be impored in the source. for (const auto &tbdSymbolModule : ScanCompilerInvocation.getTBDGenOptions().embedSymbolsFromModules) { - mainDependencies.addModuleImport(tbdSymbolModule, &alreadyAddedModules); + mainDependencies.addModuleImport(tbdSymbolModule, + &alreadyAddedModules); } } // Add source-specified `import` dependencies { for (auto fileUnit : mainModule->getFiles()) { - auto sf = dyn_cast(fileUnit); - if (!sf) + auto sourceFile = dyn_cast(fileUnit); + if (!sourceFile) continue; - mainDependencies.addModuleImport(*sf, alreadyAddedModules); + mainDependencies.addModuleImports(*sourceFile, + alreadyAddedModules, + &ScanASTContext.SourceMgr); } // Add all the successful canImport checks from the ASTContext as part of @@ -437,8 +459,9 @@ ModuleDependencyScanner::getMainModuleDependencyInfo(ModuleDecl *mainModule) { // SourceFiles. for (auto &Module : mainModule->getASTContext().getSuccessfulCanImportCheckNames()) - mainDependencies.addModuleImport(Module.first(), &alreadyAddedModules); - } + mainDependencies.addModuleImport(Module.first(), + &alreadyAddedModules); + } return mainDependencies; } @@ -558,8 +581,9 @@ void ModuleDependencyScanner::resolveImportDependencies( auto moduleDependencyInfo = optionalModuleDependencyInfo.value(); llvm::StringMap> moduleLookupResult; + // ACTDOO: Import refactor for (const auto &dependsOn : moduleDependencyInfo->getModuleImports()) - moduleLookupResult.insert(std::make_pair(dependsOn, std::nullopt)); + moduleLookupResult.insert(std::make_pair(dependsOn.importIdentifier, std::nullopt)); // A scanning task to query a module by-name. If the module already exists // in the cache, do nothing and return. @@ -588,51 +612,55 @@ void ModuleDependencyScanner::resolveImportDependencies( moduleLookupResult.insert_or_assign(moduleName, moduleDependencies); }; + // ACTDOO: Import refactor // Enque asynchronous lookup tasks for (const auto &dependsOn : moduleDependencyInfo->getModuleImports()) { - bool underlyingClangModuleLookup = moduleID.ModuleName == dependsOn; - bool isTestable = moduleDependencyInfo->isTestableImport(dependsOn); - ScanningThreadPool.async(scanForModuleDependency, getModuleImportIdentifier(dependsOn), + bool underlyingClangModuleLookup = moduleID.ModuleName == dependsOn.importIdentifier; + bool isTestable = moduleDependencyInfo->isTestableImport(dependsOn.importIdentifier); + ScanningThreadPool.async(scanForModuleDependency, getModuleImportIdentifier(dependsOn.importIdentifier), underlyingClangModuleLookup, isTestable); } for (const auto &dependsOn : moduleDependencyInfo->getOptionalModuleImports()) { - bool underlyingClangModuleLookup = moduleID.ModuleName == dependsOn; - bool isTestable = moduleDependencyInfo->isTestableImport(dependsOn); - ScanningThreadPool.async(scanForModuleDependency, getModuleImportIdentifier(dependsOn), + bool underlyingClangModuleLookup = moduleID.ModuleName == dependsOn.importIdentifier; + bool isTestable = moduleDependencyInfo->isTestableImport(dependsOn.importIdentifier); + ScanningThreadPool.async(scanForModuleDependency, getModuleImportIdentifier(dependsOn.importIdentifier), underlyingClangModuleLookup, isTestable); } ScanningThreadPool.wait(); - std::vector unresolvedImports; + std::vector unresolvedImports; // Aggregate both previously-cached and freshly-scanned module results auto recordResolvedModuleImport = [&cache, &moduleLookupResult, &unresolvedImports, &directDependencies, - moduleID](const std::string &moduleName, bool optionalImport) { - bool underlyingClangModule = moduleID.ModuleName == moduleName; - auto lookupResult = moduleLookupResult[moduleName]; + moduleID](const ScannerImportStatementInfo &moduleImport, bool optionalImport) { + bool underlyingClangModule = moduleID.ModuleName == moduleImport.importIdentifier; + auto lookupResult = moduleLookupResult[moduleImport.importIdentifier]; // The imported module was found in the cache if (lookupResult == std::nullopt) { const ModuleDependencyInfo *cachedInfo; if (underlyingClangModule) cachedInfo = - cache.findDependency(moduleName, ModuleDependencyKind::Clang) - .value(); + cache.findDependency(moduleImport.importIdentifier, + ModuleDependencyKind::Clang).value(); else - cachedInfo = cache.findDependency(moduleName).value(); + cachedInfo = + cache.findDependency(moduleImport.importIdentifier).value(); assert(cachedInfo && "Expected cached dependency info"); - directDependencies.insert({moduleName, cachedInfo->getKind()}); + directDependencies.insert({moduleImport.importIdentifier, + cachedInfo->getKind()}); } else { // Cache discovered module dependencies. if (!lookupResult.value().empty()) { cache.recordDependencies(lookupResult.value()); directDependencies.insert( - {moduleName, lookupResult.value()[0].first.Kind}); + {moduleImport.importIdentifier, + lookupResult.value()[0].first.Kind}); } else if (!optionalImport) { // Otherwise, we failed to resolve this dependency. We will try // again using the cache after all other imports have been resolved. // If that fails too, a scanning failure will be diagnosed. - unresolvedImports.push_back(moduleName); + unresolvedImports.push_back(moduleImport); } } }; @@ -665,14 +693,16 @@ void ModuleDependencyScanner::resolveImportDependencies( // transitive dependencies to the cache, and then attempt to re-query imports // for which resolution originally failed from the cache. If this fails, then // the scanner genuinely failed to resolve this dependency. - for (const auto &moduleName : unresolvedImports) { + for (const auto &moduleImport : unresolvedImports) { auto optionalCachedModuleInfo = - cache.findDependency({moduleName, ModuleDependencyKind::Clang}); + cache.findDependency({moduleImport.importIdentifier, + ModuleDependencyKind::Clang}); if (optionalCachedModuleInfo.has_value()) directDependencies.insert( - {moduleName, optionalCachedModuleInfo.value()->getKind()}); + {moduleImport.importIdentifier, + optionalCachedModuleInfo.value()->getKind()}); else - diagnoseScannerFailure(moduleName, Diagnostics, cache, moduleID); + diagnoseScannerFailure(moduleImport, Diagnostics, cache, moduleID); } } diff --git a/lib/DependencyScan/ScanDependencies.cpp b/lib/DependencyScan/ScanDependencies.cpp index f8f6c3c0f082e..3e361dfee5c83 100644 --- a/lib/DependencyScan/ScanDependencies.cpp +++ b/lib/DependencyScan/ScanDependencies.cpp @@ -1109,6 +1109,7 @@ static void bridgeDependencyIDs(const ArrayRef dependencies, } static swiftscan_diagnostic_set_t *mapCollectedDiagnosticsForOutput( + const SourceManager &SM, const DependencyScanDiagnosticCollector *diagnosticCollector) { auto collectedDiagnostics = diagnosticCollector->getDiagnostics(); auto numDiagnostics = collectedDiagnostics.size(); @@ -1136,6 +1137,22 @@ static swiftscan_diagnostic_set_t *mapCollectedDiagnosticsForOutput( diagnosticInfo->severity = SWIFTSCAN_DIAGNOSTIC_SEVERITY_REMARK; break; } + + if (Diagnostic.ImportLocation.has_value()) { + auto importLocation = Diagnostic.ImportLocation.value(); + swiftscan_source_location_s *sourceLoc = new swiftscan_source_location_s; + if (importLocation.bufferIdentifier.empty()) + sourceLoc->buffer_identifier = swift::c_string_utils::create_null(); + else + sourceLoc->buffer_identifier = swift::c_string_utils::create_clone( + importLocation.bufferIdentifier.c_str()); + sourceLoc->line_number = importLocation.lineNumber; + sourceLoc->column_number = importLocation.columnNumber; + diagnosticInfo->source_location = sourceLoc; + } else { + diagnosticInfo->source_location = nullptr; + } + diagnosticOutput->diagnostics[i] = diagnosticInfo; } return diagnosticOutput; @@ -1322,9 +1339,10 @@ generateFullDependencyGraph(const CompilerInstance &instance, result->main_module_name = create_clone(mainModuleName.c_str()); result->dependencies = dependencySet; result->diagnostics = - diagnosticCollector - ? mapCollectedDiagnosticsForOutput(diagnosticCollector) - : nullptr; + diagnosticCollector + ? mapCollectedDiagnosticsForOutput(instance.getSourceMgr(), + diagnosticCollector) + : nullptr; return result; } @@ -1984,10 +2002,24 @@ swift::dependencies::performModulePrescan(CompilerInstance &instance, if (!mainDependencies) return mainDependencies.getError(); auto *importSet = new swiftscan_import_set_s; - importSet->imports = create_set(mainDependencies->getModuleImports()); + + std::vector importIdentifiers; + importIdentifiers.reserve(mainDependencies->getModuleImports().size()); + llvm::transform(mainDependencies->getModuleImports(), + std::back_inserter(importIdentifiers), + [](const auto &importInfo) -> std::string { + return importInfo.importIdentifier; + }); + importSet->imports = create_set(importIdentifiers); + importSet->diagnostics = + diagnosticCollector + ? mapCollectedDiagnosticsForOutput(instance.getSourceMgr(), + diagnosticCollector) + : nullptr; importSet->diagnostics = diagnosticCollector - ? mapCollectedDiagnosticsForOutput(diagnosticCollector) + ? mapCollectedDiagnosticsForOutput(instance.getSourceMgr(), + diagnosticCollector) : nullptr; return importSet; } diff --git a/lib/Serialization/ScanningLoaders.cpp b/lib/Serialization/ScanningLoaders.cpp index 0bb53171a8c37..1293acb794ca1 100644 --- a/lib/Serialization/ScanningLoaders.cpp +++ b/lib/Serialization/ScanningLoaders.cpp @@ -240,14 +240,15 @@ SwiftModuleScanner::scanInterfaceFile(Twine moduleInterfacePath, // Walk the source file to find the import declarations. llvm::StringSet<> alreadyAddedModules; - Result->addModuleImport(*sourceFile, alreadyAddedModules); + Result->addModuleImports(*sourceFile, alreadyAddedModules, + &Ctx.SourceMgr); // Collect implicitly imported modules in case they are not explicitly // printed in the interface file, e.g. SwiftOnoneSupport. auto &imInfo = mainMod->getImplicitImportInfo(); for (auto import : imInfo.AdditionalUnloadedImports) { Result->addModuleImport(import.module.getModulePath(), - &alreadyAddedModules); + &alreadyAddedModules, &Ctx.SourceMgr); } return std::error_code(); diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index 62d0de51da0f7..1461b30f17567 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -479,26 +479,25 @@ SerializedModuleLoaderBase::scanModuleFile(Twine modulePath, bool isFramework, Ctx.LangOpts.PackageName, isTestableImport); auto importedModuleSet = binaryModuleImports->moduleImports; - std::vector importedModuleNames; - importedModuleNames.reserve(importedModuleSet.size()); - llvm::transform(importedModuleSet.keys(), - std::back_inserter(importedModuleNames), - [](llvm::StringRef N) { - return N.str(); - }); + std::vector moduleImports; + moduleImports.reserve(importedModuleSet.size()); + llvm::transform( + importedModuleSet.keys(), std::back_inserter(moduleImports), + [](llvm::StringRef N) { return ScannerImportStatementInfo(N.str()); }); auto importedHeader = binaryModuleImports->headerImport; auto &importedOptionalModuleSet = binaryModuleOptionalImports->moduleImports; - std::vector importedOptionalModuleNames; + std::vector optionalModuleImports; for (const auto optionalImportedModule : importedOptionalModuleSet.keys()) if (!importedModuleSet.contains(optionalImportedModule)) - importedOptionalModuleNames.push_back(optionalImportedModule.str()); + optionalModuleImports.push_back( + ScannerImportStatementInfo(optionalImportedModule.str())); // Map the set of dependencies over to the "module dependencies". auto dependencies = ModuleDependencyInfo::forSwiftBinaryModule( - modulePath.str(), moduleDocPath, sourceInfoPath, - importedModuleNames, importedOptionalModuleNames, - importedHeader, isFramework, /*module-cache-key*/ ""); + modulePath.str(), moduleDocPath, sourceInfoPath, moduleImports, + optionalModuleImports, importedHeader, isFramework, + /*module-cache-key*/ ""); return std::move(dependencies); } diff --git a/test/ScanDependencies/error_path.swift b/test/ScanDependencies/error_path.swift index f8301f00353b6..0e128e2cea40b 100644 --- a/test/ScanDependencies/error_path.swift +++ b/test/ScanDependencies/error_path.swift @@ -1,14 +1,17 @@ -// expected-error@-1 {{Unable to find module dependency: 'missing_module'}} // RUN: %empty-directory(%t) // RUN: mkdir -p %t/clang-module-cache // REQUIRES: objc_interop - // RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 2>&1 | %FileCheck %s import P -// CHECK: :0: error: Unable to find module dependency: 'missing_module' -// CHECK: :0: note: a dependency of Swift module 'Z': '{{.*}}/Inputs/Swift/Z.swiftinterface' -// CHECK: :0: note: a dependency of Swift module 'Y': '{{.*}}/Inputs/Swift/Y.swiftinterface' -// CHECK: :0: note: a dependency of Swift module 'P': '{{.*}}/Inputs/Swift/P.swiftinterface' -// CHECK: :0: note: a dependency of main module 'deps' +// CHECK: {{.*}}{{/|\\}}Z.swiftinterface:3:8: error: Unable to find module dependency: 'missing_module' +// CHECK-NEXT: 1 | // swift-interface-format-version: 1.0 +// CHECK-NEXT: 2 | // swift-module-flags: -module-name Z +// CHECK-NEXT: 3 | import missing_module +// CHECK-NEXT: | |- error: Unable to find module dependency: 'missing_module' +// CHECK-NEXT: | |- note: a dependency of Swift module 'Z': '{{.*}}{{/|\\}}Z.swiftinterface' +// CHECK-NEXT: | |- note: a dependency of Swift module 'Y': '{{.*}}{{/|\\}}Y.swiftinterface' +// CHECK-NEXT: | |- note: a dependency of Swift module 'P': '{{.*}}{{/|\\}}P.swiftinterface' +// CHECK-NEXT: | `- note: a dependency of main module 'deps' +// CHECK-NEXT: 4 | public func funcZ() { } diff --git a/test/ScanDependencies/error_source_locations.swift b/test/ScanDependencies/error_source_locations.swift new file mode 100644 index 0000000000000..be4392a02795e --- /dev/null +++ b/test/ScanDependencies/error_source_locations.swift @@ -0,0 +1,27 @@ +// RUN: %empty-directory(%t) +// RUN: mkdir -p %t/clang-module-cache +// REQUIRES: objc_interop +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 2>&1 | %FileCheck %s + +import P +import FooBar + +// CHECK: {{.*}}{{/|\\}}error_source_locations.swift:7:8: error: Unable to find module dependency: 'FooBar' +// CHECK-NEXT: 5 | +// CHECK-NEXT: 6 | import P +// CHECK-NEXT: 7 | import FooBar +// CHECK-NEXT: | |- error: Unable to find module dependency: 'FooBar' +// CHECK-NEXT: | `- note: a dependency of main module 'deps' +// CHECK-NEXT: 8 | +// CHECK-NEXT: 9 | + +// CHECK: {{.*}}{{/|\\}}Z.swiftinterface:3:8: error: Unable to find module dependency: 'missing_module' +// CHECK-NEXT: 1 | // swift-interface-format-version: 1.0 +// CHECK-NEXT: 2 | // swift-module-flags: -module-name Z +// CHECK-NEXT: 3 | import missing_module +// CHECK-NEXT: | |- error: Unable to find module dependency: 'missing_module' +// CHECK-NEXT: | |- note: a dependency of Swift module 'Z': '{{.*}}{{/|\\}}Z.swiftinterface' +// CHECK-NEXT: | |- note: a dependency of Swift module 'Y': '{{.*}}{{/|\\}}Y.swiftinterface' +// CHECK-NEXT: | |- note: a dependency of Swift module 'P': '{{.*}}{{/|\\}}P.swiftinterface' +// CHECK-NEXT: | `- note: a dependency of main module 'deps' +// CHECK-NEXT: 4 | public func funcZ() { } diff --git a/tools/libSwiftScan/libSwiftScan.cpp b/tools/libSwiftScan/libSwiftScan.cpp index 1838d8bc5fb07..9121ecd925ce1 100644 --- a/tools/libSwiftScan/libSwiftScan.cpp +++ b/tools/libSwiftScan/libSwiftScan.cpp @@ -14,6 +14,7 @@ // //===----------------------------------------------------------------------===// +#include "swift-c/DependencyScan/DependencyScan.h" #include "swift/Basic/LLVMInitialize.h" #include "swift/Basic/InitializeSwiftModules.h" #include "swift/DependencyScan/DependencyScanImpl.h" @@ -505,7 +506,7 @@ void swiftscan_scan_invocation_set_working_directory( invocation->working_directory = swift::c_string_utils::create_clone(working_directory); } -SWIFTSCAN_PUBLIC void +void swiftscan_scan_invocation_set_argv(swiftscan_scan_invocation_t invocation, int argc, const char **argv) { invocation->argv = swift::c_string_utils::create_set(argc, argv); @@ -662,6 +663,9 @@ swiftscan_scanner_diagnostics_query(swiftscan_scanner_t scanner) { DiagnosticInfo->severity = SWIFTSCAN_DIAGNOSTIC_SEVERITY_REMARK; break; } + // swiftscan_scanner_diagnostics_query is deprecated, + // so it does not support source locations. + DiagnosticInfo->source_location = nullptr; Result->diagnostics[i] = DiagnosticInfo; } @@ -684,8 +688,17 @@ swiftscan_diagnostic_get_severity(swiftscan_diagnostic_info_t diagnostic) { return diagnostic->severity; } +swiftscan_source_location_t +swiftscan_diagnostic_get_source_location(swiftscan_diagnostic_info_t diagnostic) { + return diagnostic->source_location; +} + void swiftscan_diagnostic_dispose(swiftscan_diagnostic_info_t diagnostic) { swiftscan_string_dispose(diagnostic->message); + if (diagnostic->source_location) { + swiftscan_string_dispose(diagnostic->source_location->buffer_identifier); + delete diagnostic->source_location; + } delete diagnostic; } @@ -698,6 +711,23 @@ swiftscan_diagnostics_set_dispose(swiftscan_diagnostic_set_t* diagnostics){ delete diagnostics; } +//=== Source Location -----------------------------------------------------===// + +swiftscan_string_ref_t +swiftscan_source_location_get_buffer_identifier(swiftscan_source_location_t source_location) { + return source_location->buffer_identifier; +} + +int64_t +swiftscan_source_location_get_line_number(swiftscan_source_location_t source_location) { + return source_location->line_number; +} + +int64_t +swiftscan_source_location_get_column_number(swiftscan_source_location_t source_location) { + return source_location->column_number; +} + //=== Experimental Compiler Invocation Functions ------------------------===// int invoke_swift_compiler(int argc, const char **argv) { diff --git a/tools/libSwiftScan/libSwiftScan.exports b/tools/libSwiftScan/libSwiftScan.exports index af002619c7de5..2232eb027a6c8 100644 --- a/tools/libSwiftScan/libSwiftScan.exports +++ b/tools/libSwiftScan/libSwiftScan.exports @@ -78,7 +78,11 @@ swiftscan_scanner_diagnostics_query swiftscan_scanner_diagnostics_reset swiftscan_diagnostic_get_message swiftscan_diagnostic_get_severity +swiftscan_diagnostic_get_source_location swiftscan_diagnostics_set_dispose +swiftscan_source_location_get_buffer_identifier +swiftscan_source_location_get_line_number +swiftscan_source_location_get_column_number swiftscan_cas_create_from_options swiftscan_cas_get_ondisk_size swiftscan_cas_set_ondisk_size_limit