Skip to content

Commit 40af9ef

Browse files
committed
Update CodeGeneration to latest SwiftSyntax version
This updates the version lock of CodeGeneration to the latest SwiftSyntax version. CodeGeneration still relies quite a bit on raw string interpolation. I’m hoping that we can remove some of these if we stop generating the node definitions using gyb and can thus improve the underlying data structure in the SyntaxSupport module.
1 parent 6e3dfb3 commit 40af9ef

File tree

17 files changed

+824
-93
lines changed

17 files changed

+824
-93
lines changed

CodeGeneration/Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ let package = Package(
1313
.executable(name: "generate-swiftsyntaxbuilder", targets: ["generate-swiftsyntaxbuilder"]),
1414
],
1515
dependencies: [
16-
.package(url: "https://github.com/apple/swift-syntax.git", revision: "5e9dcce1dc5c81e48b658ced23f0848be4671a0c"),
16+
.package(url: "https://github.com/apple/swift-syntax.git", revision: "6e3dfb332553ad1462f0a3d45b4d91e349ce4013"),
1717
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "1.1.4")),
1818
],
1919
targets: [

CodeGeneration/Sources/Utils/CodeGenerationFormat.swift

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,27 @@ import SwiftSyntax
1717
public class CodeGenerationFormat: BasicFormat {
1818
public override var indentation: TriviaPiece { .spaces(indentationLevel * 2) }
1919

20+
public func ensuringTwoLeadingNewlines<NodeType: SyntaxProtocol>(node: NodeType) -> NodeType {
21+
if node.leadingTrivia?.first?.isNewline ?? false {
22+
return node.withLeadingTrivia(indentedNewline + (node.leadingTrivia ?? []))
23+
} else {
24+
return node.withLeadingTrivia(indentedNewline + indentedNewline + (node.leadingTrivia ?? []))
25+
}
26+
}
27+
2028
public override func visit(_ node: MemberDeclListItemSyntax) -> MemberDeclListItemSyntax {
2129
let formatted = super.visit(node)
22-
return formatted.withLeadingTrivia(indentedNewline + (formatted.leadingTrivia ?? []))
30+
if node.indexInParent != 0 {
31+
return ensuringTwoLeadingNewlines(node: formatted)
32+
} else {
33+
return formatted
34+
}
2335
}
2436

2537
public override func visit(_ node: CodeBlockItemSyntax) -> CodeBlockItemSyntax {
2638
if node.parent?.parent?.is(SourceFileSyntax.self) == true, !node.item.is(ImportDeclSyntax.self) {
2739
let formatted = super.visit(node)
28-
return formatted.withLeadingTrivia(indentedNewline + indentedNewline + (formatted.leadingTrivia ?? []))
40+
return ensuringTwoLeadingNewlines(node: formatted)
2941
} else {
3042
return super.visit(node)
3143
}

CodeGeneration/Sources/Utils/SyntaxBuildableChild.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public extension Child {
3535
}
3636

3737
var parameterType: Type {
38-
return self.type.optionalWrapped(type: Type(parameterBaseType))
38+
return self.type.optionalWrapped(type: SimpleTypeIdentifier(name: .identifier(parameterBaseType)))
3939
}
4040

4141
/// If the child node has documentation associated with it, return it as single
@@ -74,7 +74,7 @@ public extension Child {
7474
}
7575
for textChoice in choices {
7676
assertChoices.append(Expr(SequenceExpr {
77-
MemberAccessExpr(base: type.forceUnwrappedIfNeeded(expr: Expr(varName)), name: "text")
77+
MemberAccessExpr(base: type.forceUnwrappedIfNeeded(expr: IdentifierExpr(identifier: .identifier(varName))), name: "text")
7878
BinaryOperatorExpr(text: "==")
7979
StringLiteralExpr(content: textChoice)
8080
}))

CodeGeneration/Sources/Utils/SyntaxBuildableType.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public struct SyntaxBuildableType: Hashable {
8787
/// - For token: `TokenSyntax` (tokens don't have a dedicated type in SwiftSyntaxBuilder)
8888
/// If the type is optional, the type is wrapped in an `OptionalType`.
8989
public var buildable: Type {
90-
optionalWrapped(type: Type(shorthandName))
90+
optionalWrapped(type: SimpleTypeIdentifier(name: .identifier(shorthandName)))
9191
}
9292

9393
/// Whether parameters of this type should be initializable by a result builder.
@@ -126,7 +126,7 @@ public struct SyntaxBuildableType: Hashable {
126126
/// which will eventually get built from `SwiftSyntaxBuilder`. If the type
127127
/// is optional, this terminates with a `?`.
128128
public var syntax: TypeSyntax {
129-
return optionalWrapped(type: TypeSyntax(syntaxBaseName))
129+
return optionalWrapped(type: SimpleTypeIdentifier(name: .identifier(syntaxBaseName)))
130130
}
131131

132132
/// The type that is used for paramters in SwiftSyntaxBuilder that take this
@@ -140,7 +140,7 @@ public struct SyntaxBuildableType: Hashable {
140140
}
141141

142142
public var parameterType: TypeSyntax {
143-
return optionalWrapped(type: TypeSyntax(parameterBaseType))
143+
return optionalWrapped(type: SimpleTypeIdentifier(name: .identifier(parameterBaseType)))
144144
}
145145

146146
/// Assuming that this is a collection type, the non-optional type of the result builder
@@ -165,7 +165,7 @@ public struct SyntaxBuildableType: Hashable {
165165
}
166166

167167
/// Wraps a type in an optional depending on whether `isOptional` is true.
168-
public func optionalWrapped(type: TypeSyntaxProtocol) -> TypeSyntax {
168+
public func optionalWrapped<TypeNode: TypeSyntaxProtocol>(type: TypeNode) -> TypeSyntax {
169169
if isOptional {
170170
return TypeSyntax(OptionalType(wrappedType: type))
171171
} else {

CodeGeneration/Sources/generate-swiftbasicformat/BasicFormatFile.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ let basicFormatFile = SourceFile {
8080
SwitchStmt(expression: Expr("keyPath")) {
8181
for node in SYNTAX_NODES where !node.isBase {
8282
for child in node.children where child.isIndented {
83-
SwitchCase("case \\\(node.type.syntaxBaseName).\(child.swiftName):") {
83+
SwitchCase("case \\\(raw: node.type.syntaxBaseName).\(raw: child.swiftName):") {
8484
ReturnStmt("return true")
8585
}
8686
}
@@ -95,7 +95,7 @@ let basicFormatFile = SourceFile {
9595
SwitchStmt(expression: Expr("keyPath")) {
9696
for node in SYNTAX_NODES where !node.isBase {
9797
for child in node.children where child.requiresLeadingNewline {
98-
SwitchCase("case \\\(node.type.syntaxBaseName).\(child.swiftName):") {
98+
SwitchCase("case \\\(raw: node.type.syntaxBaseName).\(raw: child.swiftName):") {
9999
ReturnStmt("return true")
100100
}
101101
}
@@ -110,7 +110,7 @@ let basicFormatFile = SourceFile {
110110
SwitchStmt(expression: Expr("node.as(SyntaxEnum.self)")) {
111111
for node in SYNTAX_NODES where !node.isBase {
112112
if node.elementsSeparatedByNewline {
113-
SwitchCase("case .\(node.swiftSyntaxKind):") {
113+
SwitchCase("case .\(raw: node.swiftSyntaxKind):") {
114114
ReturnStmt("return true")
115115
}
116116
}
@@ -125,7 +125,7 @@ let basicFormatFile = SourceFile {
125125
SwitchStmt(expression: Expr("tokenKind")) {
126126
for token in SYNTAX_TOKENS {
127127
if token.requiresLeadingSpace {
128-
SwitchCase("case .\(token.swiftKind):") {
128+
SwitchCase("case .\(raw: token.swiftKind):") {
129129
ReturnStmt("return true")
130130
}
131131
}
@@ -140,7 +140,7 @@ let basicFormatFile = SourceFile {
140140
SwitchStmt(expression: Expr("tokenKind")) {
141141
for token in SYNTAX_TOKENS {
142142
if token.requiresTrailingSpace {
143-
SwitchCase("case .\(token.swiftKind):") {
143+
SwitchCase("case .\(raw: token.swiftKind):") {
144144
ReturnStmt("return true")
145145
}
146146
}
@@ -178,7 +178,7 @@ private func createChildVisitCall(childType: SyntaxBuildableType, rewrittenExpr:
178178
}
179179
if childType.baseType?.baseName != "Syntax", childType.baseType?.isSyntaxCollection != true, childType.baseType != nil {
180180
let optionalChained = childType.optionalChained(expr: visitCall)
181-
return FunctionCallExpr("\(optionalChained).cast(\(childType.syntaxBaseName).self)")
181+
return FunctionCallExpr("\(optionalChained).cast(\(raw: childType.syntaxBaseName).self)")
182182
} else {
183183
return visitCall
184184
}
@@ -193,7 +193,7 @@ private func makeSyntaxCollectionRewriteFunc(node: Node) -> FunctionDecl {
193193
let formattedChildrenVarLet = node.elementsSeparatedByNewline ? "var" : "let"
194194
VariableDecl(
195195
"""
196-
\(formattedChildrenVarLet) formattedChildren = node.map {
196+
\(raw: formattedChildrenVarLet) formattedChildren = node.map {
197197
\(createChildVisitCall(childType: node.collectionElementType, rewrittenExpr: IdentifierExpr(identifier: .dollarIdentifier("$0"))))
198198
}
199199
"""
@@ -211,7 +211,7 @@ private func makeSyntaxCollectionRewriteFunc(node: Node) -> FunctionDecl {
211211
"""
212212
)
213213
}
214-
ReturnStmt("return \(node.type.syntaxBaseName)(formattedChildren)")
214+
ReturnStmt("return \(raw: node.type.syntaxBaseName)(formattedChildren)")
215215
}
216216
}
217217

CodeGeneration/Sources/generate-swiftideutils/SyntaxClassificationFile.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ var node_child_classifications: [ChildClassification] {
3232
let syntaxClassificationFile = SourceFile {
3333
ImportDecl(
3434
"""
35-
\(generateCopyrightHeader(for: "generate-ideutils"))
35+
\(raw: generateCopyrightHeader(for: "generate-ideutils"))
3636
@_spi(RawSyntax) import SwiftSyntax
3737
"""
3838
)
@@ -41,8 +41,8 @@ let syntaxClassificationFile = SourceFile {
4141
for classification in SYNTAX_CLASSIFICATIONS {
4242
EnumCaseDecl(
4343
"""
44-
/// \(classification.description)
45-
case \(classification.swiftName)
44+
/// \(raw: classification.description)
45+
case \(raw: classification.swiftName)
4646
"""
4747
)
4848
}
@@ -70,8 +70,8 @@ let syntaxClassificationFile = SourceFile {
7070
) {
7171
SwitchStmtSyntax(expression: ExprSyntax("(parentKind, indexInParent)")) {
7272
for childClassification in node_child_classifications where childClassification.isToken {
73-
SwitchCaseSyntax("case (.\(childClassification.parent.swiftSyntaxKind), \(childClassification.childIndex)):") {
74-
ReturnStmt("return (.\(childClassification.classification!.swiftName), \(childClassification.force))")
73+
SwitchCaseSyntax("case (.\(raw: childClassification.parent.swiftSyntaxKind), \(raw: childClassification.childIndex)):") {
74+
ReturnStmt("return (.\(raw: childClassification.classification!.swiftName), \(raw: childClassification.force))")
7575
}
7676
}
7777

@@ -80,8 +80,8 @@ let syntaxClassificationFile = SourceFile {
8080
} elseBody: {
8181
SwitchStmtSyntax(expression: ExprSyntax("(parentKind, indexInParent)")) {
8282
for childClassification in node_child_classifications where !childClassification.isToken {
83-
SwitchCaseSyntax("case (.\(childClassification.parent.swiftSyntaxKind), \(childClassification.childIndex)):") {
84-
ReturnStmt("return (.\(childClassification.classification!.swiftName), \(childClassification.force))")
83+
SwitchCaseSyntax("case (.\(raw: childClassification.parent.swiftSyntaxKind), \(raw: childClassification.childIndex)):") {
84+
ReturnStmt("return (.\(raw: childClassification.classification!.swiftName), \(raw: childClassification.force))")
8585
}
8686
}
8787

@@ -98,9 +98,9 @@ let syntaxClassificationFile = SourceFile {
9898
type: TypeAnnotation(type: TypeSyntax("SyntaxClassification"))) {
9999
SwitchStmt(expression: ExprSyntax("self")) {
100100
for token in SYNTAX_TOKENS {
101-
SwitchCaseSyntax("case .\(token.swiftKind):") {
101+
SwitchCaseSyntax("case .\(raw: token.swiftKind):") {
102102
if let classification = token.classification {
103-
ReturnStmt("return .\(classification.swiftName)")
103+
ReturnStmt("return .\(raw: classification.swiftName)")
104104
} else {
105105
ReturnStmt("return .none)")
106106
}

CodeGeneration/Sources/generate-swiftsyntaxbuilder/BuildableCollectionNodesFile.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ let buildableCollectionNodesFile = SourceFile {
3333
InitializerDecl(
3434
"""
3535
public init(_ elements: \(ArrayType(elementType: elementType.parameterType))) {
36-
self = \(node.type.syntaxBaseName)(elements.map { \(elementType.syntax)(fromProtocol: $0) })
36+
self = \(raw: node.type.syntaxBaseName)(elements.map { \(elementType.syntax)(fromProtocol: $0) })
3737
}
3838
"""
3939
)

CodeGeneration/Sources/generate-swiftsyntaxbuilder/BuildableNodesFile.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ let buildableNodesFile = SourceFile {
2828
let docComment: SwiftSyntax.Trivia = node.documentation.isEmpty ? [] : .docLineComment("/// \(node.documentation)") + .newline
2929
ExtensionDecl(
3030
leadingTrivia: docComment,
31-
extendedType: Type(type.shorthandName),
31+
extendedType: SimpleTypeIdentifier(name: .identifier(type.shorthandName)),
3232
inheritanceClause: hasTrailingComma ? TypeInheritanceClause { InheritedType(typeName: Type("HasTrailingComma")) } : nil
3333
) {
3434
// Generate initializers
@@ -61,9 +61,9 @@ let buildableNodesFile = SourceFile {
6161

6262
private func convertFromSyntaxProtocolToSyntaxType(child: Child) -> Expr {
6363
if child.type.isBaseType && child.nodeChoices.isEmpty {
64-
return Expr(FunctionCallExpr("\(child.type.syntaxBaseName)(fromProtocol: \(child.swiftName))"))
64+
return Expr(FunctionCallExpr("\(raw: child.type.syntaxBaseName)(fromProtocol: \(raw: child.swiftName))"))
6565
} else {
66-
return Expr(IdentifierExpr(child.swiftName))
66+
return Expr(IdentifierExpr(identifier: .identifier(child.swiftName)))
6767
}
6868
}
6969

@@ -104,7 +104,7 @@ private func createDefaultInitializer(node: Node) -> InitializerDecl {
104104
assertStmt
105105
}
106106
}
107-
let nodeConstructorCall = FunctionCallExpr(callee: type.syntaxBaseName) {
107+
let nodeConstructorCall = FunctionCallExpr(callee: Expr(IdentifierExpr(identifier: .identifier(type.syntaxBaseName)))) {
108108
for child in node.children {
109109
TupleExprElement(
110110
label: child.isUnexpectedNodes ? nil : child.swiftName,
@@ -141,12 +141,12 @@ private func createConvenienceInitializer(node: Node) -> InitializerDecl? {
141141
if child.type.builderInitializableType != child.type {
142142
let param = Node.from(type: child.type).singleNonDefaultedChild
143143
if child.isOptional {
144-
produceExpr = Expr(FunctionCallExpr("\(child.swiftName)Builder().map { \(child.type.syntaxBaseName)(\(param.swiftName): $0) }"))
144+
produceExpr = Expr(FunctionCallExpr("\(raw: child.swiftName)Builder().map { \(raw: child.type.syntaxBaseName)(\(raw: param.swiftName): $0) }"))
145145
} else {
146-
produceExpr = Expr(FunctionCallExpr("\(child.type.syntaxBaseName)(\(param.swiftName): \(child.swiftName)Builder())"))
146+
produceExpr = Expr(FunctionCallExpr("\(raw: child.type.syntaxBaseName)(\(raw: param.swiftName): \(raw: child.swiftName)Builder())"))
147147
}
148148
} else {
149-
produceExpr = Expr(FunctionCallExpr("\(child.swiftName)Builder()"))
149+
produceExpr = Expr(FunctionCallExpr("\(raw: child.swiftName)Builder()"))
150150
}
151151
let defaultArgument = ClosureExpr {
152152
if child.type.isOptional {
@@ -163,11 +163,11 @@ private func createConvenienceInitializer(node: Node) -> InitializerDecl? {
163163
// Allow initializing identifiers and other tokens without default text with a String
164164
shouldCreateInitializer = true
165165
let paramType = child.type.optionalWrapped(type: Type("String"))
166-
let tokenExpr = MemberAccessExpr("Token.\(token.swiftKind.withFirstCharacterLowercased.backticked)")
166+
let tokenExpr = MemberAccessExpr("Token.\(raw: token.swiftKind.withFirstCharacterLowercased.backticked)")
167167
if child.type.isOptional {
168-
produceExpr = Expr(FunctionCallExpr("\(child.swiftName).map { \(tokenExpr)($0) }"))
168+
produceExpr = Expr(FunctionCallExpr("\(raw: child.swiftName).map { \(tokenExpr)($0) }"))
169169
} else {
170-
produceExpr = Expr(FunctionCallExpr("\(tokenExpr)(\(child.swiftName))"))
170+
produceExpr = Expr(FunctionCallExpr("\(tokenExpr)(\(raw: child.swiftName))"))
171171
}
172172
normalParameters.append(FunctionParameter("\(child.swiftName): \(paramType)", for: .functionParameters))
173173
} else {

CodeGeneration/Sources/generate-swiftsyntaxbuilder/ResultBuildersFile.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ let resultBuildersFile = SourceFile {
7878
"""
7979
/// If declared, provides contextual type information for statement
8080
/// expressions to translate them into partial results.
81-
public static func buildExpression(_ expression: \(elementChoice)) -> Self.Component {
81+
public static func buildExpression(_ expression: \(raw: elementChoice)) -> Self.Component {
8282
return buildExpression(.init(expression))
8383
}
8484
"""
@@ -168,8 +168,8 @@ let resultBuildersFile = SourceFile {
168168

169169
ExtensionDecl(
170170
"""
171-
public extension \(type.shorthandName) {
172-
init(@\(type.resultBuilderBaseName) itemsBuilder: () -> \(type.shorthandName)) {
171+
public extension \(raw: type.shorthandName) {
172+
init(@\(raw: type.resultBuilderBaseName) itemsBuilder: () -> \(raw: type.shorthandName)) {
173173
self = itemsBuilder()
174174
}
175175
}

CodeGeneration/Sources/generate-swiftsyntaxbuilder/TokenFile.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,17 @@ let tokenFile = SourceFile {
2525
for token in SYNTAX_TOKENS {
2626
if token.isKeyword {
2727
VariableDecl("""
28-
/// The `\(token.text!)` keyword
29-
static var \(token.name.withFirstCharacterLowercased.backticked): Token {
30-
return .\(token.swiftKind)()
28+
/// The `\(raw: token.text!)` keyword
29+
static var \(raw: token.name.withFirstCharacterLowercased.backticked): Token {
30+
return .\(raw: token.swiftKind)()
3131
}
3232
"""
3333
)
3434
} else if let text = token.text {
3535
VariableDecl("""
36-
/// The `\(text)` token
37-
static var \(token.name.withFirstCharacterLowercased.backticked): TokenSyntax {
38-
return .\(token.swiftKind)Token()
36+
/// The `\(raw: text)` token
37+
static var \(raw: token.name.withFirstCharacterLowercased.backticked): TokenSyntax {
38+
return .\(raw: token.swiftKind)Token()
3939
}
4040
"""
4141
)

CodeGeneration/Sources/generate-swiftsyntaxbuilder/TypealiasesFile.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,6 @@ let typealiasesFile = SourceFile {
2525
TypealiasDecl("public typealias Token = TokenSyntax")
2626

2727
for node in SYNTAX_NODES where !node.isUnknown && !node.isMissing {
28-
TypealiasDecl("public typealias \(node.type.shorthandName) = \(node.type.syntaxBaseName)")
28+
TypealiasDecl("public typealias \(raw: node.type.shorthandName) = \(raw: node.type.syntaxBaseName)")
2929
}
3030
}

Sources/IDEUtils/generated/SyntaxClassification.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,40 +19,58 @@
1919
public enum SyntaxClassification {
2020
/// The token should not receive syntax coloring.
2121
case none
22+
2223
/// A Swift keyword, including contextual keywords.
2324
case keyword
25+
2426
/// A generic identifier.
2527
case identifier
28+
2629
/// An identifier referring to a type.
2730
case typeIdentifier
31+
2832
/// An identifier referring to an operator.
2933
case operatorIdentifier
34+
3035
/// An identifier starting with `$` like `$0`.
3136
case dollarIdentifier
37+
3238
/// An integer literal.
3339
case integerLiteral
40+
3441
/// A floating point literal.
3542
case floatingLiteral
43+
3644
/// A string literal including multiline string literals.
3745
case stringLiteral
46+
3847
/// The opening and closing parenthesis of string interpolation.
3948
case stringInterpolationAnchor
49+
4050
/// A `#` keyword like `#warning`.
4151
case poundDirectiveKeyword
52+
4253
/// A build configuration directive like `#if`, `#elseif`, `#else`.
4354
case buildConfigId
55+
4456
/// An attribute starting with an `@`.
4557
case attribute
58+
4659
/// An image, color, etc. literal.
4760
case objectLiteral
61+
4862
/// An editor placeholder of the form `<#content#>`
4963
case editorPlaceholder
64+
5065
/// A line comment starting with `//`.
5166
case lineComment
67+
5268
/// A doc line comment starting with `///`.
5369
case docLineComment
70+
5471
/// A block comment starting with `/**` and ending with `*/.
5572
case blockComment
73+
5674
/// A doc block comment starting with `/**` and ending with `*/.
5775
case docBlockComment
5876
}

0 commit comments

Comments
 (0)