@@ -26,7 +26,11 @@ final class Swift2JavaVisitor: SyntaxVisitor {
26
26
/// store this along with type names as we import them.
27
27
let targetJavaPackage : String
28
28
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 }
30
34
31
35
/// The current type name as a nested name like A.B.C.
32
36
var currentTypeName : String ? { self . currentType? . swiftTypeName }
@@ -41,37 +45,50 @@ final class Swift2JavaVisitor: SyntaxVisitor {
41
45
super. init ( viewMode: . all)
42
46
}
43
47
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
+
44
63
override func visit( _ node: ClassDeclSyntax ) -> SyntaxVisitorContinueKind {
45
- log. debug ( " Visit \( node. kind) : \( node) " )
64
+ log. debug ( " Visit \( node. kind) : ' \( node. qualifiedNameForDebug ) ' " )
46
65
guard let importedNominalType = translator. importedNominalType ( node) else {
47
66
return . skipChildren
48
67
}
49
68
50
- self . currentType = importedNominalType
69
+ self . pushTypeContext ( syntax : node , importedNominal : importedNominalType)
51
70
return . visitChildren
52
71
}
53
72
54
73
override func visitPost( _ node: ClassDeclSyntax ) {
55
- if currentType != nil {
74
+ if self . popTypeContext ( syntax : node ) {
56
75
log. debug ( " Completed import: \( node. kind) \( node. name) " )
57
- self . currentType = nil
58
76
}
59
77
}
60
78
61
79
override func visit( _ node: StructDeclSyntax ) -> SyntaxVisitorContinueKind {
62
- log. debug ( " Visit \( node. kind) : \( node) " )
80
+ log. debug ( " Visit \( node. kind) : \( node. qualifiedNameForDebug ) " )
63
81
guard let importedNominalType = translator. importedNominalType ( node) else {
64
82
return . skipChildren
65
83
}
66
84
67
- self . currentType = importedNominalType
85
+ self . pushTypeContext ( syntax : node , importedNominal : importedNominalType)
68
86
return . visitChildren
69
87
}
70
88
71
89
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) " )
75
92
}
76
93
}
77
94
@@ -84,13 +101,13 @@ final class Swift2JavaVisitor: SyntaxVisitor {
84
101
return . skipChildren
85
102
}
86
103
87
- self . currentType = importedNominalType
104
+ self . pushTypeContext ( syntax : node , importedNominal : importedNominalType)
88
105
return . visitChildren
89
106
}
90
107
91
108
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 ) " )
94
111
}
95
112
}
96
113
@@ -148,6 +165,10 @@ final class Swift2JavaVisitor: SyntaxVisitor {
148
165
}
149
166
150
167
override func visit( _ node: VariableDeclSyntax ) -> SyntaxVisitorContinueKind {
168
+ guard node. shouldImport ( log: log) else {
169
+ return . skipChildren
170
+ }
171
+
151
172
guard let binding = node. bindings. first else {
152
173
return . skipChildren
153
174
}
@@ -156,7 +177,7 @@ final class Swift2JavaVisitor: SyntaxVisitor {
156
177
157
178
// TODO: filter out kinds of variables we cannot import
158
179
159
- self . log. debug ( " Import variable: \( node. kind) \( fullName ) " )
180
+ self . log. debug ( " Import variable: \( node. kind) ' \( node . qualifiedNameForDebug ) ' " )
160
181
161
182
let returnTy : TypeSyntax
162
183
if let typeAnnotation = binding. typeAnnotation {
@@ -169,7 +190,7 @@ final class Swift2JavaVisitor: SyntaxVisitor {
169
190
do {
170
191
javaResultType = try cCompatibleType ( for: returnTy)
171
192
} catch {
172
- self . log. info ( " Unable to import variable \( node. debugDescription ) - \( error) " )
193
+ log. info ( " Unable to import variable ' \( node. qualifiedNameForDebug ) ' - \( error) " )
173
194
return . skipChildren
174
195
}
175
196
@@ -190,7 +211,7 @@ final class Swift2JavaVisitor: SyntaxVisitor {
190
211
log. debug ( " Record variable in \( currentTypeName) " )
191
212
translator. importedTypes [ currentTypeName] !. variables. append ( varDecl)
192
213
} else {
193
- fatalError ( " Global variables are not supported yet: \( node. debugDescription ) " )
214
+ fatalError ( " Global variables are not supported yet: \( node. qualifiedNameForDebug ) " )
194
215
}
195
216
196
217
return . skipChildren
@@ -206,7 +227,7 @@ final class Swift2JavaVisitor: SyntaxVisitor {
206
227
return . skipChildren
207
228
}
208
229
209
- self . log. debug ( " Import initializer: \( node. kind) \( currentType . javaType . description ) " )
230
+ self . log. debug ( " Import initializer: \( node. kind) ' \( node . qualifiedNameForDebug ) ' " )
210
231
let params : [ ImportedParam ]
211
232
do {
212
233
params = try node. signature. parameterClause. parameters. map { param in
@@ -247,37 +268,24 @@ final class Swift2JavaVisitor: SyntaxVisitor {
247
268
}
248
269
}
249
270
250
- extension DeclGroupSyntax where Self: NamedDeclSyntax {
271
+ extension DeclSyntaxProtocol where Self: WithModifiersSyntax & WithAttributesSyntax {
251
272
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" )
254
275
return false
255
276
}
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 " )
267
279
return false
268
280
}
269
281
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
275
284
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
+ }
281
289
}
282
290
283
291
return true
0 commit comments