Skip to content

Commit 77ace5f

Browse files
committed
Add support for failing build when multiple types are mapped to the same type
1 parent 3ceb6ef commit 77ace5f

File tree

3 files changed

+115
-0
lines changed

3 files changed

+115
-0
lines changed

Sources/Java2Swift/JavaToSwift.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,9 @@ struct JavaToSwift: ParsableCommand {
267267
allClassesToVisit.append(contentsOf: nestedClasses)
268268
}
269269

270+
// Validate configurations before writing any files
271+
try translator.validateClassConfiguration()
272+
270273
// Translate all of the Java classes into Swift classes.
271274
for javaClass in javaClasses {
272275
translator.startNewFile()
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the Swift.org project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of Swift.org project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import Foundation
16+
17+
package extension JavaTranslator {
18+
struct SwiftTypeName: Hashable {
19+
let swiftType: String
20+
let swiftModule: String?
21+
22+
package init(swiftType: String, swiftModule: String?) {
23+
self.swiftType = swiftType
24+
self.swiftModule = swiftModule
25+
}
26+
}
27+
28+
struct SwiftToJavaMapping: Equatable {
29+
let swiftType: SwiftTypeName
30+
let javaTypes: [String]
31+
32+
package init(swiftType: SwiftTypeName, javaTypes: [String]) {
33+
self.swiftType = swiftType
34+
self.javaTypes = javaTypes
35+
}
36+
}
37+
38+
enum ValidationError: Error, CustomStringConvertible {
39+
case multipleClassesMappedToSameName(swiftToJavaMapping: [SwiftToJavaMapping])
40+
41+
package var description: String {
42+
switch self {
43+
case .multipleClassesMappedToSameName(let swiftToJavaMapping):
44+
"""
45+
The following Java classes were mapped to the same Swift type:
46+
\(swiftToJavaMapping.map { mapping in
47+
"Swift Type: \(mapping.swiftType.swiftModule ?? "").\(mapping.swiftType.swiftType), Java Types: \(mapping.javaTypes.sorted().joined(separator: ", "))"
48+
}.joined(separator: "\n"))
49+
"""
50+
}
51+
}
52+
53+
}
54+
func validateClassConfiguration() throws {
55+
// Group all classes by swift name
56+
let groupedDictionary: [SwiftTypeName: [(String, (String, String?))]] = Dictionary(grouping: translatedClasses, by: { SwiftTypeName(swiftType: $0.value.swiftType, swiftModule: $0.value.swiftModule) })
57+
// Find all that are mapped to multiple names
58+
let multipleClassesMappedToSameName: [SwiftTypeName: [(String, (String, String?))]] = groupedDictionary.filter { (key: SwiftTypeName, value: [(String, (String, String?))]) in
59+
value.count > 1
60+
}
61+
62+
if !multipleClassesMappedToSameName.isEmpty {
63+
// Convert them to swift object and throw
64+
var errorMappings = [SwiftToJavaMapping]()
65+
for (swiftType, swiftJavaMappings) in multipleClassesMappedToSameName {
66+
errorMappings.append(SwiftToJavaMapping(swiftType: swiftType, javaTypes: swiftJavaMappings.map(\.0)))
67+
}
68+
throw ValidationError.multipleClassesMappedToSameName(swiftToJavaMapping: errorMappings)
69+
}
70+
71+
}
72+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the Swift.org project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of Swift.org project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import Java2SwiftLib
16+
import XCTest
17+
18+
final class JavaTranslatorValidationTests: XCTestCase {
19+
func testValidationError() throws {
20+
let translator = try JavaTranslator(swiftModuleName: "SwiftModule", environment: jvm.environment())
21+
translator.translatedClasses = [
22+
"TestClass": ("Class1", "Module1"),
23+
"TestClass2": ("Class1", "Module2"),
24+
"TestClass3": ("Class1", "Module1"),
25+
"TestClass4": ("Class1", nil)
26+
]
27+
28+
XCTAssertThrowsError(try translator.validateClassConfiguration()) { error in
29+
XCTAssertTrue(error is JavaTranslator.ValidationError)
30+
let validationError = error as! JavaTranslator.ValidationError
31+
switch validationError {
32+
case .multipleClassesMappedToSameName(let swiftToJavaMapping):
33+
XCTAssertEqual(swiftToJavaMapping, [
34+
JavaTranslator.SwiftToJavaMapping(swiftType: .init(swiftType: "Class1", swiftModule: "Module1"),
35+
javaTypes: ["TestClass", "TestClass3"])
36+
])
37+
}
38+
}
39+
}
40+
}

0 commit comments

Comments
 (0)