@@ -201,7 +201,7 @@ struct JavaToSwift: ParsableCommand {
201201 // Add the configuration for this module.
202202 translator. addConfiguration ( config, forSwiftModule: moduleName)
203203
204- // Load all of the requested classes.
204+ // Load all of the explicitly- requested classes.
205205 let classLoader = try JavaClass < ClassLoader > ( environment: environment)
206206 . getSystemClassLoader ( ) !
207207 var javaClasses : [ JavaClass < JavaObject > ] = [ ]
@@ -211,29 +211,50 @@ struct JavaToSwift: ParsableCommand {
211211 continue
212212 }
213213
214+ // Add this class to the list of classes we'll translate.
214215 javaClasses. append ( javaClass)
216+ }
217+
218+ // Find all of the nested classes for each class, adding them to the list
219+ // of classes to be translated if they were already specified.
220+ var allClassesToVisit = javaClasses
221+ var currentClassIndex : Int = 0
222+ while currentClassIndex < allClassesToVisit. count {
223+ defer {
224+ currentClassIndex += 1
225+ }
226+
227+ // Find all of the nested classes that weren't explicitly translated
228+ // already.
229+ let currentClass = allClassesToVisit [ currentClassIndex]
230+ let nestedClasses : [ JavaClass < JavaObject > ] = currentClass. getClasses ( ) . compactMap { nestedClass in
231+ guard let nestedClass else { return nil }
232+
233+ // If this is a local class, we're done.
234+ let javaClassName = nestedClass. getName ( )
235+ if javaClassName. isLocalJavaClass {
236+ return nil
237+ }
215238
216- // Replace any $'s within the Java class name (which separate nested
217- // classes) with .'s (which represent nesting in Swift).
218- let translatedSwiftName = swiftName. replacing ( " $ " , with: " . " )
219-
220- // Note that we will be translating this Java class, so it is a known class.
221- translator. translatedClasses [ javaClassName] = ( translatedSwiftName, nil , true )
222-
223- var classes : [ JavaClass < JavaObject > ? ] = javaClass. getClasses ( )
224-
225- // Go through all subclasses to find all of the classes to translate
226- while let internalClass = classes. popLast ( ) {
227- if let internalClass {
228- let ( javaName, swiftName) = names ( from: internalClass. getName ( ) )
229- // If we have already been through this class, don't go through it again
230- guard translator. translatedClasses [ javaName] == nil else { continue }
231- let currentClassName = swiftName
232- let currentSanitizedClassName = currentClassName. replacing ( " $ " , with: " . " )
233- classes. append ( contentsOf: internalClass. getClasses ( ) )
234- translator. translatedClasses [ javaName] = ( currentSanitizedClassName, nil , true )
239+ // If this class has been explicitly mentioned, we're done.
240+ if translator. translatedClasses [ javaClassName] != nil {
241+ return nil
235242 }
243+
244+ // Record this as a translated class.
245+ let swiftName = javaClassName. defaultSwiftNameForJavaClass
246+ translator. translatedClasses [ javaClassName] = ( swiftName, nil , true )
247+ return nestedClass
236248 }
249+
250+ // If there were no new nested classes, there's nothing to do.
251+ if nestedClasses. isEmpty {
252+ continue
253+ }
254+
255+ // Record all of the nested classes that we will visit.
256+ translator. nestedClasses [ currentClass. getName ( ) ] = nestedClasses
257+ allClassesToVisit. append ( contentsOf: nestedClasses)
237258 }
238259
239260 // Translate all of the Java classes into Swift classes.
@@ -276,7 +297,7 @@ struct JavaToSwift: ParsableCommand {
276297 javaClassName = javaClassNameOpt
277298 }
278299
279- return ( javaClassName, swiftName)
300+ return ( javaClassName, swiftName. javaClassNameToCanonicalName )
280301 }
281302
282303 mutating func writeContents( _ contents: String , to filename: String , description: String ) throws {
@@ -317,12 +338,9 @@ struct JavaToSwift: ParsableCommand {
317338 continue
318339 }
319340
320- // If any of the segments of the Java name start with a number, it's a
321- // local class that cannot be mapped into Swift.
322- for segment in entry. getName ( ) . split ( separator: " $ " ) {
323- if let firstChar = segment. first, firstChar. isNumber {
324- continue
325- }
341+ // If this is a local class, it cannot be mapped into Swift.
342+ if entry. getName ( ) . isLocalJavaClass {
343+ continue
326344 }
327345
328346 let javaCanonicalName = String ( entry. getName ( ) . replacing ( " / " , with: " . " )
@@ -365,10 +383,10 @@ extension String {
365383 fileprivate var defaultSwiftNameForJavaClass : String {
366384 if let dotLoc = lastIndex ( of: " . " ) {
367385 let afterDot = index ( after: dotLoc)
368- return String ( self [ afterDot... ] )
386+ return String ( self [ afterDot... ] ) . javaClassNameToCanonicalName
369387 }
370388
371- return self
389+ return javaClassNameToCanonicalName
372390 }
373391}
374392
@@ -382,3 +400,22 @@ extension JavaClass<ClassLoader> {
382400 @JavaStaticMethod
383401 public func getSystemClassLoader( ) -> ClassLoader ?
384402}
403+
404+ extension String {
405+ /// Replace all of the $'s for nested names with "." to turn a Java class
406+ /// name into a Java canonical class name,
407+ fileprivate var javaClassNameToCanonicalName : String {
408+ return replacing ( " $ " , with: " . " )
409+ }
410+
411+ /// Whether this is the name of an anonymous class.
412+ fileprivate var isLocalJavaClass : Bool {
413+ for segment in split ( separator: " $ " ) {
414+ if let firstChar = segment. first, firstChar. isNumber {
415+ return true
416+ }
417+ }
418+
419+ return false
420+ }
421+ }
0 commit comments