forked from swiftlang/swift-java
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathJNISwift2JavaGenerator.swift
More file actions
147 lines (128 loc) · 5.74 KB
/
JNISwift2JavaGenerator.swift
File metadata and controls
147 lines (128 loc) · 5.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift.org project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Swift.org project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
import CodePrinting
import SwiftJavaConfigurationShared
import SwiftJavaJNICore
/// A table that where keys are Swift class names and the values are
/// the fully qualified canoical names.
package typealias JavaClassLookupTable = [String: String]
package class JNISwift2JavaGenerator: Swift2JavaGenerator {
let logger: Logger
let config: Configuration
let analysis: AnalysisResult
let swiftModuleName: String
let javaPackage: String
let swiftOutputDirectory: String
let javaOutputDirectory: String
let lookupContext: SwiftTypeLookupContext
let javaClassLookupTable: JavaClassLookupTable
var javaPackagePath: String {
javaPackage.replacingOccurrences(of: ".", with: "/")
}
var thunkNameRegistry = ThunkNameRegistry()
/// Accumulates every ``@_cdecl`` symbol name emitted during thunk printing.
/// Written to a linker version script after generation when
/// ``Configuration/linkerExportListOutput`` is set.
var generatedCDeclSymbolNames: [String] = []
/// Cached Java translation result. 'nil' indicates failed translation.
var translatedDecls: [ImportedFunc: TranslatedFunctionDecl] = [:]
var translatedEnumCases: [ImportedEnumCase: TranslatedEnumCase] = [:]
var interfaceProtocolWrappers: [ImportedNominalType: JavaInterfaceSwiftWrapper] = [:]
/// Duplicate identifier tracking for the current batch of methods being generated.
var currentJavaIdentifiers: JavaIdentifierFactory = JavaIdentifierFactory()
/// The Java-facing name of the type currently being printed.
/// Used to override cached parentName in translations (needed for specializations
/// where the same ImportedFunc is shared between base and specialized types)
var currentPrintingTypeName: String?
/// The type currently being printed (Java class or Swift thunks).
/// Used to determine specialization context for correct code generation
var currentPrintingType: ImportedNominalType?
/// Because we need to write empty files for SwiftPM, keep track which files we didn't write yet,
/// and write an empty file for those.
///
/// Since Swift files in SwiftPM builds needs to be unique, we use this fact to flatten paths into plain names here.
/// For uniqueness checking "did we write this file already", just checking the name should be sufficient.
var expectedOutputSwiftFileNames: Set<String>
package init(
config: Configuration,
translator: Swift2JavaTranslator,
javaPackage: String,
swiftOutputDirectory: String,
javaOutputDirectory: String,
javaClassLookupTable: JavaClassLookupTable,
) {
self.config = config
self.logger = Logger(label: "jni-generator", logLevel: translator.log.logLevel)
self.analysis = translator.result
self.swiftModuleName = translator.swiftModuleName
self.javaPackage = javaPackage
self.swiftOutputDirectory = swiftOutputDirectory
self.javaOutputDirectory = javaOutputDirectory
self.javaClassLookupTable = javaClassLookupTable
self.lookupContext = translator.lookupContext
// If we are forced to write empty files, construct the expected outputs.
// It is sufficient to use file names only, since SwiftPM requires names to be unique within a module anyway.
if translator.config.effectiveWriteEmptyFiles {
self.expectedOutputSwiftFileNames = Set(
translator.inputs.compactMap { (input) -> String? in
guard let fileName = input.path.split(separator: PATH_SEPARATOR).last else {
return nil
}
if fileName.hasSuffix(".swift") {
return String(fileName.replacing(".swift", with: "+SwiftJava.swift"))
} else if fileName.hasSuffix(".swiftinterface") {
return String(fileName.replacing(".swiftinterface", with: "+SwiftJava.swift"))
}
return nil
}
)
// Also include filtered-out files so SwiftPM gets the empty outputs it expects
for path in translator.filteredOutPaths {
guard let fileName = path.split(separator: PATH_SEPARATOR).last else {
continue
}
if fileName.hasSuffix(".swift") {
self.expectedOutputSwiftFileNames.insert(
String(fileName.replacing(".swift", with: "+SwiftJava.swift"))
)
}
}
self.expectedOutputSwiftFileNames.insert("\(translator.swiftModuleName)Module+SwiftJava.swift")
self.expectedOutputSwiftFileNames.insert("Foundation+SwiftJava.swift")
} else {
self.expectedOutputSwiftFileNames = []
}
if translator.config.enableJavaCallbacks ?? false {
// We translate all the protocol wrappers
// as we need them to know what protocols we can allow the user to implement themselves
// in Java.
self.interfaceProtocolWrappers = self.generateInterfaceWrappers(Array(self.analysis.importedTypes.values))
}
}
func generate() throws {
try writeSwiftThunkSources()
try writeExportedJavaSources()
try writeLinkerExportList()
let pendingFileCount = self.expectedOutputSwiftFileNames.count
if pendingFileCount > 0 {
print("[swift-java] Write empty [\(pendingFileCount)] 'expected' files in: \(swiftOutputDirectory)/")
try writeSwiftExpectedEmptySources()
}
}
}
extension JNISwift2JavaGenerator {
static func indirectVariableName(for parameterName: String) -> String {
"\(parameterName)$indirect"
}
}