Skip to content

Commit 3340b24

Browse files
committed
[Explicit Module Builds] Add support for libSwiftScan API to query source import details
1 parent 8594e08 commit 3340b24

File tree

6 files changed

+203
-3
lines changed

6 files changed

+203
-3
lines changed

Sources/CSwiftScan/include/swiftscan_header.h

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
#include <stdint.h>
1919

2020
#define SWIFTSCAN_VERSION_MAJOR 2
21-
#define SWIFTSCAN_VERSION_MINOR 1
21+
#define SWIFTSCAN_VERSION_MINOR 2
2222

2323
//=== Public Scanner Data Types -------------------------------------------===//
2424

@@ -43,6 +43,7 @@ typedef struct swiftscan_dependency_info_s *swiftscan_dependency_info_t;
4343
typedef struct swiftscan_link_library_info_s *swiftscan_link_library_info_t;
4444
typedef struct swiftscan_dependency_graph_s *swiftscan_dependency_graph_t;
4545
typedef struct swiftscan_import_set_s *swiftscan_import_set_t;
46+
typedef struct swiftscan_import_info_s *swiftscan_import_info_t;
4647
typedef struct swiftscan_diagnostic_info_s *swiftscan_diagnostic_info_t;
4748
typedef struct swiftscan_source_location_s *swiftscan_source_location_t;
4849

@@ -52,6 +53,13 @@ typedef enum {
5253
SWIFTSCAN_DIAGNOSTIC_SEVERITY_NOTE = 2,
5354
SWIFTSCAN_DIAGNOSTIC_SEVERITY_REMARK = 3
5455
} swiftscan_diagnostic_severity_t;
56+
typedef enum {
57+
SWIFTSCAN_ACCESS_LEVEL_PRIVATE = 0,
58+
SWIFTSCAN_ACCESS_LEVEL_FILEPRIVATE = 1,
59+
SWIFTSCAN_ACCESS_LEVEL_INTERNAL = 2,
60+
SWIFTSCAN_ACCESS_LEVEL_PACKAGE = 3,
61+
SWIFTSCAN_ACCESS_LEVEL_PUBLIC = 4
62+
} swiftscan_access_level_t;
5563
typedef struct {
5664
swiftscan_diagnostic_info_t *diagnostics;
5765
size_t count;
@@ -64,6 +72,14 @@ typedef struct {
6472
swiftscan_link_library_info_t *link_libraries;
6573
size_t count;
6674
} swiftscan_link_library_set_t;
75+
typedef struct {
76+
swiftscan_import_info_t *imports;
77+
size_t count;
78+
} swiftscan_import_info_set_t;
79+
typedef struct {
80+
swiftscan_source_location_t *source_locations;
81+
size_t count;
82+
} swiftscan_source_location_set_t;
6783

6884
//=== Scanner Invocation Specification ------------------------------------===//
6985

@@ -104,6 +120,8 @@ typedef struct {
104120
(*swiftscan_module_info_get_direct_dependencies)(swiftscan_dependency_info_t);
105121
swiftscan_link_library_set_t *
106122
(*swiftscan_module_info_get_link_libraries)(swiftscan_dependency_graph_t);
123+
swiftscan_import_info_set_t *
124+
(*swiftscan_module_info_get_imports)(swiftscan_dependency_graph_t);
107125
swiftscan_module_details_t
108126
(*swiftscan_module_info_get_details)(swiftscan_dependency_info_t);
109127

@@ -115,6 +133,14 @@ typedef struct {
115133
bool
116134
(*swiftscan_link_library_info_get_should_force_load)(swiftscan_link_library_info_t);
117135

136+
//=== Import Details Functions -------------------------------------------===//
137+
swiftscan_source_location_set_t *
138+
(*swiftscan_import_info_get_source_locations)(swiftscan_import_info_t info);
139+
swiftscan_string_ref_t
140+
(*swiftscan_import_info_get_identifier)(swiftscan_import_info_t info);
141+
swiftscan_access_level_t
142+
(*swiftscan_import_info_get_access_level)(swiftscan_import_info_t info);
143+
118144
//=== Dependency Module Info Details Functions ----------------------------===//
119145
swiftscan_dependency_info_kind_t
120146
(*swiftscan_module_detail_get_kind)(swiftscan_module_details_t);

Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyGraph.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,29 @@ public struct LinkLibraryInfo: Codable, Hashable {
9090
public var shouldForceLoad: Bool
9191
}
9292

93+
/// Source 'import'
94+
public struct ImportInfo : Codable, Hashable {
95+
public enum ImportAccessLevel : Codable, Hashable {
96+
case Private
97+
case FilePrivate
98+
case Internal
99+
case Package
100+
case Public
101+
}
102+
103+
public var importIdentifier: String
104+
public var accessLevel: ImportAccessLevel
105+
public var sourceLocations: [ScannerDiagnosticSourceLocation]
106+
107+
@_spi(Testing) public init(importIdentifier: String,
108+
accessLevel: ImportAccessLevel,
109+
sourceLocations: [ScannerDiagnosticSourceLocation]) {
110+
self.importIdentifier = importIdentifier
111+
self.accessLevel = accessLevel
112+
self.sourceLocations = sourceLocations
113+
}
114+
}
115+
93116
/// Details specific to Swift modules.
94117
public struct SwiftModuleDetails: Codable, Hashable {
95118
/// The module interface from which this module was built, if any.
@@ -195,6 +218,9 @@ public struct ModuleInfo: Codable, Hashable {
195218
/// The set of libraries that need to be linked
196219
public var linkLibraries: [LinkLibraryInfo]?
197220

221+
/// The set of import details of this module
222+
public var importInfos: [ImportInfo]?
223+
198224
/// Specific details of a particular kind of module.
199225
public var details: Details
200226

@@ -215,11 +241,13 @@ public struct ModuleInfo: Codable, Hashable {
215241
sourceFiles: [String]?,
216242
directDependencies: [ModuleDependencyId]?,
217243
linkLibraries: [LinkLibraryInfo]?,
244+
importInfos: [ImportInfo]?,
218245
details: Details) {
219246
self.modulePath = modulePath
220247
self.sourceFiles = sourceFiles
221248
self.directDependencies = directDependencies
222249
self.linkLibraries = linkLibraries
250+
self.importInfos = importInfos
223251
self.details = details
224252
}
225253
}

Sources/SwiftDriver/ExplicitModuleBuilds/InterModuleDependencies/InterModuleDependencyOracle.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,13 @@ public class InterModuleDependencyOracle {
137137
return swiftScan.supportsLinkLibraries
138138
}
139139

140+
@_spi(Testing) public func supportsImportInfos() throws -> Bool {
141+
guard let swiftScan = swiftScanLibInstance else {
142+
fatalError("Attempting to query supported scanner API with no scanner instance.")
143+
}
144+
return swiftScan.supportsImportInfos
145+
}
146+
140147
@_spi(Testing) public func supportsSeparateImportOnlyDependencise() throws -> Bool {
141148
guard let swiftScan = swiftScanLibInstance else {
142149
fatalError("Attempting to query supported scanner API with no scanner instance.")

Sources/SwiftDriver/SwiftScan/DependencyGraphBuilder.swift

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,22 @@ private extension SwiftScan {
104104
}
105105
}
106106

107+
var importInfos: [ImportInfo] = []
108+
if supportsImportInfos {
109+
let importInfoSetRefOrNull = api.swiftscan_module_info_get_imports(moduleInfoRef)
110+
guard let importInfoSetRef = importInfoSetRefOrNull else {
111+
throw DependencyScanningError.missingField("dependency_graph.imports")
112+
}
113+
let importInfoRefArray = Array(UnsafeBufferPointer(start: importInfoSetRef.pointee.imports,
114+
count: Int(importInfoSetRef.pointee.count)))
115+
for importInfoRefOrNull in importInfoRefArray {
116+
guard let importInfoRef = importInfoRefOrNull else {
117+
throw DependencyScanningError.missingField("dependency_set_t.imports[_]")
118+
}
119+
importInfos.append(try constructImportInfo(from: importInfoRef))
120+
}
121+
}
122+
107123
guard let moduleDetailsRef = api.swiftscan_module_info_get_details(moduleInfoRef) else {
108124
throw DependencyScanningError.missingField("modules[\(moduleId)].details")
109125
}
@@ -113,6 +129,7 @@ private extension SwiftScan {
113129
return (moduleId, ModuleInfo(modulePath: modulePath, sourceFiles: sourceFiles,
114130
directDependencies: directDependencies,
115131
linkLibraries: linkLibraries,
132+
importInfos: importInfos,
116133
details: details))
117134
}
118135

@@ -122,6 +139,41 @@ private extension SwiftScan {
122139
shouldForceLoad: api.swiftscan_link_library_info_get_should_force_load(linkLibraryInfoRef))
123140
}
124141

142+
func constructImportInfo(from importInfoRef: swiftscan_import_info_t) throws -> ImportInfo {
143+
var sourceLocations : [ScannerDiagnosticSourceLocation] = []
144+
145+
let sourceLocationsRefOrNull = api.swiftscan_import_info_get_source_locations(importInfoRef)
146+
guard let sourceLocationsRef = sourceLocationsRefOrNull else {
147+
throw DependencyScanningError.missingField("import_info.source_locations")
148+
}
149+
let sourceLocationsRefArray = Array(UnsafeBufferPointer(start: sourceLocationsRef.pointee.source_locations,
150+
count: Int(sourceLocationsRef.pointee.count)))
151+
for sourceLocationRefOrNull in sourceLocationsRefArray {
152+
guard let sourceLocationRef = sourceLocationRefOrNull else {
153+
throw DependencyScanningError.missingField("import_info.source_locations[_]")
154+
}
155+
sourceLocations.append(try constructSourceLocation(from: sourceLocationRef))
156+
}
157+
158+
let accessLevel = switch api.swiftscan_import_info_get_access_level(importInfoRef) {
159+
case SWIFTSCAN_ACCESS_LEVEL_PRIVATE: ImportInfo.ImportAccessLevel.Private
160+
case SWIFTSCAN_ACCESS_LEVEL_FILEPRIVATE: ImportInfo.ImportAccessLevel.FilePrivate
161+
case SWIFTSCAN_ACCESS_LEVEL_INTERNAL: ImportInfo.ImportAccessLevel.Internal
162+
case SWIFTSCAN_ACCESS_LEVEL_PACKAGE: ImportInfo.ImportAccessLevel.Package
163+
case SWIFTSCAN_ACCESS_LEVEL_PUBLIC: ImportInfo.ImportAccessLevel.Public
164+
default: ImportInfo.ImportAccessLevel.Public
165+
}
166+
167+
return ImportInfo(importIdentifier: try toSwiftString(api.swiftscan_import_info_get_identifier(importInfoRef)),
168+
accessLevel: accessLevel, sourceLocations: sourceLocations)
169+
}
170+
171+
func constructSourceLocation(from sourceLocationRef: swiftscan_source_location_t) throws -> ScannerDiagnosticSourceLocation {
172+
return ScannerDiagnosticSourceLocation(bufferIdentifier: try toSwiftString(api.swiftscan_source_location_get_buffer_identifier(sourceLocationRef)),
173+
lineNumber: Int(api.swiftscan_source_location_get_line_number(sourceLocationRef)),
174+
columnNumber: Int(api.swiftscan_source_location_get_column_number(sourceLocationRef)))
175+
}
176+
125177
/// From a reference to a binary-format module info details object info returned by libSwiftScan,
126178
/// construct an instance of an `ModuleInfo`.Details as used by the driver.
127179
/// The object returned by libSwiftScan is a union so ensure to execute dependency-specific queries.

Sources/SwiftDriver/SwiftScan/SwiftScan.swift

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,21 @@ public enum DependencyScanningError: LocalizedError, DiagnosticData, Equatable {
7272
}
7373
}
7474

75-
public struct ScannerDiagnosticSourceLocation : DiagnosticLocation {
75+
public struct ScannerDiagnosticSourceLocation : DiagnosticLocation, Codable, Hashable {
7676
public var description: String {
7777
return "\(bufferIdentifier):\(lineNumber):\(columnNumber)"
7878
}
7979
public let bufferIdentifier: String
8080
public let lineNumber: Int
8181
public let columnNumber: Int
82+
83+
@_spi(Testing) public init(bufferIdentifier: String,
84+
lineNumber: Int,
85+
columnNumber: Int) {
86+
self.bufferIdentifier = bufferIdentifier
87+
self.lineNumber = lineNumber
88+
self.columnNumber = columnNumber
89+
}
8290
}
8391

8492
public struct ScannerDiagnosticPayload {
@@ -318,6 +326,13 @@ private extension String {
318326
api.swiftscan_link_library_info_get_should_force_load != nil
319327
}
320328

329+
@_spi(Testing) public var supportsImportInfos : Bool {
330+
return api.swiftscan_module_info_get_imports != nil &&
331+
api.swiftscan_import_info_get_source_locations != nil &&
332+
api.swiftscan_import_info_get_identifier != nil &&
333+
api.swiftscan_import_info_get_access_level != nil
334+
}
335+
321336
internal func mapToDriverDiagnosticPayload(_ diagnosticSetRef: UnsafeMutablePointer<swiftscan_diagnostic_set_t>) throws -> [ScannerDiagnosticPayload] {
322337
var result: [ScannerDiagnosticPayload] = []
323338
let diagnosticRefArray = Array(UnsafeBufferPointer(start: diagnosticSetRef.pointee.diagnostics,
@@ -573,6 +588,11 @@ private extension swiftscan_functions_t {
573588
self.swiftscan_link_library_info_get_is_framework = loadOptional("swiftscan_link_library_info_get_is_framework")
574589
self.swiftscan_link_library_info_get_should_force_load = loadOptional("swiftscan_link_library_info_get_should_force_load")
575590

591+
self.swiftscan_module_info_get_imports = loadOptional("swiftscan_module_info_get_imports")
592+
self.swiftscan_import_info_get_source_locations = loadOptional("swiftscan_import_info_get_source_locations")
593+
self.swiftscan_import_info_get_identifier = loadOptional("swiftscan_import_info_get_identifier")
594+
self.swiftscan_import_info_get_access_level = loadOptional("swiftscan_import_info_get_access_level")
595+
576596
// Swift Overlay Dependencies
577597
self.swiftscan_swift_textual_detail_get_swift_overlay_dependencies =
578598
loadOptional("swiftscan_swift_textual_detail_get_swift_overlay_dependencies")

Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,74 @@ final class ExplicitModuleBuildTests: XCTestCase {
500500
}
501501
}
502502

503+
func testExplicitImportDetails() throws {
504+
try withTemporaryDirectory { path in
505+
let (_, _, toolchain, _) = try getDriverArtifactsForScanning()
506+
507+
let main = path.appending(component: "testExplicitLinkLibraries.swift")
508+
try localFileSystem.writeFileContents(main, bytes:
509+
"""
510+
public import C;
511+
internal import E;
512+
private import G;
513+
internal import C;
514+
"""
515+
)
516+
517+
let cHeadersPath: AbsolutePath =
518+
try testInputsPath.appending(component: "ExplicitModuleBuilds")
519+
.appending(component: "CHeaders")
520+
let swiftModuleInterfacesPath: AbsolutePath =
521+
try testInputsPath.appending(component: "ExplicitModuleBuilds")
522+
.appending(component: "Swift")
523+
let sdkArgumentsForTesting = (try? Driver.sdkArgumentsForTesting()) ?? []
524+
525+
let dependencyOracle = InterModuleDependencyOracle()
526+
let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib())
527+
try dependencyOracle.verifyOrCreateScannerInstance(swiftScanLibPath: scanLibPath)
528+
guard try dependencyOracle.supportsImportInfos() else {
529+
throw XCTSkip("libSwiftScan does not support import details reporting.")
530+
}
531+
532+
let args = ["swiftc",
533+
"-I", cHeadersPath.nativePathString(escaped: true),
534+
"-I", swiftModuleInterfacesPath.nativePathString(escaped: true),
535+
"-explicit-module-build",
536+
"-disable-implicit-concurrency-module-import",
537+
"-disable-implicit-string-processing-module-import",
538+
main.nativePathString(escaped: true)] + sdkArgumentsForTesting
539+
var driver = try Driver(args: args)
540+
let _ = try driver.planBuild()
541+
let dependencyGraph = try XCTUnwrap(driver.explicitDependencyBuildPlanner?.dependencyGraph)
542+
let mainModuleImports = try XCTUnwrap(dependencyGraph.mainModule.importInfos)
543+
XCTAssertEqual(mainModuleImports.count, 5)
544+
XCTAssertTrue(mainModuleImports.contains(ImportInfo(importIdentifier: "Swift",
545+
accessLevel: ImportInfo.ImportAccessLevel.Public,
546+
sourceLocations: [])))
547+
XCTAssertTrue(mainModuleImports.contains(ImportInfo(importIdentifier: "SwiftOnoneSupport",
548+
accessLevel: ImportInfo.ImportAccessLevel.Public,
549+
sourceLocations: [])))
550+
XCTAssertTrue(mainModuleImports.contains(ImportInfo(importIdentifier: "C",
551+
accessLevel: ImportInfo.ImportAccessLevel.Public,
552+
sourceLocations: [ScannerDiagnosticSourceLocation(bufferIdentifier: main.nativePathString(escaped: true),
553+
lineNumber: 1,
554+
columnNumber: 8),
555+
ScannerDiagnosticSourceLocation(bufferIdentifier: main.nativePathString(escaped: true),
556+
lineNumber: 4,
557+
columnNumber: 8)])))
558+
XCTAssertTrue(mainModuleImports.contains(ImportInfo(importIdentifier: "E",
559+
accessLevel: ImportInfo.ImportAccessLevel.Internal,
560+
sourceLocations: [ScannerDiagnosticSourceLocation(bufferIdentifier: main.nativePathString(escaped: true),
561+
lineNumber: 2,
562+
columnNumber: 8)])))
563+
XCTAssertTrue(mainModuleImports.contains(ImportInfo(importIdentifier: "G",
564+
accessLevel: ImportInfo.ImportAccessLevel.Private,
565+
sourceLocations: [ScannerDiagnosticSourceLocation(bufferIdentifier: main.nativePathString(escaped: true),
566+
lineNumber: 3,
567+
columnNumber: 8)])))
568+
}
569+
}
570+
503571
func testExplicitLinkLibraries() throws {
504572
try withTemporaryDirectory { path in
505573
let (_, _, toolchain, _) = try getDriverArtifactsForScanning()
@@ -521,7 +589,6 @@ final class ExplicitModuleBuildTests: XCTestCase {
521589
.appending(component: "Swift")
522590
let sdkArgumentsForTesting = (try? Driver.sdkArgumentsForTesting()) ?? []
523591

524-
// 2. Run a dependency scan to find the just-built module
525592
let dependencyOracle = InterModuleDependencyOracle()
526593
let scanLibPath = try XCTUnwrap(toolchain.lookupSwiftScanLib())
527594
try dependencyOracle.verifyOrCreateScannerInstance(swiftScanLibPath: scanLibPath)

0 commit comments

Comments
 (0)