Skip to content

Commit 69909d6

Browse files
authored
Merge pull request #2739 from ahoppen/accessor-decl-header-initializer
Fix issue that caused `AccessorDeclSyntax` initializer with header + body to be misparsed
2 parents 3db6f01 + 81091c1 commit 69909d6

File tree

2 files changed

+53
-2
lines changed

2 files changed

+53
-2
lines changed

Sources/SwiftSyntaxBuilder/SyntaxNodeWithBody.swift

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212

1313
#if swift(>=6)
1414
public import SwiftSyntax
15+
internal import SwiftParser
1516
#else
1617
import SwiftSyntax
18+
import SwiftParser
1719
#endif
1820

1921
// MARK: - PartialSyntaxNode
@@ -124,7 +126,22 @@ extension WithOptionalCodeBlockSyntax where Self: DeclSyntaxProtocol {
124126
_ header: SyntaxNodeString,
125127
@CodeBlockItemListBuilder bodyBuilder: () throws -> CodeBlockItemListSyntax
126128
) throws {
127-
let decl = DeclSyntax("\(header) {}")
129+
// If the type provides a custom `SyntaxParseable` implementation, use that. Otherwise construct it as a
130+
// `DeclSyntax`.
131+
// We cannot use normal string interpolation here because the conformance to `ExpressibleByStringInterpolation` is
132+
// not implied by `SyntaxParsable` but generated for each type by
133+
// `SyntaxExpressibleByStringInterpolationConformances.swift`. And we can’t use that protocol in the `as?` check
134+
// because then the compiler complains that `parsableType` is not instantiable. So, manually do the same work that
135+
// a string literal with interpolation segments would do.
136+
let decl: DeclSyntax
137+
var stringInterpolation = SyntaxStringInterpolation(literalCapacity: 1, interpolationCount: 1)
138+
stringInterpolation.appendInterpolation(header)
139+
stringInterpolation.appendLiteral(" {}")
140+
if let parsableType = Self.self as? SyntaxParseable.Type {
141+
decl = parsableType.init(stringInterpolation: stringInterpolation).cast(DeclSyntax.self)
142+
} else {
143+
decl = DeclSyntax(stringInterpolation: stringInterpolation)
144+
}
128145
guard let castedDecl = decl.as(Self.self) else {
129146
throw SyntaxStringInterpolationInvalidNodeTypeError(expectedType: Self.self, actualNode: decl)
130147
}
@@ -170,7 +187,17 @@ extension HasTrailingMemberDeclBlock where Self: DeclSyntaxProtocol {
170187
_ header: SyntaxNodeString,
171188
@MemberBlockItemListBuilder membersBuilder: () throws -> MemberBlockItemListSyntax
172189
) throws {
173-
let decl = DeclSyntax("\(header) {}")
190+
// If the type provides a custom `SyntaxParseable` implementation, use that. Otherwise construct it as a
191+
// `DeclSyntax`.
192+
let decl: DeclSyntax
193+
var stringInterpolation = SyntaxStringInterpolation(literalCapacity: 1, interpolationCount: 1)
194+
stringInterpolation.appendInterpolation(header)
195+
stringInterpolation.appendLiteral(" {}")
196+
if let parsableType = Self.self as? SyntaxParseable.Type {
197+
decl = parsableType.init(stringInterpolation: stringInterpolation).cast(DeclSyntax.self)
198+
} else {
199+
decl = DeclSyntax(stringInterpolation: stringInterpolation)
200+
}
174201
guard let castedDecl = decl.as(Self.self) else {
175202
throw SyntaxStringInterpolationInvalidNodeTypeError(expectedType: Self.self, actualNode: decl)
176203
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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 AccessorDeclTests: XCTestCase {
18+
func testCreateAccessorWithHeaderAndBody() throws {
19+
let accessor = try AccessorDeclSyntax("get") {
20+
ExprSyntax("1")
21+
}
22+
XCTAssertEqual(accessor.body?.statements.count, 1)
23+
}
24+
}

0 commit comments

Comments
 (0)