Skip to content

Commit 33e65f8

Browse files
authored
Merge pull request #3299 from MKY508/subscript-result-builder
2 parents 52f931e + 8baa158 commit 33e65f8

2 files changed

Lines changed: 111 additions & 0 deletions

File tree

Sources/SwiftSyntaxBuilder/SyntaxNodeWithBody.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,45 @@ extension SwitchExprSyntax {
371371
}
372372
}
373373

374+
// MARK: - SubscriptDeclSyntax
375+
// SubscriptDeclSyntax is a special scenario as it don't have body or members
376+
// So we cannot conform to `HasTrailingCodeBlock` or `HasTrailingMemberDeclBlock`
377+
378+
extension SubscriptDeclSyntax {
379+
/// Construct a subscript with a single `get` accessor where `header` builds
380+
/// the text before the opening `{` and `accessor` builds the accessor body.
381+
///
382+
/// For example, to construct
383+
///
384+
/// ```swift
385+
/// subscript(_ index: Int) -> Element {
386+
/// return storage[index]
387+
/// }
388+
/// ```
389+
///
390+
/// using this call
391+
///
392+
/// ```swift
393+
/// try SubscriptDeclSyntax("subscript(_ index: Int) -> Element") {
394+
/// StmtSyntax("return storage[index]")
395+
/// }
396+
/// ```
397+
///
398+
/// Throws an error if `header` does not start a subscript declaration.
399+
/// E.g. if calling `try SubscriptDeclSyntax("func foo") {}`
400+
public init(
401+
_ header: SyntaxNodeString,
402+
@CodeBlockItemListBuilder accessor: () throws -> CodeBlockItemListSyntax
403+
) throws {
404+
let decl = DeclSyntax("\(header) {}")
405+
guard let castedDecl = decl.as(Self.self) else {
406+
throw SyntaxStringInterpolationInvalidNodeTypeError(expectedType: Self.self, actualNode: decl)
407+
}
408+
self = castedDecl
409+
self.accessorBlock = AccessorBlockSyntax(accessors: .getter(try accessor()))
410+
}
411+
}
412+
374413
// MARK: - VariableDeclSyntax
375414
// VariableDeclSyntax is a special scenario as it don't have body or members
376415
// So we cannot conform to `HasTrailingCodeBlock` or `HasTrailingMemberDeclBlock`
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) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import SwiftSyntax
14+
import SwiftSyntaxBuilder
15+
import XCTest
16+
17+
final class SubscriptTests: XCTestCase {
18+
func testSubscriptGetter() throws {
19+
let buildable = try SubscriptDeclSyntax("subscript(_ index: Int) -> Element") {
20+
StmtSyntax("return storage[index]")
21+
}
22+
23+
assertBuildResult(
24+
buildable,
25+
"""
26+
subscript(_ index: Int) -> Element {
27+
return storage[index]
28+
}
29+
"""
30+
)
31+
}
32+
33+
func testSubscriptAccessorList() throws {
34+
let buildable = try SubscriptDeclSyntax("subscript(_ index: Int) -> Element") {
35+
AccessorDeclSyntax(accessorSpecifier: .keyword(.get)) {
36+
StmtSyntax("return storage[index]")
37+
}
38+
39+
AccessorDeclSyntax(accessorSpecifier: .keyword(.set)) {
40+
ExprSyntax("storage[index] = newValue")
41+
}
42+
}
43+
44+
assertBuildResult(
45+
buildable,
46+
"""
47+
subscript(_ index: Int) -> Element {
48+
get {
49+
return storage[index]
50+
}
51+
set {
52+
storage[index] = newValue
53+
}
54+
}
55+
"""
56+
)
57+
}
58+
59+
func testSubscriptProtocolRequirement() throws {
60+
let buildable = DeclSyntax("subscript(_ index: Int) -> Element { get set }")
61+
62+
assertBuildResult(
63+
buildable,
64+
"""
65+
subscript(_ index: Int) -> Element {
66+
get
67+
set
68+
}
69+
"""
70+
)
71+
}
72+
}

0 commit comments

Comments
 (0)