Skip to content

Commit d7dc105

Browse files
Merge pull request #44 from CheekyGhost-Labs/develop
[BUG] Fixing incorrect resolving of inout on parameters (#43)
2 parents 9dc4a36 + 82eb0ed commit d7dc105

File tree

5 files changed

+126
-8
lines changed

5 files changed

+126
-8
lines changed

Sources/SyntaxSparrow/Internal/Resolvers/Syntax/EnumCaseParameterSemanticsResolver.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,8 @@ struct EnumCaseParameterSemanticsResolver: ParameterNodeSemanticsResolving {
7474
}
7575

7676
func resolveIsInOut() -> Bool {
77-
node.type.tokens(viewMode: .fixedUp).contains(where: {
78-
$0.tokenKind == TokenKind.keyword(.inout)
79-
})
77+
let tokens = node.type.children(viewMode: .fixedUp).compactMap { $0.as(TokenSyntax.self) }
78+
return tokens.contains(where: { $0.tokenKind == TokenKind.keyword(.inout) })
8079
}
8180

8281
func resolveDescription() -> String {

Sources/SyntaxSparrow/Internal/Resolvers/Syntax/FunctionParameterSemanticsResolver.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,7 @@ struct FunctionParameterSemanticsResolver: ParameterNodeSemanticsResolving {
6767
}
6868

6969
func resolveIsInOut() -> Bool {
70-
node.type.tokens(viewMode: .fixedUp).contains(where: {
71-
$0.tokenKind == TokenKind.keyword(.inout)
72-
})
70+
let tokens = node.type.children(viewMode: .fixedUp).compactMap { $0.as(TokenSyntax.self) }
71+
return tokens.contains(where: { $0.tokenKind == TokenKind.keyword(.inout) })
7372
}
7473
}

Sources/SyntaxSparrow/Internal/Resolvers/Syntax/TupleParameterSemanticsResolver.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ struct TupleParameterSemanticsResolver: ParameterNodeSemanticsResolving {
6868
}
6969

7070
func resolveIsInOut() -> Bool {
71-
node.inoutKeyword != nil
71+
guard node.inoutKeyword == nil else {
72+
return true
73+
}
74+
guard let attributedType = node.children(viewMode: .fixedUp).first?.as(AttributedTypeSyntax.self) else {
75+
return false
76+
}
77+
let tokens = attributedType.children(viewMode: .fixedUp).compactMap { $0.as(TokenSyntax.self) }
78+
return tokens.contains(where: { $0.tokenKind == TokenKind.keyword(.inout) })
7279
}
7380
}

Tests/SyntaxSparrowTests/Declarations/EnumerationTests.swift

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,14 +342,15 @@ final class DeinitializerTests: XCTestCase {
342342
case resultOptional(processResult: Result<String, Error>?)
343343
case defaultValue(name: String = "name")
344344
case inoutValue(names: inout [String])
345+
case inoutValues(names: inout [String], inout String)
345346
}
346347
"""#
347348
instanceUnderTest.updateToSource(source)
348349
XCTAssertTrue(instanceUnderTest.isStale)
349350
instanceUnderTest.collectChildren()
350351
XCTAssertFalse(instanceUnderTest.isStale)
351352
XCTAssertEqual(instanceUnderTest.enumerations.count, 1)
352-
XCTAssertEqual(instanceUnderTest.enumerations[0].cases.count, 18)
353+
XCTAssertEqual(instanceUnderTest.enumerations[0].cases.count, 19)
353354
let enumeration = instanceUnderTest.enumerations[0]
354355

355356
// No Parameters
@@ -783,5 +784,44 @@ final class DeinitializerTests: XCTestCase {
783784
} else {
784785
XCTFail("function.signature.input[0] type should be Array")
785786
}
787+
788+
// Optional Result parameter
789+
// case inoutValues(names: inout [String], inout String)
790+
enumCase = enumeration.cases[18]
791+
XCTAssertEqual(enumCase.keyword, "case")
792+
XCTAssertEqual(enumCase.name, "inoutValues")
793+
XCTAssertEqual(enumCase.associatedValues.count, 2)
794+
XCTAssertEqual(enumCase.associatedValues[0].attributes, [])
795+
XCTAssertEqual(enumCase.associatedValues[0].modifiers, [])
796+
XCTAssertEqual(enumCase.associatedValues[0].name, "names")
797+
XCTAssertNil(enumCase.associatedValues[0].secondName)
798+
XCTAssertFalse(enumCase.associatedValues[0].isLabelOmitted)
799+
XCTAssertFalse(enumCase.associatedValues[0].isVariadic)
800+
XCTAssertFalse(enumCase.associatedValues[0].isOptional)
801+
XCTAssertTrue(enumCase.associatedValues[0].isInOut)
802+
XCTAssertEqual(enumCase.associatedValues[0].rawType, "inout [String]")
803+
XCTAssertNil(enumCase.associatedValues[0].defaultArgument)
804+
XCTAssertEqual(enumCase.associatedValues[0].description, "names: inout [String]")
805+
806+
if case let EntityType.array(array) = enumCase.associatedValues[0].type {
807+
XCTAssertEqual(array.declType, .squareBrackets)
808+
XCTAssertFalse(array.isOptional)
809+
XCTAssertEqual(array.elementType, .simple("String"))
810+
} else {
811+
XCTFail("function.signature.input[0] type should be Array")
812+
}
813+
814+
XCTAssertEqual(enumCase.associatedValues[1].attributes, [])
815+
XCTAssertEqual(enumCase.associatedValues[1].modifiers, [])
816+
XCTAssertNil(enumCase.associatedValues[1].name)
817+
XCTAssertNil(enumCase.associatedValues[1].secondName)
818+
XCTAssertFalse(enumCase.associatedValues[1].isLabelOmitted)
819+
XCTAssertFalse(enumCase.associatedValues[1].isVariadic)
820+
XCTAssertFalse(enumCase.associatedValues[1].isOptional)
821+
XCTAssertTrue(enumCase.associatedValues[1].isInOut)
822+
XCTAssertEqual(enumCase.associatedValues[1].rawType, "String")
823+
XCTAssertNil(enumCase.associatedValues[1].defaultArgument)
824+
XCTAssertEqual(enumCase.associatedValues[1].description, "inout String")
825+
XCTAssertEqual(enumCase.associatedValues[1].type, .simple("String"))
786826
}
787827
}

Tests/SyntaxSparrowTests/Declarations/FunctionTests.swift

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,79 @@ final class FunctionTests: XCTestCase {
297297
XCTAssertEqual(instanceUnderTest.functions[0].signature.node, instanceUnderTest.functions[0].node.signature)
298298
}
299299

300+
func test_function_inoutWithinClosure_resolvesExpectedTypes() {
301+
let source = #"""
302+
func closure(_ handler: @escaping (inout Int, String) -> Void, name: inout String) {}
303+
"""#
304+
instanceUnderTest.updateToSource(source)
305+
XCTAssertTrue(instanceUnderTest.isStale)
306+
instanceUnderTest.collectChildren()
307+
XCTAssertFalse(instanceUnderTest.isStale)
308+
XCTAssertEqual(instanceUnderTest.functions.count, 1)
309+
let function = instanceUnderTest.functions[0]
310+
311+
XCTAssertEqual(function.keyword, "func")
312+
XCTAssertEqual(function.identifier, "closure")
313+
XCTAssertNil(function.signature.effectSpecifiers)
314+
XCTAssertEqual(function.signature.input.count, 2)
315+
// Closure Input with inout input
316+
XCTAssertEqual(function.signature.input[0].attributes.map(\.name), ["escaping"])
317+
XCTAssertEqual(function.signature.input[0].attributes.flatMap(\.arguments), [])
318+
XCTAssertEqual(function.signature.input[0].modifiers, [])
319+
XCTAssertEqual(function.signature.input[0].name, "_")
320+
XCTAssertEqual(function.signature.input[0].secondName, "handler")
321+
XCTAssertTrue(function.signature.input[0].isLabelOmitted)
322+
XCTAssertFalse(function.signature.input[0].isVariadic)
323+
XCTAssertFalse(function.signature.input[0].isOptional)
324+
XCTAssertFalse(function.signature.input[0].isInOut)
325+
XCTAssertNil(function.signature.input[0].defaultArgument)
326+
XCTAssertEqual(function.signature.input[0].rawType, "@escaping (inout Int, String) -> Void")
327+
XCTAssertEqual(function.signature.input[0].description, "_ handler: @escaping (inout Int, String) -> Void")
328+
// Closure type assessment
329+
if case let EntityType.closure(closure) = function.signature.input[0].type {
330+
XCTAssertEqual(closure.output, .void("Void", false))
331+
XCTAssertTrue(closure.isVoidOutput)
332+
XCTAssertFalse(closure.isOptional)
333+
XCTAssertTrue(closure.isEscaping)
334+
XCTAssertFalse(closure.isAutoEscaping)
335+
XCTAssertEqual(closure.description, "(inout Int, String) -> Void")
336+
// Input
337+
XCTAssertFalse(closure.isVoidInput)
338+
if case let EntityType.tuple(tuple) = closure.input {
339+
XCTAssertEqual(tuple.elements.count, 2)
340+
// Inout Int
341+
XCTAssertFalse(tuple.elements[0].isOptional)
342+
XCTAssertTrue(tuple.elements[0].isInOut)
343+
XCTAssertEqual(tuple.elements[0].type, .simple("Int"))
344+
XCTAssertEqual(tuple.elements[0].description, "inout Int")
345+
// Standard String
346+
XCTAssertFalse(tuple.elements[1].isOptional)
347+
XCTAssertFalse(tuple.elements[1].isInOut)
348+
XCTAssertEqual(tuple.elements[1].type, .simple("String"))
349+
XCTAssertEqual(tuple.elements[1].description, "String")
350+
} else {
351+
XCTFail("The closure input should be a tuple type")
352+
}
353+
} else {
354+
XCTFail("function.signature.input[0] type should be closure")
355+
}
356+
357+
// inout name String
358+
XCTAssertEqual(function.signature.input[1].attributes.map(\.name), [])
359+
XCTAssertEqual(function.signature.input[1].attributes.flatMap(\.arguments), [])
360+
XCTAssertEqual(function.signature.input[1].modifiers, [])
361+
XCTAssertEqual(function.signature.input[1].name, "name")
362+
XCTAssertNil(function.signature.input[1].secondName)
363+
XCTAssertFalse(function.signature.input[1].isLabelOmitted)
364+
XCTAssertFalse(function.signature.input[1].isVariadic)
365+
XCTAssertFalse(function.signature.input[1].isOptional)
366+
XCTAssertTrue(function.signature.input[1].isInOut)
367+
XCTAssertNil(function.signature.input[1].defaultArgument)
368+
XCTAssertEqual(function.signature.input[1].type.description, "String")
369+
XCTAssertEqual(function.signature.input[1].rawType, "inout String")
370+
XCTAssertEqual(function.signature.input[1].description, "name: inout String")
371+
}
372+
300373
func test_function_parameters_willResolveExpectedTypes() throws {
301374
let source = #"""
302375
func noParameters() throws {}

0 commit comments

Comments
 (0)