Skip to content

Commit c4c4498

Browse files
committed
add additional SwiftSyntax logic that monkey-patches the upsteam bug swiftlang/swift#78343
1 parent fa523c7 commit c4c4498

File tree

12 files changed

+205
-103
lines changed

12 files changed

+205
-103
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
/Assets/secrets/
1717
/Assets/icons/*.jpg
1818

19+
/TestModules/SymbolGraphs/*.json
1920
/TestModules/*.json
2021
/TestPackages/*.bson
2122
/TypeScript/node_modules

Sources/MarkdownPluginSwift/Signatures/Signature.Abridged (ext).swift

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,13 @@ extension Signature.Abridged
5858
let text:String = .init(decoding: utf8[range], as: Unicode.UTF8.self)
5959
switch (color, text, depth)
6060
{
61-
case (.keyword, "subscript", .toplevel?),
62-
(.keyword, "deinit", .toplevel?),
63-
(.keyword, "init", .toplevel?),
64-
(.identifier, _, .toplevel?):
65-
$0[.identifier] = text
66-
67-
case (_, _, _):
68-
$0 += text
61+
case (.keyword, "subscript", .toplevel?): $0[.identifier] = text
62+
case (.keyword, "deinit", .toplevel?): $0[.identifier] = text
63+
case (.keyword, "init", .toplevel?): $0[.identifier] = text
64+
case (.identifier, _, .toplevel?): $0[.identifier] = text
65+
// See note in `Signature.Expanded (ext).swift`
66+
case (.type, "`Self`", _): $0[.type] = "Self"
67+
case (_, _, _): $0 += text
6968
}
7069
}
7170
}

Sources/MarkdownPluginSwift/Signatures/Signature.Expanded (ext).swift

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ extension Signature.Expanded
55
{
66
@inlinable public
77
init(_ fragments:__shared some Collection<Signature<Scalar>.Fragment>,
8-
keywords:inout InterestingKeywords)
8+
landmarks:inout Signature.Landmarks)
99
{
1010
var utf8:[UInt8] = []
1111
utf8.reserveCapacity(fragments.reduce(0) { $0 + $1.spelling.utf8.count })
@@ -29,7 +29,7 @@ extension Signature.Expanded
2929
self.init(utf8: utf8,
3030
linkBoundaries: linkBoundaries,
3131
linkTargets: &linkTargets,
32-
keywords: &keywords)
32+
landmarks: &landmarks)
3333

3434
if !linkTargets.isEmpty
3535
{
@@ -51,27 +51,27 @@ extension Signature.Expanded
5151
init(_ string:String,
5252
linkBoundaries:borrowing [Int] = [])
5353
{
54-
var ignored:InterestingKeywords = .init()
55-
self.init(string, linkBoundaries: linkBoundaries, keywords: &ignored)
54+
var ignored:Signature.Landmarks = .init()
55+
self.init(string, linkBoundaries: linkBoundaries, landmarks: &ignored)
5656
}
5757

5858
@inlinable @_spi(testable) public
5959
init(_ string:String,
6060
linkBoundaries:borrowing [Int] = [],
61-
keywords:inout InterestingKeywords)
61+
landmarks:inout Signature.Landmarks)
6262
{
6363
var empty:[Int: Scalar] = [:]
6464
self.init(utf8: [UInt8].init(string.utf8),
6565
linkBoundaries: linkBoundaries,
6666
linkTargets: &empty,
67-
keywords: &keywords)
67+
landmarks: &landmarks)
6868
}
6969

7070
@inlinable
7171
init(utf8:[UInt8],
7272
linkBoundaries:borrowing [Int],
7373
linkTargets:inout [Int: Scalar],
74-
keywords:inout InterestingKeywords)
74+
landmarks:inout Signature.Landmarks)
7575
{
7676
let signature:SignatureSyntax = utf8.withUnsafeBufferPointer { .expanded($0) }
7777
var references:[Scalar: Int] = [:]
@@ -97,8 +97,8 @@ extension Signature.Expanded
9797
{
9898
switch String.init(decoding: utf8[range], as: Unicode.UTF8.self)
9999
{
100-
case "@attached": keywords.attached = true
101-
case "@freestanding": keywords.freestanding = true
100+
case "@attached": landmarks.keywords.attached = true
101+
case "@freestanding": landmarks.keywords.freestanding = true
102102
default: break
103103
}
104104
}
@@ -108,20 +108,21 @@ extension Signature.Expanded
108108
// other way to detect them besides inspecting token text!
109109
switch String.init(decoding: utf8[range], as: Unicode.UTF8.self)
110110
{
111-
case "actor": keywords.actor = true
112-
case "class": keywords.class = true
113-
case "final": keywords.final = true
111+
case "actor": landmarks.keywords.actor = true
112+
case "class": landmarks.keywords.class = true
113+
case "final": landmarks.keywords.final = true
114114
default: break
115115
}
116116
}
117117

118118
fallthrough
119119

120120
case .text(let range, let color?, _):
121+
let referent:Scalar? = linkTargets.removeValue(forKey: range.lowerBound)
122+
121123
$0[color]
122124
{
123-
if let referent:Scalar = linkTargets.removeValue(
124-
forKey: range.lowerBound)
125+
if let referent:Scalar
125126
{
126127
$0[.href] =
127128
{
@@ -139,9 +140,34 @@ extension Signature.Expanded
139140
} (&references[referent])
140141
}
141142
}
142-
content:
143+
content:
143144
{
144-
$0 += utf8[range]
145+
// This is an ugly, ugly hack to work around the upstream bug in
146+
// lib/SymbolGraphGen described here:
147+
// https://github.com/swiftlang/swift/issues/78343
148+
//
149+
// This hack is still **correct** if the declaration shadows the `Self`
150+
// type, because lib/SymbolGraphGen will emit such a token without the
151+
// extraneous backticks.
152+
if case .type = color,
153+
case [
154+
0x60, // '`'
155+
0x53, // 'S'
156+
0x65, // 'e'
157+
0x6C, // 'l'
158+
0x66, // 'f'
159+
0x60, // '`'
160+
] = utf8[range]
161+
{
162+
let i:Int = utf8.index(after: range.lowerBound)
163+
let j:Int = utf8.index(before: range.upperBound)
164+
165+
$0 += utf8[i ..< j]
166+
}
167+
else
168+
{
169+
$0 += utf8[range]
170+
}
145171
}
146172
}
147173
}

Sources/MarkdownPluginSwift/Signatures/Signature.Expanded.InterestingKeywords.swift renamed to Sources/MarkdownPluginSwift/Signatures/Signature.Landmarks.InterestingKeywords.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Signatures
22

3-
extension Signature.Expanded
3+
extension Signature.Landmarks
44
{
55
@frozen public
66
struct InterestingKeywords
@@ -16,7 +16,7 @@ extension Signature.Expanded
1616
public
1717
var freestanding:Bool
1818

19-
@inlinable public
19+
@inlinable
2020
init(actor:Bool = false,
2121
attached:Bool = false,
2222
`class`:Bool = false,
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import Signatures
2+
3+
extension Signature
4+
{
5+
@frozen public
6+
struct Landmarks
7+
{
8+
public
9+
var keywords:InterestingKeywords
10+
11+
@inlinable public
12+
init()
13+
{
14+
self.keywords = .init()
15+
}
16+
}
17+
}

Sources/MarkdownPluginSwift/Signatures/SignatureSyntax.ExpandedParameter.swift

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,28 +21,27 @@ extension SignatureSyntax.ExpandedParameter:SignatureParameter
2121
var named:Bool = false
2222
for region:Syntax in self.syntax.children(viewMode: .sourceAccurate)
2323
{
24-
guard
25-
let region:TokenSyntax = region.as(TokenSyntax.self)
26-
else
27-
{
28-
signature += region
29-
continue
30-
}
31-
32-
switch region.tokenKind
24+
if let region:TokenSyntax = region.as(TokenSyntax.self)
3325
{
34-
case .identifier, .wildcard:
35-
if named
36-
{
37-
signature[in: .binding] += region
38-
}
39-
else
26+
switch region.tokenKind
4027
{
41-
signature[in: .identifier] += region
42-
named = true
43-
}
28+
case .identifier, .wildcard:
29+
if named
30+
{
31+
signature[in: .binding] += region
32+
}
33+
else
34+
{
35+
signature[in: .identifier] += region
36+
named = true
37+
}
4438

45-
case _:
39+
case _:
40+
signature += region
41+
}
42+
}
43+
else
44+
{
4645
signature += region
4746
}
4847
}

Sources/MarkdownPluginSwift/Signatures/SignatureSyntax.Span.Depth.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
extension SignatureSyntax.Span
22
{
3-
@frozen @usableFromInline internal
3+
@frozen @usableFromInline
44
enum Depth
55
{
66
case toplevel

Sources/MarkdownPluginSwiftTests/InterestingKeywords.swift

Lines changed: 50 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -7,92 +7,93 @@ import MarkdownPluginSwift
77
@Suite
88
struct InterestingKeywords
99
{
10-
@Test
11-
static func Actor()
10+
private
11+
var landmarks:Signature<Never>.Landmarks
12+
13+
init()
14+
{
15+
self.landmarks = .init()
16+
}
17+
18+
@Test mutating
19+
func Actor()
1220
{
1321
let decl:String = "actor MargotRobbie"
1422

15-
var keywords:Signature<Never>.Expanded.InterestingKeywords = .init()
16-
let expanded:Signature<Never>.Expanded = .init(decl,
17-
keywords: &keywords)
23+
let signature:Signature<Never>.Expanded = .init(decl,
24+
landmarks: &self.landmarks)
1825

19-
#expect("\(expanded.bytecode.safe)" == decl)
20-
#expect(keywords.actor)
26+
#expect("\(signature.bytecode.safe)" == decl)
27+
#expect(self.landmarks.keywords.actor)
2128
}
22-
@Test
23-
static func Final()
29+
@Test mutating
30+
func Final()
2431
{
2532
let decl:String = "final class C"
2633

27-
var keywords:Signature<Never>.Expanded.InterestingKeywords = .init()
28-
let expanded:Signature<Never>.Expanded = .init(decl,
29-
keywords: &keywords)
34+
let signature:Signature<Never>.Expanded = .init(decl,
35+
landmarks: &self.landmarks)
3036

31-
#expect("\(expanded.bytecode.safe)" == decl)
32-
#expect(keywords.final)
37+
#expect("\(signature.bytecode.safe)" == decl)
38+
#expect(self.landmarks.keywords.final)
3339
}
34-
@Test
35-
static func ClassSubscript()
40+
@Test mutating
41+
func ClassSubscript()
3642
{
3743
let decl:String = "class subscript(index: Int) -> Int"
3844

39-
var keywords:Signature<Never>.Expanded.InterestingKeywords = .init()
40-
let expanded:Signature<Never>.Expanded = .init(decl,
41-
keywords: &keywords)
45+
let signature:Signature<Never>.Expanded = .init(decl,
46+
landmarks: &self.landmarks)
4247

43-
#expect("\(expanded.bytecode.safe)" == decl)
44-
#expect(keywords.class)
48+
#expect("\(signature.bytecode.safe)" == decl)
49+
#expect(self.landmarks.keywords.class)
4550
}
46-
@Test
47-
static func ClassFunc()
51+
@Test mutating
52+
func ClassFunc()
4853
{
4954
let decl:String = "class func x() -> Int"
5055

51-
var keywords:Signature<Never>.Expanded.InterestingKeywords = .init()
52-
let expanded:Signature<Never>.Expanded = .init(decl,
53-
keywords: &keywords)
56+
let signature:Signature<Never>.Expanded = .init(decl,
57+
landmarks: &self.landmarks)
5458

55-
#expect("\(expanded.bytecode.safe)" == decl)
56-
#expect(keywords.class)
59+
#expect("\(signature.bytecode.safe)" == decl)
60+
#expect(self.landmarks.keywords.class)
5761
}
58-
@Test
59-
static func ClassVar()
62+
@Test mutating
63+
func ClassVar()
6064
{
6165
let decl:String = "class var x: Int { get }"
6266

63-
var keywords:Signature<Never>.Expanded.InterestingKeywords = .init()
64-
let expanded:Signature<Never>.Expanded = .init(decl,
65-
keywords: &keywords)
67+
let signature:Signature<Never>.Expanded = .init(decl,
68+
landmarks: &self.landmarks)
6669

67-
#expect("\(expanded.bytecode.safe)" == decl)
68-
#expect(keywords.class)
70+
#expect("\(signature.bytecode.safe)" == decl)
71+
#expect(self.landmarks.keywords.class)
6972
}
70-
@Test
71-
static func FreestandingMacro()
73+
@Test mutating
74+
func FreestandingMacro()
7275
{
7376
let decl:String = """
7477
@freestanding(expression) macro line<T: ExpressibleByIntegerLiteral>() -> T
7578
"""
7679

77-
var keywords:Signature<Never>.Expanded.InterestingKeywords = .init()
78-
let expanded:Signature<Never>.Expanded = .init(decl,
79-
keywords: &keywords)
80+
let signature:Signature<Never>.Expanded = .init(decl,
81+
landmarks: &self.landmarks)
8082

81-
#expect("\(expanded.bytecode.safe)" == decl)
82-
#expect(keywords.freestanding)
83+
#expect("\(signature.bytecode.safe)" == decl)
84+
#expect(self.landmarks.keywords.freestanding)
8385
}
84-
@Test
85-
static func AttachedMacro()
86+
@Test mutating
87+
func AttachedMacro()
8688
{
8789
let decl:String = """
8890
@attached(member) @attached(conformance) public macro OptionSet<RawType>()
8991
"""
9092

91-
var keywords:Signature<Never>.Expanded.InterestingKeywords = .init()
92-
let expanded:Signature<Never>.Expanded = .init(decl,
93-
keywords: &keywords)
93+
let signature:Signature<Never>.Expanded = .init(decl,
94+
landmarks: &self.landmarks)
9495

95-
#expect("\(expanded.bytecode.safe)" == decl)
96-
#expect(keywords.attached)
96+
#expect("\(signature.bytecode.safe)" == decl)
97+
#expect(self.landmarks.keywords.attached)
9798
}
9899
}

0 commit comments

Comments
 (0)