Skip to content

Commit a0961dd

Browse files
authored
Merge pull request #822 from wfltaylor/escape-reserved-parameter-names
BridgeJS: Escape reserved words in exported function parameters
2 parents 5c95e3c + 89057a1 commit a0961dd

16 files changed

Lines changed: 1885 additions & 105 deletions

File tree

‎Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -213,10 +213,11 @@ public class ExportSwift {
213213

214214
func liftParameter(param: Parameter) throws {
215215
parameters.append(param)
216+
let escapedName = param.escapedSwiftIdentifier
216217
let liftingInfo = try param.type.liftParameterInfo()
217218
let argumentsToLift: [String]
218219
if liftingInfo.parameters.count == 1 {
219-
argumentsToLift = [param.name]
220+
argumentsToLift = [escapedName]
220221
} else {
221222
argumentsToLift = liftingInfo.parameters.map { (name, _) in param.name + name.capitalizedFirstLetter }
222223
}
@@ -227,7 +228,9 @@ public class ExportSwift {
227228
switch param.type {
228229
case .closure(let signature, _):
229230
typeNameForIntrinsic = param.type.swiftType
230-
liftingExpr = ExprSyntax("_BJS_Closure_\(raw: signature.mangleName).bridgeJSLift(\(raw: param.name))")
231+
liftingExpr = ExprSyntax(
232+
"_BJS_Closure_\(raw: signature.mangleName).bridgeJSLift(\(raw: escapedName))"
233+
)
231234
case .swiftStruct(let structName):
232235
typeNameForIntrinsic = structName
233236
liftingExpr = ExprSyntax("\(raw: structName).bridgeJSLiftParameter()")
@@ -252,7 +255,7 @@ public class ExportSwift {
252255
)
253256
}
254257

255-
parameterBindings.insert("let \(raw: param.name) = \(liftingExpr)", at: 0)
258+
parameterBindings.insert("let \(raw: param.escapedSwiftBindingIdentifier) = \(liftingExpr)", at: 0)
256259
for (name, type) in zip(argumentsToLift, liftingInfo.parameters.map { $0.type }) {
257260
abiParameterSignatures.append((name, type))
258261
}
@@ -268,14 +271,14 @@ public class ExportSwift {
268271
}
269272

270273
private func removeFirstLiftedParameter() -> String {
271-
return parameters.removeFirst().name
274+
return parameters.removeFirst().escapedSwiftIdentifier
272275
}
273276

274277
private func renderCallStatement(callee: ExprSyntax, returnType: BridgeType) -> CodeBlockItemSyntax {
275278
let labeledParams = parameters.map { param in
276279
LabeledExprSyntax(
277280
label: param.label,
278-
expression: DeclReferenceExprSyntax(baseName: .identifier(param.name))
281+
expression: DeclReferenceExprSyntax(baseName: .identifier(param.escapedSwiftIdentifier))
279282
)
280283
}
281284
var callExpr: ExprSyntax =

‎Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift‎

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,8 @@ public struct ImportTS {
143143
}
144144

145145
func lowerParameter(param: Parameter) throws {
146-
if let genericPush = param.type.genericStackPushStatement(value: param.name) {
146+
let escapedName = param.escapedSwiftIdentifier
147+
if let genericPush = param.type.genericStackPushStatement(value: escapedName) {
147148
stackLoweringStmts.insert(genericPush, at: 0)
148149
return
149150
}
@@ -153,10 +154,10 @@ public struct ImportTS {
153154
switch param.type {
154155
case .closure(let signature, useJSTypedClosure: false):
155156
let jsTypedClosureType = BridgeType.closure(signature, useJSTypedClosure: true).swiftType
156-
body.write("let \(param.name) = \(jsTypedClosureType)(\(param.name))")
157+
body.write("let \(param.escapedSwiftBindingIdentifier) = \(jsTypedClosureType)(\(escapedName))")
157158
// The just created JSObject is not owned by the caller unlike those passed in parameters,
158159
// so we need to extend its lifetime during the call to ensure the JSObject.id is valid.
159-
valuesToExtendLifetimeDuringCall.append(param.name)
160+
valuesToExtendLifetimeDuringCall.append(escapedName)
160161
default:
161162
break
162163
}
@@ -177,7 +178,7 @@ public struct ImportTS {
177178
if loweringInfo.useBorrowing {
178179
let returnVariableName = "ret\(borrowedArguments.count)"
179180
let assign = needsReturnVariable ? "let \(returnVariableName) = " : ""
180-
body.write("\(assign)\(param.name).bridgeJSWithLoweredParameter { \(pattern) in")
181+
body.write("\(assign)\(escapedName).bridgeJSWithLoweredParameter { \(pattern) in")
181182
body.indent()
182183
borrowedArguments.append(
183184
BorrowedArgument(
@@ -190,10 +191,10 @@ public struct ImportTS {
190191
)
191192
} else if case .nullable(.swiftProtocol(let protocolName), _) = param.type, context == .exportSwift {
192193
body.write("let \(pattern): (Int32, Int32)")
193-
body.write("if let \(param.name) {")
194+
body.write("if let \(param.escapedSwiftBindingIdentifier) {")
194195
body.indent {
195196
body.write(
196-
"\(pattern) = (1, _bridgeJSUnwrapProtocolExportable(\(param.name), \"\(protocolName)\").bridgeJSLowerAsProtocolReturn())"
197+
"\(pattern) = (1, _bridgeJSUnwrapProtocolExportable(\(escapedName), \"\(protocolName)\").bridgeJSLowerAsProtocolReturn())"
197198
)
198199
}
199200
body.write("} else {")
@@ -205,10 +206,10 @@ public struct ImportTS {
205206
let initializerExpr: ExprSyntax
206207
if case .swiftProtocol(let protocolName) = param.type, context == .exportSwift {
207208
initializerExpr = ExprSyntax(
208-
"_bridgeJSUnwrapProtocolExportable(\(raw: param.name), \"\(raw: protocolName)\").bridgeJSLowerAsProtocolReturn()"
209+
"_bridgeJSUnwrapProtocolExportable(\(raw: escapedName), \"\(raw: protocolName)\").bridgeJSLowerAsProtocolReturn()"
209210
)
210211
} else {
211-
initializerExpr = ExprSyntax("\(raw: param.name).bridgeJSLowerParameter()")
212+
initializerExpr = ExprSyntax("\(raw: escapedName).bridgeJSLowerParameter()")
212213
}
213214

214215
let binding = loweringInfo.loweredParameters.isEmpty ? "_" : pattern
@@ -218,10 +219,10 @@ public struct ImportTS {
218219

219220
// Add to signatures and forwardings (unified for both single and multiple)
220221
for (index, (paramName, type)) in loweringInfo.loweredParameters.enumerated() {
221-
// For single parameter, use param.name; for multiple, use constructed name
222+
// For single parameter, use the escaped name; for multiple, use constructed name
222223
let abiParamName: String
223224
if loweringInfo.loweredParameters.count == 1 {
224-
abiParamName = param.name
225+
abiParamName = escapedName
225226
} else {
226227
abiParamName = "\(param.name)\(paramName.capitalizedFirstLetter)"
227228
}
@@ -723,20 +724,21 @@ struct SwiftSignatureBuilder {
723724
var out = "("
724725
out += parameters.map { param in
725726
let label = param.label ?? param.name
727+
let escapedName = param.escapedSwiftIdentifier
726728
let paramType = buildParameterTypeSyntax(from: param.type)
727729

728730
if useWildcardLabels {
729731
// Always use wildcard labels: "_ name: Type"
730-
return "_ \(param.name): \(paramType)"
731-
} else if label == param.name {
732+
return "_ \(escapedName): \(paramType)"
733+
} else if SwiftToSkeleton.normalizeIdentifier(label) == param.name {
732734
// External label same as parameter name: "count: Int"
733-
return "\(param.name): \(paramType)"
735+
return "\(escapedName): \(paramType)"
734736
} else if param.label == nil {
735737
// No label specified: use wildcard "_ name: Type"
736-
return "_ \(param.name): \(paramType)"
738+
return "_ \(escapedName): \(paramType)"
737739
} else {
738740
// External label differs: "label count: Int"
739-
return "\(label) \(param.name): \(paramType)"
741+
return "\(label) \(escapedName): \(paramType)"
740742
}
741743
}.joined(separator: ", ")
742744
out += ")"
@@ -1065,3 +1067,13 @@ extension String {
10651067
return self.isValidSwiftIdentifier(for: .variableName) ? self : "`\(self)`"
10661068
}
10671069
}
1070+
1071+
extension Parameter {
1072+
var escapedSwiftIdentifier: String {
1073+
name == "self" ? name : name.backtickIfNeeded()
1074+
}
1075+
1076+
var escapedSwiftBindingIdentifier: String {
1077+
name.backtickIfNeeded()
1078+
}
1079+
}

‎Plugins/BridgeJS/Sources/BridgeJSCore/SwiftToSkeleton.swift‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1587,7 +1587,7 @@ private final class ExportSwiftAPICollector: SyntaxAnyVisitor {
15871587
continue
15881588
}
15891589

1590-
let name = param.secondName?.text ?? param.firstName.text
1590+
let name = SwiftToSkeleton.normalizeIdentifier(param.secondName?.text ?? param.firstName.text)
15911591
let label = param.firstName.text
15921592

15931593
let defaultValue: DefaultValue?

0 commit comments

Comments
 (0)