Skip to content

Commit 5000d8b

Browse files
committed
Convert between computed properties and zero-parameters functions
1 parent d1a9857 commit 5000d8b

File tree

3 files changed

+140
-0
lines changed

3 files changed

+140
-0
lines changed

Sources/SwiftLanguageService/CodeActions/SyntaxCodeActions.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ let allSyntaxCodeActions: [SyntaxCodeActionProvider.Type] = {
1818
var result: [SyntaxCodeActionProvider.Type] = [
1919
AddDocumentation.self,
2020
AddSeparatorsToIntegerLiteral.self,
21+
ConvertComputedPropertyToZeroParameterFunction.self,
2122
ConvertIntegerLiteral.self,
2223
ConvertJSONToCodableStruct.self,
2324
ConvertStringConcatenationToStringInterpolation.self,
25+
ConvertZeroParameterFunctionToComputedProperty.self,
2426
FormatRawStringLiteral.self,
2527
MigrateToNewIfLetSyntax.self,
2628
OpaqueParameterToGeneric.self,

Sources/SwiftLanguageService/CodeActions/SyntaxRefactoringCodeActionProvider.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,28 @@ extension RemoveSeparatorsFromIntegerLiteral: SyntaxRefactoringCodeActionProvide
113113
}
114114
}
115115

116+
extension ConvertZeroParameterFunctionToComputedProperty: SyntaxRefactoringCodeActionProvider {
117+
package static var title: String { "Convert to computed property" }
118+
119+
static func nodeToRefactor(in scope: SyntaxCodeActionScope) -> Input? {
120+
return scope.innermostNodeContainingRange?.findParentOfSelf(
121+
ofType: FunctionDeclSyntax.self,
122+
stoppingIf: { $0.is(CodeBlockSyntax.self) || $0.is(MemberBlockSyntax.self) }
123+
)
124+
}
125+
}
126+
127+
extension ConvertComputedPropertyToZeroParameterFunction: SyntaxRefactoringCodeActionProvider {
128+
package static var title: String { "Convert to zero parameter function" }
129+
130+
static func nodeToRefactor(in scope: SyntaxCodeActionScope) -> Input? {
131+
return scope.innermostNodeContainingRange?.findParentOfSelf(
132+
ofType: VariableDeclSyntax.self,
133+
stoppingIf: { $0.is(CodeBlockSyntax.self) || $0.is(MemberBlockSyntax.self) }
134+
)
135+
}
136+
}
137+
116138
extension SyntaxProtocol {
117139
/// Finds the innermost parent of the given type while not walking outside of nodes that satisfy `stoppingIf`.
118140
func findParentOfSelf<ParentType: SyntaxProtocol>(

Tests/SourceKitLSPTests/CodeActionTests.swift

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,6 +1180,122 @@ final class CodeActionTests: SourceKitLSPTestCase {
11801180
)
11811181
}
11821182
1183+
func testConvertFunctionZeroParameterToComputedProperty() async throws {
1184+
let testClient = try await TestSourceKitLSPClient(capabilities: clientCapabilitiesWithCodeActionSupport)
1185+
let uri = DocumentURI(for: .swift)
1186+
1187+
let positions = testClient.openDocument(
1188+
"""
1189+
1️⃣func someFunction() -> String2️⃣ { return "" }3️⃣
1190+
""",
1191+
uri: uri
1192+
)
1193+
1194+
let request = CodeActionRequest(
1195+
range: positions["1️⃣"]..<positions["2️⃣"],
1196+
context: .init(),
1197+
textDocument: TextDocumentIdentifier(uri)
1198+
)
1199+
let result = try await testClient.send(request)
1200+
1201+
guard case .codeActions(let codeActions) = result else {
1202+
XCTFail("Expected code actions")
1203+
return
1204+
}
1205+
1206+
let expectedCodeAction = CodeAction(
1207+
title: "Convert to computed property",
1208+
kind: .refactorInline,
1209+
diagnostics: nil,
1210+
edit: WorkspaceEdit(
1211+
changes: [
1212+
uri: [
1213+
TextEdit(
1214+
range: positions["1️⃣"]..<positions["3️⃣"],
1215+
newText: """
1216+
var someFunction: String { return "" }
1217+
"""
1218+
)
1219+
]
1220+
]
1221+
),
1222+
command: nil
1223+
)
1224+
1225+
XCTAssertTrue(codeActions.contains(expectedCodeAction))
1226+
}
1227+
1228+
func testConvertZeroParameterFunctionToComputedPropertyIsNotShownFromTheBody() async throws {
1229+
try await assertCodeActions(
1230+
##"""
1231+
func someFunction() -> String 1️⃣{
1232+
2️⃣return ""
1233+
}3️⃣
1234+
"""##,
1235+
exhaustive: false
1236+
) { uri, positions in
1237+
[]
1238+
}
1239+
}
1240+
1241+
func testConvertComputedPropertyToZeroParameterFunction() async throws {
1242+
let testClient = try await TestSourceKitLSPClient(capabilities: clientCapabilitiesWithCodeActionSupport)
1243+
let uri = DocumentURI(for: .swift)
1244+
1245+
let positions = testClient.openDocument(
1246+
"""
1247+
1️⃣var someFunction: String2️⃣ { return "" }3️⃣
1248+
""",
1249+
uri: uri
1250+
)
1251+
1252+
let request = CodeActionRequest(
1253+
range: positions["1️⃣"]..<positions["2️⃣"],
1254+
context: .init(),
1255+
textDocument: TextDocumentIdentifier(uri)
1256+
)
1257+
let result = try await testClient.send(request)
1258+
1259+
guard case .codeActions(let codeActions) = result else {
1260+
XCTFail("Expected code actions")
1261+
return
1262+
}
1263+
1264+
let expectedCodeAction = CodeAction(
1265+
title: "Convert to zero parameter function",
1266+
kind: .refactorInline,
1267+
diagnostics: nil,
1268+
edit: WorkspaceEdit(
1269+
changes: [
1270+
uri: [
1271+
TextEdit(
1272+
range: positions["1️⃣"]..<positions["3️⃣"],
1273+
newText: """
1274+
func someFunction() -> String { return "" }
1275+
"""
1276+
)
1277+
]
1278+
]
1279+
),
1280+
command: nil
1281+
)
1282+
1283+
XCTAssertTrue(codeActions.contains(expectedCodeAction))
1284+
}
1285+
1286+
func testConvertComputedPropertyToZeroParameterFunctionIsNotShownFromTheBody() async throws {
1287+
try await assertCodeActions(
1288+
##"""
1289+
var someFunction: String 1️⃣{
1290+
2️⃣return ""
1291+
}3️⃣
1292+
"""##,
1293+
exhaustive: false
1294+
) { uri, positions in
1295+
[]
1296+
}
1297+
}
1298+
11831299
/// Retrieves the code action at a set of markers and asserts that it matches a list of expected code actions.
11841300
///
11851301
/// - Parameters:

0 commit comments

Comments
 (0)