Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Sources/SwiftJava/String+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
import Foundation

extension String {
/// For a String that's of the form java.util.Vector, return the "Vector"
/// part.
/// For a String that's of the form java.util.Vector, return the "Vector" part.
package var defaultSwiftNameForJavaClass: String {
if let dotLoc = lastIndex(of: ".") {
let afterDot = index(after: dotLoc)
Expand Down
27 changes: 20 additions & 7 deletions Sources/SwiftJavaTool/Commands/WrapJavaCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -180,28 +180,39 @@ extension SwiftJava.WrapJavaCommand {
// of classes to be translated if they were already specified.
var allClassesToVisit = javaClasses
var currentClassIndex: Int = 0
while currentClassIndex < allClassesToVisit.count {
outerClassLoop: while currentClassIndex < allClassesToVisit.count {
defer {
currentClassIndex += 1
}

// The current class we're in.
// The current top-level class we're in.
let currentClass = allClassesToVisit[currentClassIndex]
let currentClassName = currentClass.getName()
guard let currentSwiftName = translator.translatedClasses[currentClass.getName()]?.swiftType else {
continue
}

// Find all of the nested classes that weren't explicitly translated
// already.
let nestedClasses: [JavaClass<JavaObject>] = currentClass.getClasses().compactMap { nestedClass in
guard let nestedClass else { return nil }
// Find all of the nested classes that weren't explicitly translated already.
let nestedAndSuperclassNestedClasses = currentClass.getClasses() // watch out, this includes nested types from superclasses
let nestedClasses: [JavaClass<JavaObject>] = nestedAndSuperclassNestedClasses.compactMap { nestedClass in
guard let nestedClass else {
return nil
}

// If this is a local class, we're done.
let javaClassName = nestedClass.getName()
if javaClassName.isLocalJavaClass {
return nil
}

// We only want to visit and import types which are explicitly inside this decl,
// and NOT any of the types contained in the super classes. That would violate our "current class"
// nesting, because those are *actually* nested in the other class, not "the current one" (i.e. in a super class).
guard javaClassName.hasPrefix(currentClassName) else {
log.trace("Skip super-class nested class '\(javaClassName)', is not member of \(currentClassName). Will be visited independently.")
return nil
}

// If we have an inclusive filter, import only types from it
for include in config.filterInclude ?? [] {
guard javaClassName.starts(with: include) else {
Expand All @@ -227,7 +238,9 @@ extension SwiftJava.WrapJavaCommand {
.defaultSwiftNameForJavaClass

let swiftName = "\(currentSwiftName).\(swiftUnqualifiedName)"
translator.translatedClasses[javaClassName] = SwiftTypeName(module: nil, name: swiftName)
let translatedSwiftName = SwiftTypeName(module: nil, name: swiftName)
translator.translatedClasses[javaClassName] = translatedSwiftName
log.debug("Record translated Java class '\(javaClassName)' -> \(translatedSwiftName)")
return nestedClass
}

Expand Down
12 changes: 4 additions & 8 deletions Sources/SwiftJavaToolLib/JavaTranslator+Validation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ package extension JavaTranslator {
package var description: String {
switch self {
case .multipleClassesMappedToSameName(let swiftToJavaMapping):
"""
The following Java classes were mapped to the same Swift type name:
\(swiftToJavaMapping.map(mappingDescription(mapping:)).joined(separator: "\n"))
"""
"""
The following Java classes were mapped to the same Swift type name:
\(swiftToJavaMapping.map(mappingDescription(mapping:)).joined(separator: "\n"))
"""
}
}

Expand All @@ -72,10 +72,6 @@ package extension JavaTranslator {
}
}
func validateClassConfiguration() throws(ValidationError) {
// for a in translatedClasses {
// print("MAPPING = \(a.key) -> \(a.value.swiftModule?.escapedSwiftName ?? "").\(a.value.swiftType.escapedSwiftName)")
// }

// Group all classes by swift name
let groupedDictionary: [SwiftTypeName: [(JavaFullyQualifiedTypeName, SwiftTypeName)]] = Dictionary(grouping: translatedClasses, by: {
// SwiftTypeName(swiftType: $0.value.swiftType, swiftModule: $0.value.swiftModule)
Expand Down
39 changes: 39 additions & 0 deletions Tests/SwiftJavaToolLibTests/WrapJavaTests/BasicWrapJavaTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,43 @@ final class BasicWrapJavaTests: XCTestCase {
)
}

func test_wrapJava_doNotDupeImportNestedClassesFromSuperclassAutomatically() async throws {
let classpathURL = try await compileJava(
"""
package com.example;

class SuperClass {
class SuperNested {}
}

class ExampleSimpleClass {
class SimpleNested {}
}
""")

try assertWrapJavaOutput(
javaClassNames: [
"com.example.SuperClass",
"com.example.SuperClass$SuperNested",
"com.example.ExampleSimpleClass",
],
classpath: [classpathURL],
expectedChunks: [
"""
@JavaClass("com.example.SuperClass")
open class SuperClass: JavaObject {
""",
// FIXME: the mapping configuration could be used to nest this properly but today we don't automatically?
"""
@JavaClass("com.example.SuperClass$SuperNested")
open class SuperNested: JavaObject {
""",
"""
@JavaClass("com.example.SuperClass")
open class SuperClass: JavaObject {
""",
]
)
}

}
Loading