Skip to content

Commit 0b9c25d

Browse files
authored
Merge pull request #73600 from artemcm/DepScanSourceLocsV2
[Dependency Scanning] Specify Source Locations For Missing Module Dependencies
2 parents 6339b22 + 9aeadd0 commit 0b9c25d

16 files changed

+440
-163
lines changed

include/swift-c/DependencyScan/DependencyScan.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
/// SWIFTSCAN_VERSION_MINOR should increase when there are API additions.
2626
/// SWIFTSCAN_VERSION_MAJOR is intended for "major" source/ABI breaking changes.
2727
#define SWIFTSCAN_VERSION_MAJOR 0
28-
#define SWIFTSCAN_VERSION_MINOR 8
28+
#define SWIFTSCAN_VERSION_MINOR 9
2929

3030
SWIFTSCAN_BEGIN_DECLS
3131

@@ -55,6 +55,9 @@ typedef struct swiftscan_import_set_s *swiftscan_import_set_t;
5555
/// Opaque container to contain the info of a diagnostics emitted by the scanner.
5656
typedef struct swiftscan_diagnostic_info_s *swiftscan_diagnostic_info_t;
5757

58+
/// Opaque container to contain the info of a source location.
59+
typedef struct swiftscan_source_location_s *swiftscan_source_location_t;
60+
5861
/// Full Dependency Graph (Result)
5962
typedef struct {
6063
swiftscan_dependency_info_t *modules;
@@ -419,9 +422,22 @@ swiftscan_diagnostic_get_message(swiftscan_diagnostic_info_t diagnostic);
419422
SWIFTSCAN_PUBLIC swiftscan_diagnostic_severity_t
420423
swiftscan_diagnostic_get_severity(swiftscan_diagnostic_info_t diagnostic);
421424

425+
SWIFTSCAN_PUBLIC swiftscan_source_location_t
426+
swiftscan_diagnostic_get_source_location(swiftscan_diagnostic_info_t diagnostic);
427+
422428
SWIFTSCAN_PUBLIC void
423429
swiftscan_diagnostics_set_dispose(swiftscan_diagnostic_set_t* diagnostics);
424430

431+
//=== Source Location -----------------------------------------------------===//
432+
SWIFTSCAN_PUBLIC swiftscan_string_ref_t
433+
swiftscan_source_location_get_buffer_identifier(swiftscan_source_location_t source_location);
434+
435+
SWIFTSCAN_PUBLIC int64_t
436+
swiftscan_source_location_get_line_number(swiftscan_source_location_t source_location);
437+
438+
SWIFTSCAN_PUBLIC int64_t
439+
swiftscan_source_location_get_column_number(swiftscan_source_location_t source_location);
440+
425441
//=== Scanner Cache Operations --------------------------------------------===//
426442
// The following operations expose an implementation detail of the dependency
427443
// scanner: its module dependencies cache. This is done in order

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2224,6 +2224,8 @@ ERROR(alignment_not_power_of_two,none,
22242224

22252225
// Dependency Scanning
22262226
ERROR(dependency_scan_module_not_found, none, "Unable to find module dependency: '%0'", (StringRef))
2227+
NOTE(unresolved_import_location,none,
2228+
"also imported here", ())
22272229
NOTE(dependency_as_imported_by_main_module,none,
22282230
"a dependency of main module '%0'", (StringRef))
22292231
NOTE(dependency_as_imported_by, none,

include/swift/AST/ModuleDependencies.h

Lines changed: 72 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,39 @@ namespace dependencies {
129129
bool);
130130
}
131131

132+
struct ScannerImportStatementInfo {
133+
struct ImportDiagnosticLocationInfo {
134+
ImportDiagnosticLocationInfo() = delete;
135+
ImportDiagnosticLocationInfo(std::string bufferIdentifier,
136+
uint32_t lineNumber,
137+
uint32_t columnNumber)
138+
: bufferIdentifier(bufferIdentifier),
139+
lineNumber(lineNumber),
140+
columnNumber(columnNumber) {}
141+
std::string bufferIdentifier;
142+
uint32_t lineNumber;
143+
uint32_t columnNumber;
144+
};
145+
146+
ScannerImportStatementInfo(std::string importIdentifier)
147+
: importLocations(),
148+
importIdentifier(importIdentifier) {}
149+
150+
ScannerImportStatementInfo(std::string importIdentifier,
151+
ImportDiagnosticLocationInfo location)
152+
: importLocations({location}),
153+
importIdentifier(importIdentifier) {}
154+
155+
void addImportLocation(ImportDiagnosticLocationInfo location) {
156+
importLocations.push_back(location);
157+
}
158+
159+
// Buffer, line & column number of the import statement
160+
SmallVector<ImportDiagnosticLocationInfo, 4> importLocations;
161+
// Imported module string. e.g. "Foo.Bar" in 'import Foo.Bar'
162+
std::string importIdentifier;
163+
};
164+
132165
/// Base class for the variant storage of ModuleDependencyInfo.
133166
///
134167
/// This class is mostly an implementation detail for \c ModuleDependencyInfo.
@@ -141,25 +174,27 @@ class ModuleDependencyInfoStorageBase {
141174
: dependencyKind(dependencyKind), moduleCacheKey(moduleCacheKey.str()),
142175
resolved(false), finalized(false) {}
143176

144-
ModuleDependencyInfoStorageBase(ModuleDependencyKind dependencyKind,
145-
const std::vector<std::string> &moduleImports,
146-
const std::vector<std::string> &optionalModuleImports,
147-
StringRef moduleCacheKey = "")
177+
ModuleDependencyInfoStorageBase(
178+
ModuleDependencyKind dependencyKind,
179+
const std::vector<ScannerImportStatementInfo> &moduleImports,
180+
const std::vector<ScannerImportStatementInfo> &optionalModuleImports,
181+
StringRef moduleCacheKey = "")
148182
: dependencyKind(dependencyKind), moduleImports(moduleImports),
149183
optionalModuleImports(optionalModuleImports),
150-
moduleCacheKey(moduleCacheKey.str()), resolved(false), finalized(false) {}
184+
moduleCacheKey(moduleCacheKey.str()), resolved(false),
185+
finalized(false) {}
151186

152187
virtual ModuleDependencyInfoStorageBase *clone() const = 0;
153188

154189
virtual ~ModuleDependencyInfoStorageBase();
155190

156191
/// The set of modules on which this module depends.
157-
std::vector<std::string> moduleImports;
192+
std::vector<ScannerImportStatementInfo> moduleImports;
158193

159194
/// The set of modules which constitute optional module
160195
/// dependencies for this module, such as `@_implementationOnly`
161196
/// or `internal` imports.
162-
std::vector<std::string> optionalModuleImports;
197+
std::vector<ScannerImportStatementInfo> optionalModuleImports;
163198

164199
/// The set of modules on which this module depends, resolved
165200
/// to Module IDs, qualified by module kind: Swift, Clang, etc.
@@ -320,21 +355,23 @@ class SwiftSourceModuleDependenciesStorage :
320355
}
321356
};
322357

323-
/// Describes the dependencies of a pre-built Swift module (with no .swiftinterface).
358+
/// Describes the dependencies of a pre-built Swift module (with no
359+
/// .swiftinterface).
324360
///
325361
/// This class is mostly an implementation detail for \c ModuleDependencyInfo.
326-
class SwiftBinaryModuleDependencyStorage : public ModuleDependencyInfoStorageBase {
362+
class SwiftBinaryModuleDependencyStorage
363+
: public ModuleDependencyInfoStorageBase {
327364
public:
328-
SwiftBinaryModuleDependencyStorage(const std::string &compiledModulePath,
329-
const std::string &moduleDocPath,
330-
const std::string &sourceInfoPath,
331-
const std::vector<std::string> &moduleImports,
332-
const std::vector<std::string> &optionalModuleImports,
333-
const std::string &headerImport,
334-
const bool isFramework,
335-
const std::string &moduleCacheKey)
365+
SwiftBinaryModuleDependencyStorage(
366+
const std::string &compiledModulePath, const std::string &moduleDocPath,
367+
const std::string &sourceInfoPath,
368+
const std::vector<ScannerImportStatementInfo> &moduleImports,
369+
const std::vector<ScannerImportStatementInfo> &optionalModuleImports,
370+
const std::string &headerImport, const bool isFramework,
371+
const std::string &moduleCacheKey)
336372
: ModuleDependencyInfoStorageBase(ModuleDependencyKind::SwiftBinary,
337-
moduleImports, optionalModuleImports, moduleCacheKey),
373+
moduleImports, optionalModuleImports,
374+
moduleCacheKey),
338375
compiledModulePath(compiledModulePath), moduleDocPath(moduleDocPath),
339376
sourceInfoPath(sourceInfoPath), headerImport(headerImport),
340377
isFramework(isFramework) {}
@@ -520,8 +557,8 @@ class ModuleDependencyInfo {
520557
const std::string &compiledModulePath,
521558
const std::string &moduleDocPath,
522559
const std::string &sourceInfoPath,
523-
const std::vector<std::string> &moduleImports,
524-
const std::vector<std::string> &optionalModuleImports,
560+
const std::vector<ScannerImportStatementInfo> &moduleImports,
561+
const std::vector<ScannerImportStatementInfo> &optionalModuleImports,
525562
const std::string &headerImport,
526563
bool isFramework, const std::string &moduleCacheKey) {
527564
return ModuleDependencyInfo(
@@ -572,12 +609,12 @@ class ModuleDependencyInfo {
572609
}
573610

574611
/// Retrieve the module-level imports.
575-
ArrayRef<std::string> getModuleImports() const {
612+
ArrayRef<ScannerImportStatementInfo> getModuleImports() const {
576613
return storage->moduleImports;
577614
}
578615

579616
/// Retrieve the module-level optional imports.
580-
ArrayRef<std::string> getOptionalModuleImports() const {
617+
ArrayRef<ScannerImportStatementInfo> getOptionalModuleImports() const {
581618
return storage->optionalModuleImports;
582619
}
583620

@@ -754,31 +791,24 @@ class ModuleDependencyInfo {
754791
void addOptionalModuleImport(StringRef module,
755792
llvm::StringSet<> *alreadyAddedModules = nullptr);
756793

794+
/// Add all of the module imports in the given source
795+
/// file to the set of module imports.
796+
void addModuleImports(const SourceFile &sourceFile,
797+
llvm::StringSet<> &alreadyAddedModules,
798+
const SourceManager *sourceManager);
757799

758800
/// Add a dependency on the given module, if it was not already in the set.
759-
void addModuleImport(StringRef module,
760-
llvm::StringSet<> *alreadyAddedModules = nullptr);
801+
void addModuleImport(ImportPath::Module module,
802+
llvm::StringSet<> *alreadyAddedModules = nullptr,
803+
const SourceManager *sourceManager = nullptr,
804+
SourceLoc sourceLocation = SourceLoc());
761805

762806
/// Add a dependency on the given module, if it was not already in the set.
763-
void addModuleImport(ImportPath::Module module,
764-
llvm::StringSet<> *alreadyAddedModules = nullptr) {
765-
std::string ImportedModuleName = module.front().Item.str().str();
766-
auto submodulePath = module.getSubmodulePath();
767-
if (submodulePath.size() > 0 && !submodulePath[0].Item.empty()) {
768-
auto submoduleComponent = submodulePath[0];
769-
// Special case: a submodule named "Foo.Private" can be moved to a top-level
770-
// module named "Foo_Private". ClangImporter has special support for this.
771-
if (submoduleComponent.Item.str() == "Private")
772-
addOptionalModuleImport(ImportedModuleName + "_Private", alreadyAddedModules);
773-
}
774-
775-
addModuleImport(ImportedModuleName, alreadyAddedModules);
776-
}
807+
void addModuleImport(StringRef module,
808+
llvm::StringSet<> *alreadyAddedModules = nullptr,
809+
const SourceManager *sourceManager = nullptr,
810+
SourceLoc sourceLocation = SourceLoc());
777811

778-
/// Add all of the module imports in the given source
779-
/// file to the set of module imports.
780-
void addModuleImport(const SourceFile &sf,
781-
llvm::StringSet<> &alreadyAddedModules);
782812
/// Add a kind-qualified module dependency ID to the set of
783813
/// module dependencies.
784814
void addModuleDependency(ModuleDependencyID dependencyID);

include/swift/DependencyScan/DependencyScanImpl.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
namespace swift {
2222
namespace dependencies {
2323
class DependencyScanningTool;
24-
}
24+
} // namespace dependencies
2525
} // namespace swift
2626

2727
struct swiftscan_dependency_graph_s {
@@ -212,7 +212,13 @@ struct swiftscan_scan_invocation_s {
212212
struct swiftscan_diagnostic_info_s {
213213
swiftscan_string_ref_t message;
214214
swiftscan_diagnostic_severity_t severity;
215-
// TODO: SourceLoc
215+
swiftscan_source_location_t source_location;
216+
};
217+
218+
struct swiftscan_source_location_s {
219+
swiftscan_string_ref_t buffer_identifier;
220+
uint32_t line_number;
221+
uint32_t column_number;
216222
};
217223

218224
#endif // SWIFT_C_DEPENDENCY_SCAN_IMPL_H

include/swift/DependencyScan/DependencyScanningTool.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@ class DependencyScanDiagnosticCollector : public DiagnosticConsumer {
3737
struct ScannerDiagnosticInfo {
3838
std::string Message;
3939
llvm::SourceMgr::DiagKind Severity;
40+
std::optional<ScannerImportStatementInfo::ImportDiagnosticLocationInfo> ImportLocation;
4041
};
42+
std::vector<ScannerDiagnosticInfo> Diagnostics;
4143

4244
void handleDiagnostic(SourceManager &SM, const DiagnosticInfo &Info) override;
43-
std::vector<ScannerDiagnosticInfo> Diagnostics;
4445

4546
protected:
4647
virtual void addDiagnostic(SourceManager &SM, const DiagnosticInfo &Info);

lib/AST/ModuleDependencies.cpp

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -121,16 +121,67 @@ void ModuleDependencyInfo::addOptionalModuleImport(
121121
}
122122

123123
void ModuleDependencyInfo::addModuleImport(
124-
StringRef module, llvm::StringSet<> *alreadyAddedModules) {
125-
if (!alreadyAddedModules || alreadyAddedModules->insert(module).second)
126-
storage->moduleImports.push_back(module.str());
124+
StringRef module, llvm::StringSet<> *alreadyAddedModules,
125+
const SourceManager *sourceManager, SourceLoc sourceLocation) {
126+
auto scannerImportLocToDiagnosticLocInfo =
127+
[&sourceManager](SourceLoc sourceLocation) {
128+
auto lineAndColumnNumbers =
129+
sourceManager->getLineAndColumnInBuffer(sourceLocation);
130+
return ScannerImportStatementInfo::ImportDiagnosticLocationInfo(
131+
sourceManager->getDisplayNameForLoc(sourceLocation).str(),
132+
lineAndColumnNumbers.first, lineAndColumnNumbers.second);
133+
};
134+
bool validSourceLocation = sourceManager && sourceLocation.isValid() &&
135+
sourceManager->isOwning(sourceLocation);
136+
137+
if (alreadyAddedModules && alreadyAddedModules->contains(module)) {
138+
if (validSourceLocation) {
139+
// Find a prior import of this module and add import location
140+
for (auto &existingImport : storage->moduleImports) {
141+
if (existingImport.importIdentifier == module) {
142+
existingImport.addImportLocation(
143+
scannerImportLocToDiagnosticLocInfo(sourceLocation));
144+
break;
145+
}
146+
}
147+
}
148+
} else {
149+
if (alreadyAddedModules)
150+
alreadyAddedModules->insert(module);
151+
152+
if (validSourceLocation)
153+
storage->moduleImports.push_back(ScannerImportStatementInfo(
154+
module.str(), scannerImportLocToDiagnosticLocInfo(sourceLocation)));
155+
else
156+
storage->moduleImports.push_back(
157+
ScannerImportStatementInfo(module.str()));
158+
}
127159
}
128160

129161
void ModuleDependencyInfo::addModuleImport(
130-
const SourceFile &sf, llvm::StringSet<> &alreadyAddedModules) {
162+
ImportPath::Module module, llvm::StringSet<> *alreadyAddedModules,
163+
const SourceManager *sourceManager, SourceLoc sourceLocation) {
164+
std::string ImportedModuleName = module.front().Item.str().str();
165+
auto submodulePath = module.getSubmodulePath();
166+
if (submodulePath.size() > 0 && !submodulePath[0].Item.empty()) {
167+
auto submoduleComponent = submodulePath[0];
168+
// Special case: a submodule named "Foo.Private" can be moved to a top-level
169+
// module named "Foo_Private". ClangImporter has special support for this.
170+
if (submoduleComponent.Item.str() == "Private")
171+
addOptionalModuleImport(ImportedModuleName + "_Private",
172+
alreadyAddedModules);
173+
}
174+
175+
addModuleImport(ImportedModuleName, alreadyAddedModules,
176+
sourceManager, sourceLocation);
177+
}
178+
179+
void ModuleDependencyInfo::addModuleImports(
180+
const SourceFile &sourceFile, llvm::StringSet<> &alreadyAddedModules,
181+
const SourceManager *sourceManager) {
131182
// Add all of the module dependencies.
132183
SmallVector<Decl *, 32> decls;
133-
sf.getTopLevelDecls(decls);
184+
sourceFile.getTopLevelDecls(decls);
134185
for (auto decl : decls) {
135186
auto importDecl = dyn_cast<ImportDecl>(decl);
136187
if (!importDecl)
@@ -149,10 +200,12 @@ void ModuleDependencyInfo::addModuleImport(
149200

150201
// Ignore/diagnose tautological imports akin to import resolution
151202
if (!swift::dependencies::checkImportNotTautological(
152-
realPath, importDecl->getLoc(), sf, importDecl->isExported()))
203+
realPath, importDecl->getLoc(), sourceFile,
204+
importDecl->isExported()))
153205
continue;
154206

155-
addModuleImport(realPath, &alreadyAddedModules);
207+
addModuleImport(realPath, &alreadyAddedModules,
208+
sourceManager, importDecl->getLoc());
156209

157210
// Additionally, keep track of which dependencies of a Source
158211
// module are `@Testable`.
@@ -161,7 +214,7 @@ void ModuleDependencyInfo::addModuleImport(
161214
addTestableImport(realPath);
162215
}
163216

164-
auto fileName = sf.getFilename();
217+
auto fileName = sourceFile.getFilename();
165218
if (fileName.empty())
166219
return;
167220

0 commit comments

Comments
 (0)