@@ -103,26 +103,57 @@ private extension Trivia {
103
103
}
104
104
}
105
105
106
+ #if DEBUG
107
+ /// We call into the Swift runtime to get the fully-qualified description of a
108
+ /// type name in `debugInitCall`. This is fine-ish for two reaons:
109
+ /// - The runtime is part of the ABI and is thus stable
110
+ /// - We are only using this in a debug function that shouldn’t be called in
111
+ /// any production app.
112
+ @_silgen_name ( " swift_getTypeName " )
113
+ private func _getTypeName( _ type: Any . Type , qualified: Bool ) -> ( UnsafePointer < UInt8 > , Int )
114
+
115
+ private func getTypeName( _ type: Any . Type , qualified: Bool ) -> String ? {
116
+ let typeName = _getTypeName ( type, qualified: true )
117
+ let buffer = UnsafeBufferPointer ( start: typeName. 0 , count: typeName. 1 )
118
+ return String ( decoding: buffer, as: UTF8 . self)
119
+ }
120
+
106
121
extension SyntaxProtocol {
107
122
/// Returns a Swift expression that, when parsed, constructs this syntax node
108
123
/// (or at least an expression that's very close to constructing this node, the addition of a few manual upcast by hand is still needed).
109
124
/// The intended use case for this is to print a syntax tree and create a substructure assertion from the generated expression.
110
125
/// When `includeTrivia` is set to `false`, the token's leading and trailing trivia will not be included in the generated expression.
126
+ ///
127
+ /// - Warning: This is only designed for use in the debugger. Do not call it outside of the debugger.
128
+ @available ( * , deprecated, message: " For use in debugger only " )
111
129
public func debugInitCall( includeTrivia: Bool = true ) -> String {
112
130
return self . debugInitCallExpr ( includeTrivia: includeTrivia) . formatted ( using: InitializerExprFormat ( ) ) . description
113
131
}
114
132
115
133
private func debugInitCallExpr( includeTrivia: Bool ) -> ExprSyntax {
116
- let mirror = Mirror ( reflecting: self )
117
- if self . kind. isSyntaxCollection {
134
+ if type ( of: self ) != self . syntaxNodeType {
135
+ let nestedInitCall = Syntax ( self ) . asProtocol ( SyntaxProtocol . self) . debugInitCallExpr ( includeTrivia: includeTrivia)
136
+ if var typeName = getTypeName ( type ( of: self ) , qualified: true ) {
137
+ if typeName. hasPrefix ( " SwiftSyntax. " ) {
138
+ typeName = String ( typeName. dropFirst ( " SwiftSyntax. " . count) )
139
+ }
140
+ return ExprSyntax (
141
+ FunctionCallExprSyntax ( callee: ExprSyntax ( " \( raw: typeName) " ) ) {
142
+ TupleExprElementSyntax ( expression: nestedInitCall)
143
+ }
144
+ )
145
+ }
146
+ return nestedInitCall
147
+ }
148
+
149
+ if case . collection( let collectionElementType) = self . syntaxNodeType. structure {
118
150
let typeName = String ( describing: type ( of: self ) )
119
151
return ExprSyntax (
120
152
FunctionCallExprSyntax ( callee: IdentifierExprSyntax ( identifier: . identifier( typeName) ) ) {
121
153
TupleExprElementSyntax (
122
154
expression: ArrayExprSyntax {
123
- for child in mirror. children {
124
- let value = child. value as! SyntaxProtocol ?
125
- ArrayElementSyntax ( expression: value? . debugInitCallExpr ( includeTrivia: includeTrivia) ?? ExprSyntax ( NilLiteralExprSyntax ( ) ) )
155
+ for child in self . children ( viewMode: . all) {
156
+ ArrayElementSyntax ( expression: child. as ( collectionElementType) !. debugInitCallExpr ( includeTrivia: includeTrivia) )
126
157
}
127
158
}
128
159
)
@@ -132,12 +163,12 @@ extension SyntaxProtocol {
132
163
let tokenKind = token. tokenKind
133
164
let tokenInitializerName : String
134
165
let tokenKindArgument : ExprSyntax ?
135
- if tokenKind. isLexerClassifiedKeyword || tokenKind == . eof {
136
- tokenInitializerName = String ( describing: tokenKind)
137
- tokenKindArgument = nil
138
- } else if case . keyword( let keyword) = tokenKind {
166
+ if case . keyword( let keyword) = tokenKind {
139
167
tokenInitializerName = " keyword "
140
168
tokenKindArgument = ExprSyntax ( " . \( raw: keyword) " )
169
+ } else if tokenKind. isLexerClassifiedKeyword || tokenKind == . eof {
170
+ tokenInitializerName = String ( describing: tokenKind)
171
+ tokenKindArgument = nil
141
172
} else if tokenKind. decomposeToRaw ( ) . rawKind. defaultText != nil {
142
173
tokenInitializerName = " \( String ( describing: tokenKind) ) Token "
143
174
tokenKindArgument = nil
@@ -174,15 +205,15 @@ extension SyntaxProtocol {
174
205
}
175
206
}
176
207
)
177
- } else {
208
+ } else if case . layout ( let layout ) = self . syntaxNodeType . structure {
178
209
let typeName = String ( describing: type ( of: self ) )
179
210
return ExprSyntax (
180
211
FunctionCallExprSyntax ( callee: IdentifierExprSyntax ( identifier: . identifier( typeName) ) ) {
181
- for child in mirror . children {
182
- let label = child . label!
183
- let value = child . value as! SyntaxProtocol ?
212
+ for keyPath in layout {
213
+ let label = childName ( keyPath ) ?? " "
214
+ let value = self [ keyPath : keyPath as! PartialKeyPath < Self > ] as! SyntaxProtocol ?
184
215
let isUnexpected = label. hasPrefix ( " unexpected " )
185
- if !isUnexpected || value != nil {
216
+ if value != nil {
186
217
TupleExprElementSyntax (
187
218
label: isUnexpected ? nil : . identifier( label) ,
188
219
colon: isUnexpected ? nil : . colonToken( ) ,
@@ -192,6 +223,10 @@ extension SyntaxProtocol {
192
223
}
193
224
}
194
225
)
226
+ } else {
227
+ fatalError ( )
195
228
}
196
229
}
197
230
}
231
+
232
+ #endif
0 commit comments