Skip to content

Commit 3a43e7d

Browse files
authored
[Debug] Fix regex type names in DebugDescriptionMacro (#71379)
Fixes the way `DebugDescriptionMacro` produces a regex type name. The problem was use of backslash escapes that weren't sufficiently escaped. They needed to be double escaped. To avoid this trap, the regexes now use `[.]` to match a dot, instead of the more conventional `\.` syntax.
1 parent 55af87f commit 3a43e7d

File tree

2 files changed

+34
-4
lines changed

2 files changed

+34
-4
lines changed

lib/Macros/Sources/SwiftMacros/DebugDescriptionMacro.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,19 @@ extension DebugDescriptionMacro: MemberAttributeMacro {
7171
return []
7272
}
7373

74+
// Warning: To use a backslash escape in `typeIdentifier`, it needs to be double escaped. This is because
75+
// the string is serialized to a String literal (an argument to `@_DebugDescriptionProperty`), which
76+
// effectively "consumes" one level of escaping. To avoid mistakes, dots are matched with `[.]` instead
77+
// of the more conventional `\.`.
7478
var typeIdentifier: String
7579
if let typeParameters = declaration.asProtocol(WithGenericParametersSyntax.self)?.genericParameterClause?.parameters, typeParameters.count > 0 {
7680
let typePatterns = Array(repeating: ".+", count: typeParameters.count).joined(separator: ",")
7781
// A regex matching that matches the generic type.
78-
typeIdentifier = "^\(moduleName)\\.\(typeName)<\(typePatterns)>"
82+
typeIdentifier = "^\(moduleName)[.]\(typeName)<\(typePatterns)>"
7983
} else if declaration.is(ExtensionDeclSyntax.self) {
8084
// When attached to an extension, the type may or may not be a generic type.
8185
// This regular expression handles both cases.
82-
typeIdentifier = "^\(moduleName)\\.\(typeName)(<.+>)?$"
86+
typeIdentifier = "^\(moduleName)[.]\(typeName)(<.+>)?$"
8387
} else {
8488
typeIdentifier = "\(moduleName).\(typeName)"
8589
}
@@ -249,7 +253,7 @@ fileprivate let ENCODING_VERSION: UInt = 1
249253

250254
/// Construct an LLDB type summary record.
251255
///
252-
/// The record is serializeed as a tuple of `UInt8` bytes.
256+
/// The record is serialized as a tuple of `UInt8` bytes.
253257
///
254258
/// The record contains the following:
255259
/// * Version number of the record format
@@ -352,7 +356,7 @@ extension DeclGroupSyntax {
352356
case .actorDecl, .classDecl, .enumDecl, .structDecl:
353357
return self.asProtocol(NamedDeclSyntax.self)?.name.text
354358
case .extensionDecl:
355-
return self.as(ExtensionDeclSyntax.self)?.extendedType.description
359+
return self.as(ExtensionDeclSyntax.self)?.extendedType.trimmedDescription
356360
default:
357361
// New types of decls are not presumed to be valid.
358362
return nil
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// REQUIRES: swift_swift_parser
2+
3+
// RUN: %empty-directory(%t)
4+
// RUN: %target-swift-frontend %s -swift-version 5 -module-name main -disable-availability-checking -typecheck -enable-experimental-feature SymbolLinkageMarkers -plugin-path %swift-plugin-dir -dump-macro-expansions > %t/expansions-dump.txt 2>&1
5+
// RUN: %FileCheck %s < %t/expansions-dump.txt
6+
7+
struct MyStruct {}
8+
9+
@_DebugDescription
10+
extension MyStruct {
11+
var debugDescription: String { "thirty" }
12+
}
13+
// CHECK: #if os(Linux)
14+
// CHECK: @_section(".lldbsummaries")
15+
// CHECK: #elseif os(Windows)
16+
// CHECK: @_section(".lldbsummaries")
17+
// CHECK: #else
18+
// CHECK: @_section("__DATA_CONST,__lldbsummaries")
19+
// CHECK: #endif
20+
// CHECK: @_used
21+
// CHECK: static let _lldb_summary = (
22+
// CHECK: /* version */ 1 as UInt8,
23+
// CHECK: /* record size */ 34 as UInt8,
24+
// CHECK: /* "^main[.]MyStruct(<.+>)?$" */ 25 as UInt8, 94 as UInt8, 109 as UInt8, 97 as UInt8, 105 as UInt8, 110 as UInt8, 91 as UInt8, 46 as UInt8, 93 as UInt8, 77 as UInt8, 121 as UInt8, 83 as UInt8, 116 as UInt8, 114 as UInt8, 117 as UInt8, 99 as UInt8, 116 as UInt8, 40 as UInt8, 60 as UInt8, 46 as UInt8, 43 as UInt8, 62 as UInt8, 41 as UInt8, 63 as UInt8, 36 as UInt8, 0 as UInt8,
25+
// CHECK: /* "thirty" */ 7 as UInt8, 116 as UInt8, 104 as UInt8, 105 as UInt8, 114 as UInt8, 116 as UInt8, 121 as UInt8, 0 as UInt8
26+
// CHECK: )

0 commit comments

Comments
 (0)