@@ -26,7 +26,11 @@ final class Swift2JavaVisitor: SyntaxVisitor {
2626 /// store this along with type names as we import them.
2727 let targetJavaPackage : String
2828
29- var currentType : ImportedNominalType ? = nil
29+ /// Type context stack associated with the syntax.
30+ var typeContext : [ ( syntaxID: Syntax . ID , type: ImportedNominalType ) ] = [ ]
31+
32+ /// Innermost type context.
33+ var currentType : ImportedNominalType ? { typeContext. last? . type }
3034
3135 /// The current type name as a nested name like A.B.C.
3236 var currentTypeName : String ? { self . currentType? . swiftTypeName }
@@ -41,37 +45,50 @@ final class Swift2JavaVisitor: SyntaxVisitor {
4145 super. init ( viewMode: . all)
4246 }
4347
48+ /// Push specified type to the type context associated with the syntax.
49+ func pushTypeContext( syntax: some SyntaxProtocol , importedNominal: ImportedNominalType ) {
50+ typeContext. append ( ( syntax. id, importedNominal) )
51+ }
52+
53+ /// Pop type context if the current context is associated with the syntax.
54+ func popTypeContext( syntax: some SyntaxProtocol ) -> Bool {
55+ if typeContext. last? . syntaxID == syntax. id {
56+ typeContext. removeLast ( )
57+ return true
58+ } else {
59+ return false
60+ }
61+ }
62+
4463 override func visit( _ node: ClassDeclSyntax ) -> SyntaxVisitorContinueKind {
45- log. debug ( " Visit \( node. kind) : \( node) " )
64+ log. debug ( " Visit \( node. kind) : ' \( node. qualifiedNameForDebug ) ' " )
4665 guard let importedNominalType = translator. importedNominalType ( node) else {
4766 return . skipChildren
4867 }
4968
50- self . currentType = importedNominalType
69+ self . pushTypeContext ( syntax : node , importedNominal : importedNominalType)
5170 return . visitChildren
5271 }
5372
5473 override func visitPost( _ node: ClassDeclSyntax ) {
55- if currentType != nil {
74+ if self . popTypeContext ( syntax : node ) {
5675 log. debug ( " Completed import: \( node. kind) \( node. name) " )
57- self . currentType = nil
5876 }
5977 }
6078
6179 override func visit( _ node: StructDeclSyntax ) -> SyntaxVisitorContinueKind {
62- log. debug ( " Visit \( node. kind) : \( node) " )
80+ log. debug ( " Visit \( node. kind) : \( node. qualifiedNameForDebug ) " )
6381 guard let importedNominalType = translator. importedNominalType ( node) else {
6482 return . skipChildren
6583 }
6684
67- self . currentType = importedNominalType
85+ self . pushTypeContext ( syntax : node , importedNominal : importedNominalType)
6886 return . visitChildren
6987 }
7088
7189 override func visitPost( _ node: StructDeclSyntax ) {
72- if currentType != nil {
73- log. debug ( " Completed import: \( node. kind) \( node. name) " )
74- self . currentType = nil
90+ if self . popTypeContext ( syntax: node) {
91+ log. debug ( " Completed import: \( node. kind) \( node. qualifiedNameForDebug) " )
7592 }
7693 }
7794
@@ -84,13 +101,13 @@ final class Swift2JavaVisitor: SyntaxVisitor {
84101 return . skipChildren
85102 }
86103
87- self . currentType = importedNominalType
104+ self . pushTypeContext ( syntax : node , importedNominal : importedNominalType)
88105 return . visitChildren
89106 }
90107
91108 override func visitPost( _ node: ExtensionDeclSyntax ) {
92- if currentType != nil {
93- self . currentType = nil
109+ if self . popTypeContext ( syntax : node ) {
110+ log . debug ( " Completed import: \( node . kind ) \( node . qualifiedNameForDebug ) " )
94111 }
95112 }
96113
@@ -148,6 +165,10 @@ final class Swift2JavaVisitor: SyntaxVisitor {
148165 }
149166
150167 override func visit( _ node: VariableDeclSyntax ) -> SyntaxVisitorContinueKind {
168+ guard node. shouldImport ( log: log) else {
169+ return . skipChildren
170+ }
171+
151172 guard let binding = node. bindings. first else {
152173 return . skipChildren
153174 }
@@ -156,7 +177,7 @@ final class Swift2JavaVisitor: SyntaxVisitor {
156177
157178 // TODO: filter out kinds of variables we cannot import
158179
159- self . log. debug ( " Import variable: \( node. kind) \( fullName ) " )
180+ self . log. debug ( " Import variable: \( node. kind) ' \( node . qualifiedNameForDebug ) ' " )
160181
161182 let returnTy : TypeSyntax
162183 if let typeAnnotation = binding. typeAnnotation {
@@ -169,7 +190,7 @@ final class Swift2JavaVisitor: SyntaxVisitor {
169190 do {
170191 javaResultType = try cCompatibleType ( for: returnTy)
171192 } catch {
172- self . log. info ( " Unable to import variable \( node. debugDescription ) - \( error) " )
193+ log. info ( " Unable to import variable ' \( node. qualifiedNameForDebug ) ' - \( error) " )
173194 return . skipChildren
174195 }
175196
@@ -190,7 +211,7 @@ final class Swift2JavaVisitor: SyntaxVisitor {
190211 log. debug ( " Record variable in \( currentTypeName) " )
191212 translator. importedTypes [ currentTypeName] !. variables. append ( varDecl)
192213 } else {
193- fatalError ( " Global variables are not supported yet: \( node. debugDescription ) " )
214+ fatalError ( " Global variables are not supported yet: \( node. qualifiedNameForDebug ) " )
194215 }
195216
196217 return . skipChildren
@@ -206,7 +227,7 @@ final class Swift2JavaVisitor: SyntaxVisitor {
206227 return . skipChildren
207228 }
208229
209- self . log. debug ( " Import initializer: \( node. kind) \( currentType . javaType . description ) " )
230+ self . log. debug ( " Import initializer: \( node. kind) ' \( node . qualifiedNameForDebug ) ' " )
210231 let params : [ ImportedParam ]
211232 do {
212233 params = try node. signature. parameterClause. parameters. map { param in
@@ -247,37 +268,24 @@ final class Swift2JavaVisitor: SyntaxVisitor {
247268 }
248269}
249270
250- extension DeclGroupSyntax where Self: NamedDeclSyntax {
271+ extension DeclSyntaxProtocol where Self: WithModifiersSyntax & WithAttributesSyntax {
251272 func shouldImport( log: Logger ) -> Bool {
252- guard ( accessControlModifiers. first { $0. isPublic } ) != nil else {
253- log. trace ( " Cannot import \( self . name ) because: is not public" )
273+ guard accessControlModifiers. contains ( where : { $0. isPublic } ) else {
274+ log. trace ( " Skip import ' \( self . qualifiedNameForDebug ) ': not public" )
254275 return false
255276 }
256-
257- return true
258- }
259- }
260-
261- extension InitializerDeclSyntax {
262- func shouldImport( log: Logger ) -> Bool {
263- let isFailable = self . optionalMark != nil
264-
265- if isFailable {
266- log. warning ( " Skip importing failable initializer: \( self ) " )
277+ guard !attributes. contains ( where: { $0. isJava } ) else {
278+ log. trace ( " Skip import ' \( self . qualifiedNameForDebug) ': is Java " )
267279 return false
268280 }
269281
270- // Ok, import it
271- log. warning ( " Import initializer: \( self ) " )
272- return true
273- }
274- }
282+ if let node = self . as ( InitializerDeclSyntax . self) {
283+ let isFailable = node. optionalMark != nil
275284
276- extension FunctionDeclSyntax {
277- func shouldImport( log: Logger ) -> Bool {
278- guard ( accessControlModifiers. first { $0. isPublic } ) != nil else {
279- log. trace ( " Cannot import \( self . name) because: is not public " )
280- return false
285+ if isFailable {
286+ log. warning ( " Skip import ' \( self . qualifiedNameForDebug) ': failable initializer " )
287+ return false
288+ }
281289 }
282290
283291 return true
0 commit comments