Skip to content

Commit 53aa5dd

Browse files
authored
Merge pull request #392 from tayloraswift/doclink-equivalence
support disambiguation filters in doclinks
2 parents d211cd3 + 2f9580a commit 53aa5dd

17 files changed

+155
-40
lines changed

Sources/SymbolGraphLinker/Resolution/SSGC.OutlineDiagnostic.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ extension SSGC
88
{
99
case annealedIncorrectHash(in:UCF.Selector, to:FNV24)
1010
case unresolvedAbsolute(Doclink)
11+
case unresolvedRelative(Doclink)
1112
case suggestReformat(Doclink, to:UCF.Selector)
1213
}
1314
}
@@ -26,13 +27,16 @@ extension SSGC.OutlineDiagnostic:Diagnostic
2627
"""
2728

2829
case .unresolvedAbsolute(let doclink):
30+
fallthrough
31+
32+
case .unresolvedRelative(let doclink):
2933
output[.warning] = """
30-
doclink '\(doclink)' does not resolve to any article (or tutorial) in this package
34+
doclink '\(doclink.value)' does not resolve to any article (or tutorial) in this package
3135
"""
3236

3337
case .suggestReformat(let doclink, to: _):
3438
output[.warning] = """
35-
doclink '\(doclink)' referencing symbol documentation could be written as \
39+
doclink '\(doclink.value)' referencing symbol documentation could be written as \
3640
a backtick-delimited codelink
3741
"""
3842
}
@@ -52,6 +56,11 @@ extension SSGC.OutlineDiagnostic:Diagnostic
5256
documentation
5357
"""
5458

59+
case .unresolvedRelative(let doclink):
60+
output[.note] = """
61+
could not convert relative doclink '\(doclink.page)' to a UCF selector
62+
"""
63+
5564
case .suggestReformat(_, to: let codelink):
5665
output[.note] = """
5766
reformat the link as ``\(codelink)`` to suppress this warning

Sources/SymbolGraphLinker/Resolution/SSGC.OutlineResolver.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,12 +222,17 @@ extension SSGC.OutlineResolver
222222
}
223223
else
224224
{
225+
if doclink.absolute
226+
{
227+
self.diagnostics[source] = SSGC.OutlineDiagnostic.unresolvedAbsolute(doclink)
228+
return nil
229+
}
225230
// Resolution might still succeed by reinterpreting the doclink as a codelink.
226231
guard
227-
let codelink:UCF.Selector = .equivalent(to: doclink)
232+
let codelink:UCF.Selector = .init(doclink.page)
228233
else
229234
{
230-
self.diagnostics[source] = SSGC.OutlineDiagnostic.unresolvedAbsolute(doclink)
235+
self.diagnostics[source] = SSGC.OutlineDiagnostic.unresolvedRelative(doclink)
231236
return nil
232237
}
233238
guard

Sources/UCF/Codelinks/Grammar/UCF.ArrowRule.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Grammar
22

33
extension UCF
44
{
5+
/// Arrow ::= \s * '->' \s *
56
enum ArrowRule:ParsingRule
67
{
78
typealias Location = String.Index
@@ -11,8 +12,10 @@ extension UCF
1112
_ input:inout ParsingInput<some ParsingDiagnostics<Source>>) throws
1213
where Source:Collection<Terminal>, Source.Index == Location
1314
{
15+
input.parse(as: UnicodeEncoding<Location, Terminal>.Space.self, in: Void.self)
1416
try input.parse(as: UnicodeEncoding<Location, Terminal>.Hyphen.self)
1517
try input.parse(as: UnicodeEncoding<Location, Terminal>.AngleRight.self)
18+
input.parse(as: UnicodeEncoding<Location, Terminal>.Space.self, in: Void.self)
1619
}
1720
}
1821
}

Sources/UCF/Codelinks/Grammar/UCF.BracketPatternRule.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Grammar
22

33
extension UCF
44
{
5-
/// BracketPattern ::= '[' TypePattern ( ':' TypePattern ) ? ']'
5+
/// BracketPattern ::= '[' TypePattern ( \s * ':' \s * TypePattern ) ? ']'
66
enum BracketPatternRule:ParsingRule
77
{
88
typealias Location = String.Index
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import Grammar
2+
3+
extension UCF
4+
{
5+
/// DisambiguationSuffix ::= SignatureSuffix Clauses ? | Clauses
6+
///
7+
/// Note that the leading whitespace is considered part of the disambiguator.
8+
enum DisambiguationSuffixRule:ParsingRule
9+
{
10+
typealias Location = String.Index
11+
typealias Terminal = Unicode.Scalar
12+
typealias Construction = (SignaturePattern?, [(String, String?)])
13+
14+
static func parse<Diagnostics>(
15+
_ input:inout ParsingInput<Diagnostics>) throws -> Construction where
16+
Diagnostics:ParsingDiagnostics,
17+
Diagnostics.Source.Element == Terminal,
18+
Diagnostics.Source.Index == Location
19+
{
20+
if let clauses:[(String, String?)] = input.parse(as: DisambiguatorRule.Clauses?.self)
21+
{
22+
return (nil, clauses)
23+
}
24+
25+
let signature:SignaturePattern = try input.parse(as: SignatureSuffixRule.self)
26+
return (signature, input.parse(as: DisambiguatorRule.Clauses?.self) ?? [])
27+
}
28+
}
29+
}

Sources/UCF/Codelinks/Grammar/UCF.DisambiguatorRule.Clause.AlphanumericWord.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Grammar
22

33
extension UCF.DisambiguatorRule.Clause
44
{
5-
/// AlphanumericWord ::= ' ' * [0-9A-Za-z] + ' ' *
5+
/// AlphanumericWord ::= Space ? [0-9A-Za-z] + Space ?
66
enum AlphanumericWord:ParsingRule
77
{
88
typealias Location = String.Index
@@ -14,14 +14,14 @@ extension UCF.DisambiguatorRule.Clause
1414
Diagnostics.Source.Element == Terminal,
1515
Diagnostics.Source.Index == Location
1616
{
17-
input.parse(as: UnicodeEncoding<Location, Terminal>.Space.self, in: Void.self)
17+
input.parse(as: UCF.SpaceRule?.self)
1818

1919
let start:Location = input.index
2020
try input.parse(as: AlphanumericCodepoint.self)
2121
input.parse(as: AlphanumericCodepoint.self, in: Void.self)
2222
let end:Location = input.index
2323

24-
input.parse(as: UnicodeEncoding<Location, Terminal>.Space.self, in: Void.self)
24+
input.parse(as: UCF.SpaceRule?.self)
2525

2626
return start ..< end
2727
}

Sources/UCF/Codelinks/Grammar/UCF.DisambiguatorRule.Clauses.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Grammar
22

33
extension UCF.DisambiguatorRule
44
{
5-
/// Clauses ::= ' ' + '[' Clause ( ',' Clause ) * ']'
5+
/// Clauses ::= Space '[' Clause ( ',' Clause ) * ']'
66
///
77
/// Note that the leading whitespace is considered part of the filter.
88
enum Clauses:ParsingRule
@@ -16,8 +16,7 @@ extension UCF.DisambiguatorRule
1616
Diagnostics.Source.Element == Terminal,
1717
Diagnostics.Source.Index == Location
1818
{
19-
try input.parse(as: UnicodeEncoding<Location, Terminal>.Space.self)
20-
input.parse(as: UnicodeEncoding<Location, Terminal>.Space.self, in: Void.self)
19+
try input.parse(as: UCF.SpaceRule.self)
2120

2221
// No padding around structural characters; ``DisambiguationClauseRule`` already
2322
// trims whitespace.

Sources/UCF/Codelinks/Grammar/UCF.DisambiguatorRule.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Grammar
22

33
extension UCF
44
{
5-
/// Disambiguator ::= ' ' + SignaturePattern Clauses ? | Clauses
5+
/// Disambiguator ::= \s + SignaturePattern Clauses ? | Clauses
66
///
77
/// Note that the leading whitespace is considered part of the disambiguator.
88
enum DisambiguatorRule:ParsingRule

Sources/UCF/Codelinks/Grammar/UCF.FunctionPatternRule.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Grammar
22

33
extension UCF
44
{
5-
/// FunctionPattern ::= TuplePattern ( '->' TypePattern ) ?
5+
/// FunctionPattern ::= TuplePattern ( Arrow TypePattern ) ?
66
enum FunctionPatternRule:ParsingRule
77
{
88
typealias Location = String.Index
@@ -18,8 +18,7 @@ extension UCF
1818
{
1919
let tuple:[TypePattern] = try input.parse(as: TuplePatternRule.self)
2020

21-
if case ()? = input.parse(
22-
as: Pattern.Pad<ArrowRule, UnicodeEncoding<Location, Terminal>.Space>?.self)
21+
if case ()? = input.parse(as: ArrowRule?.self)
2322
{
2423
return (tuple, try input.parse(as: TypePatternRule.self))
2524
}

Sources/UCF/Codelinks/Grammar/UCF.NominalPatternRule.GenericArguments.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Grammar
22

33
extension UCF.NominalPatternRule
44
{
5-
/// GenericArguments ::= '<' TypePattern ( ',' TypePattern ) * '>'
5+
/// GenericArguments ::= '<' \s * TypePattern ( \s * ',' \s * TypePattern ) * \s * '>'
66
enum GenericArguments:ParsingRule
77
{
88
typealias Location = String.Index
@@ -15,11 +15,13 @@ extension UCF.NominalPatternRule
1515
Diagnostics.Source.Index == Location
1616
{
1717
try input.parse(as: UnicodeEncoding<Location, Terminal>.AngleLeft.self)
18+
input.parse(as: UnicodeEncoding<Location, Terminal>.Space.self, in: Void.self)
1819
let types:[UCF.TypePattern] = try input.parse(as: Pattern.Join<UCF.TypePatternRule,
1920
Pattern.Pad<
2021
UnicodeEncoding<Location, Terminal>.Comma,
2122
UnicodeEncoding<Location, Terminal>.Space>,
2223
[UCF.TypePattern]>.self)
24+
input.parse(as: UnicodeEncoding<Location, Terminal>.Space.self, in: Void.self)
2325
try input.parse(as: UnicodeEncoding<Location, Terminal>.AngleRight.self)
2426
return types
2527
}

0 commit comments

Comments
 (0)