@@ -4,6 +4,9 @@ import SwiftDiagnostics
4
4
5
5
public struct DebugDescriptionMacro { }
6
6
7
+ /// Attached peer macro which converts `debugDescription` (or `description`) implementations into
8
+ /// an LLDB type summary. The type summary record is emitted into a custom section (via a global
9
+ /// constant), where LLDB will load from at debug time.
7
10
extension DebugDescriptionMacro : PeerMacro {
8
11
public static func expansion< Decl, Context> (
9
12
of node: AttributeSyntax ,
@@ -114,7 +117,7 @@ extension DebugDescriptionMacro: PeerMacro {
114
117
@unknown default :
115
118
return [ ]
116
119
}
117
- }
120
+ }
118
121
119
122
let summaryString = summarySegments. joined ( )
120
123
@@ -152,7 +155,7 @@ extension DebugDescriptionMacro: PeerMacro {
152
155
153
156
// MARK: - Diagnostics
154
157
155
- struct ErrorMessage : DiagnosticMessage , ExpressibleByStringInterpolation {
158
+ private struct ErrorMessage : DiagnosticMessage , ExpressibleByStringInterpolation {
156
159
init ( stringLiteral value: String ) {
157
160
self . message = value
158
161
}
@@ -229,8 +232,8 @@ private func isComputedProperty(_ binding: PatternBindingSyntax) -> Bool {
229
232
// Enumerate a MemberAccess expression to produce DeclReferences in left to right order.
230
233
// `a.b.c` will result in callbacks for each DeclReference `a`, `b`, and then `c`.
231
234
private func enumerateMembers( _ memberAccess: MemberAccessExprSyntax , _ action: ( DeclReferenceExprSyntax ) -> Void ) {
232
- if let baseMembers = memberAccess. base? . as ( MemberAccessExprSyntax . self) {
233
- enumerateMembers ( baseMembers , action)
235
+ if let baseMember = memberAccess. base? . as ( MemberAccessExprSyntax . self) {
236
+ enumerateMembers ( baseMember , action)
234
237
} else if let baseDecl = memberAccess. base? . as ( DeclReferenceExprSyntax . self) {
235
238
action ( baseDecl)
236
239
}
@@ -239,6 +242,18 @@ private func enumerateMembers(_ memberAccess: MemberAccessExprSyntax, _ action:
239
242
240
243
// MARK: - Encoding
241
244
245
+ /// Construct an LLDB type summary record.
246
+ ///
247
+ /// The record is serializeed as a tuple of `UInt8` bytes.
248
+ ///
249
+ /// The record contains the following:
250
+ /// * Version number of the record format
251
+ /// * The size of the record (encoded as ULEB)
252
+ /// * The type identifier, which is either a type name, or for generic types a type regex
253
+ /// * The description string converted to an LLDB summary string
254
+ ///
255
+ /// The strings (type identifier and summary) are encoded with both a length prefix (also ULEB)
256
+ /// and with a null terminator.
242
257
private func encodeTypeSummaryRecord( _ typeIdentifier: String , _ summaryString: String ) -> String {
243
258
let encodedType = encodeString ( typeIdentifier)
244
259
let encodedSummary = encodeString ( summaryString)
@@ -251,19 +266,23 @@ private func encodeTypeSummaryRecord(_ typeIdentifier: String, _ summaryString:
251
266
"""
252
267
}
253
268
269
+ /// Generate a _partial_ Swift literal from the given bytes. It is partial in that must be embedded
270
+ /// into some other syntax, specifically as a tuple.
254
271
private func literalBytes( _ bytes: [ UInt8 ] ) -> String {
255
272
bytes. map ( { " \( $0) as UInt8 " } ) . joined ( separator: " , " )
256
273
}
257
274
275
+ /// Encode a string into UTF8 bytes, prefixed by a ULEB length, and suffixed by the null terminator.
258
276
private func encodeString( _ string: String ) -> [ UInt8 ] {
259
277
let size = UInt ( string. utf8. count) + 1 // including null terminator
260
278
var bytes : [ UInt8 ] = [ ]
261
279
bytes. append ( contentsOf: encodeULEB ( size) )
262
- bytes. append ( contentsOf: Array ( string. utf8) )
280
+ bytes. append ( contentsOf: string. utf8)
263
281
bytes. append ( 0 ) // null terminator
264
282
return bytes
265
283
}
266
284
285
+ /// Encode an unsigned integer into ULEB format. See https://en.wikipedia.org/wiki/LEB128
267
286
private func encodeULEB( _ value: UInt ) -> [ UInt8 ] {
268
287
guard value > 0 else {
269
288
return [ 0 ]
@@ -285,6 +304,8 @@ private func encodeULEB(_ value: UInt) -> [UInt8] {
285
304
// MARK: - Extensions
286
305
287
306
extension Collection {
307
+ /// Convert a single element collection to a single value. When a collection consists of
308
+ /// multiple elements, nil is returned.
288
309
fileprivate var single : Element ? {
289
310
count == 1 ? first : nil
290
311
}
0 commit comments