From 17c7bec479279cb1323cf86d6fefa47ee1da77c5 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 21 Aug 2026 09:51:37 +0000 Subject: [PATCH] [SwiftExtract] Add OpaquePointer to the known Swift stdlib types OpaquePointer was the only member of the pointer family missing from the known-modules table, so any API using it was dropped with an unresolved type warning. Add it to the fake Swift module source and the known-type kind enums, and keep it unbridged (nil) in the JNI type translator like the rest of the pointer family. --- .../JNI/JNIJavaTypeTranslator.swift | 3 +++ .../SwiftTypes/SwiftKnownModules.swift | 2 ++ .../SwiftTypes/SwiftKnownTypeDecls.swift | 4 +++ .../AnalysisResultTests.swift | 25 +++++++++++++++++++ .../SwiftKnownModuleTests.swift | 1 + 5 files changed, 35 insertions(+) diff --git a/Sources/JExtractSwiftLib/JNI/JNIJavaTypeTranslator.swift b/Sources/JExtractSwiftLib/JNI/JNIJavaTypeTranslator.swift index ea7f68317..2019ba48a 100644 --- a/Sources/JExtractSwiftLib/JNI/JNIJavaTypeTranslator.swift +++ b/Sources/JExtractSwiftLib/JNI/JNIJavaTypeTranslator.swift @@ -46,6 +46,7 @@ enum JNIJavaTypeTranslator { .unsafePointer, .unsafeMutablePointer, .unsafeRawBufferPointer, .unsafeMutableRawBufferPointer, .unsafeBufferPointer, .unsafeMutableBufferPointer, + .opaquePointer, .optional, .foundationData, .foundationDataProtocol, .essentialsData, .essentialsDataProtocol, @@ -73,6 +74,7 @@ enum JNIJavaTypeTranslator { .unsafePointer, .unsafeMutablePointer, .unsafeRawBufferPointer, .unsafeMutableRawBufferPointer, .unsafeBufferPointer, .unsafeMutableBufferPointer, + .opaquePointer, .optional, .foundationData, .foundationDataProtocol, .essentialsData, .essentialsDataProtocol, @@ -100,6 +102,7 @@ enum JNIJavaTypeTranslator { .unsafePointer, .unsafeMutablePointer, .unsafeRawBufferPointer, .unsafeMutableRawBufferPointer, .unsafeBufferPointer, .unsafeMutableBufferPointer, + .opaquePointer, .optional, .foundationData, .foundationDataProtocol, .essentialsData, .essentialsDataProtocol, diff --git a/Sources/SwiftExtract/SwiftTypes/SwiftKnownModules.swift b/Sources/SwiftExtract/SwiftTypes/SwiftKnownModules.swift index 47b7b342a..31ad2add2 100644 --- a/Sources/SwiftExtract/SwiftTypes/SwiftKnownModules.swift +++ b/Sources/SwiftExtract/SwiftTypes/SwiftKnownModules.swift @@ -94,6 +94,8 @@ private let swiftSourceFile: SourceFileSyntax = """ public struct UnsafeBufferPointer {} public struct UnsafeMutableBufferPointer {} + public struct OpaquePointer {} + public struct Optional {} public struct Array {} diff --git a/Sources/SwiftExtract/SwiftTypes/SwiftKnownTypeDecls.swift b/Sources/SwiftExtract/SwiftTypes/SwiftKnownTypeDecls.swift index 53ee8101a..bcc167f03 100644 --- a/Sources/SwiftExtract/SwiftTypes/SwiftKnownTypeDecls.swift +++ b/Sources/SwiftExtract/SwiftTypes/SwiftKnownTypeDecls.swift @@ -36,6 +36,7 @@ public enum SwiftKnownType: Equatable { case unsafeMutablePointer(_ pointee: SwiftType) case unsafeBufferPointer(_ element: SwiftType) case unsafeMutableBufferPointer(_ element: SwiftType) + case opaquePointer case optional(_ wrapped: SwiftType) case void case string @@ -86,6 +87,7 @@ public enum SwiftKnownType: Equatable { case .unsafeMutableBufferPointer: guard let arg = genericArguments?.first else { return nil } self = .unsafeMutableBufferPointer(arg) + case .opaquePointer: self = .opaquePointer case .optional: guard let arg = genericArguments?.first else { return nil } self = .optional(arg) @@ -136,6 +138,7 @@ public enum SwiftKnownType: Equatable { case .unsafeMutablePointer: .unsafeMutablePointer case .unsafeBufferPointer: .unsafeBufferPointer case .unsafeMutableBufferPointer: .unsafeMutableBufferPointer + case .opaquePointer: .opaquePointer case .optional: .optional case .void: .void case .string: .string @@ -179,6 +182,7 @@ public enum SwiftKnownTypeDeclKind: String, Hashable { case unsafeMutablePointer = "Swift.UnsafeMutablePointer" case unsafeBufferPointer = "Swift.UnsafeBufferPointer" case unsafeMutableBufferPointer = "Swift.UnsafeMutableBufferPointer" + case opaquePointer = "Swift.OpaquePointer" case optional = "Swift.Optional" case void = "Swift.Void" case string = "Swift.String" diff --git a/Tests/SwiftExtractTests/AnalysisResultTests.swift b/Tests/SwiftExtractTests/AnalysisResultTests.swift index 2fc1abd25..fcb081a44 100644 --- a/Tests/SwiftExtractTests/AnalysisResultTests.swift +++ b/Tests/SwiftExtractTests/AnalysisResultTests.swift @@ -393,6 +393,31 @@ struct AnalysisResultSuite { #expect(unresolvable.functionSignature.thrownTypedError == nil) } + @Test + func opaquePointerIsAKnownSwiftType() throws { + let result = try analyze( + sources: [ + ( + "/fake/Source.swift", + """ + public func takePointer(_ pointer: OpaquePointer) {} + public func makePointer() -> OpaquePointer? { nil } + """ + ) + ], + moduleName: "Aquarium" + ) + + let byName = Dictionary(uniqueKeysWithValues: result.extractedGlobalFuncs.map { ($0.name, $0) }) + + let take = try #require(byName["takePointer"]) + let parameterType = try #require(take.functionSignature.parameters.first?.type) + #expect(parameterType.asNominalTypeDeclaration?.knownTypeKind == .opaquePointer) + + let make = try #require(byName["makePointer"]) + #expect(make.functionSignature.result.type.description == "OpaquePointer?") + } + @Test func typedThrowsOnInitializers() throws { let result = try analyze( diff --git a/Tests/SwiftExtractTests/SwiftKnownModuleTests.swift b/Tests/SwiftExtractTests/SwiftKnownModuleTests.swift index a1912cc2c..8bd938609 100644 --- a/Tests/SwiftExtractTests/SwiftKnownModuleTests.swift +++ b/Tests/SwiftExtractTests/SwiftKnownModuleTests.swift @@ -27,6 +27,7 @@ struct SwiftKnownModuleSuite { "Float", "Double", "Bool", "String", "Array", "Dictionary", "Set", "Optional", + "OpaquePointer", ]) func swiftModuleContains(_ typeName: String) throws { let table = SwiftKnownModule.swift.symbolTable