@@ -3,6 +3,7 @@ package import BuildSystemIntegration
3
3
package import Foundation
4
4
package import IndexStoreDB
5
5
package import LanguageServerProtocol
6
+ import SKLogging
6
7
package import SemanticIndex
7
8
import SwiftDocC
8
9
@@ -27,7 +28,9 @@ package struct DocCDocumentationManager: Sendable {
27
28
28
29
package func filesDidChange( _ events: [ FileEvent ] ) async {
29
30
for event in events {
30
- guard let catalogURL = await buildSystemManager. doccCatalog ( for: event. uri) else {
31
+ guard let target = await buildSystemManager. canonicalTarget ( for: event. uri) ,
32
+ let catalogURL = await buildSystemManager. doccCatalog ( for: target)
33
+ else {
31
34
continue
32
35
}
33
36
await catalogIndexManager. invalidate ( catalogURL)
@@ -42,27 +45,38 @@ package struct DocCDocumentationManager: Sendable {
42
45
DocCSymbolLink ( string: string)
43
46
}
44
47
48
+ private func parentSymbol( of symbol: SymbolOccurrence , in index: CheckedIndex ) -> SymbolOccurrence ? {
49
+ let allParentRelations = symbol. relations
50
+ . filter { $0. roles. contains ( . childOf) }
51
+ . sorted ( )
52
+ if allParentRelations. count > 1 {
53
+ logger. debug ( " Symbol \( symbol. symbol. usr) has multiple parent symbols " )
54
+ }
55
+ guard let parentRelation = allParentRelations. first else {
56
+ return nil
57
+ }
58
+ if parentRelation. symbol. kind == . extension {
59
+ let allSymbolOccurrences = index. occurrences ( relatedToUSR: parentRelation. symbol. usr, roles: . extendedBy)
60
+ . sorted ( )
61
+ if allSymbolOccurrences. count > 1 {
62
+ logger. debug ( " Extension \( parentRelation. symbol. usr) extends multiple symbols " )
63
+ }
64
+ return allSymbolOccurrences. first
65
+ }
66
+ return index. primaryDefinitionOrDeclarationOccurrence ( ofUSR: parentRelation. symbol. usr)
67
+ }
68
+
45
69
package func symbolLink( forUSR usr: String , in index: CheckedIndex ) -> DocCSymbolLink ? {
46
70
guard let topLevelSymbolOccurrence = index. primaryDefinitionOrDeclarationOccurrence ( ofUSR: usr) else {
47
71
return nil
48
72
}
49
73
let module = topLevelSymbolOccurrence. location. moduleName
50
74
var components = [ topLevelSymbolOccurrence. symbol. name]
51
- // Find any child symbols
52
- var symbolOccurrence : SymbolOccurrence ? = topLevelSymbolOccurrence
53
- while let currentSymbolOccurrence = symbolOccurrence, components. count > 0 {
54
- let parentRelation = currentSymbolOccurrence. relations. first { $0. roles. contains ( . childOf) }
55
- guard let parentRelation else {
56
- break
57
- }
58
- if parentRelation. symbol. kind == . extension {
59
- symbolOccurrence = index. occurrences ( relatedToUSR: parentRelation. symbol. usr, roles: . extendedBy) . first
60
- } else {
61
- symbolOccurrence = index. primaryDefinitionOrDeclarationOccurrence ( ofUSR: parentRelation. symbol. usr)
62
- }
63
- if let symbolOccurrence {
64
- components. insert ( symbolOccurrence. symbol. name, at: 0 )
65
- }
75
+ // Find any parent symbols
76
+ var symbolOccurrence : SymbolOccurrence = topLevelSymbolOccurrence
77
+ while let parentSymbolOccurrence = parentSymbol ( of: symbolOccurrence, in: index) {
78
+ components. insert ( parentSymbolOccurrence. symbol. name, at: 0 )
79
+ symbolOccurrence = parentSymbolOccurrence
66
80
}
67
81
return DocCSymbolLink ( string: module) ? . appending ( components: components)
68
82
}
@@ -81,39 +95,47 @@ package struct DocCDocumentationManager: Sendable {
81
95
}
82
96
// Do a lookup to find the top level symbol
83
97
let topLevelSymbolName = components. removeLast ( ) . name
84
- var topLevelSymbolOccurrences = [ SymbolOccurrence ] ( )
98
+ var topLevelSymbolOccurrences : [ SymbolOccurrence ] = [ ]
85
99
index. forEachCanonicalSymbolOccurrence ( byName: topLevelSymbolName) { symbolOccurrence in
86
100
guard symbolOccurrence. location. moduleName == symbolLink. moduleName else {
87
- return true
101
+ return true // continue
88
102
}
89
103
topLevelSymbolOccurrences. append ( symbolOccurrence)
90
- return true
104
+ return true // continue
91
105
}
92
- guard let topLevelSymbolOccurrence = topLevelSymbolOccurrences. first else {
93
- return nil
94
- }
95
- // Find any child symbols
96
- var symbolOccurrence : SymbolOccurrence ? = topLevelSymbolOccurrence
97
- while let currentSymbolOccurrence = symbolOccurrence, components. count > 0 {
98
- let nextComponent = components. removeLast ( )
99
- let parentRelation = currentSymbolOccurrence. relations. first {
100
- $0. roles. contains ( . childOf) && $0. symbol. name == nextComponent. name
101
- }
102
- guard let parentRelation else {
103
- break
106
+ // Search each potential symbol's parents to find an exact match
107
+ let symbolOccurences = topLevelSymbolOccurrences. filter { topLevelSymbolOccurrence in
108
+ var components = components
109
+ var symbolOccurrence = topLevelSymbolOccurrence
110
+ while let parentSymbolOccurrence = parentSymbol ( of: symbolOccurrence, in: index) , !components. isEmpty {
111
+ let nextComponent = components. removeLast ( )
112
+ guard parentSymbolOccurrence. symbol. name == nextComponent. name else {
113
+ return false
114
+ }
115
+ symbolOccurrence = parentSymbolOccurrence
104
116
}
105
- if parentRelation. symbol. kind == . extension {
106
- symbolOccurrence = index. occurrences ( relatedToUSR: parentRelation. symbol. usr, roles: . extendedBy) . first
107
- } else {
108
- symbolOccurrence = index. primaryDefinitionOrDeclarationOccurrence ( ofUSR: parentRelation. symbol. usr)
117
+ guard components. isEmpty else {
118
+ return false
109
119
}
120
+ return true
121
+ } . sorted ( )
122
+ if symbolOccurences. count > 1 {
123
+ logger. debug ( " Multiple symbols found for DocC symbol link ' \( symbolLink. absoluteString) ' " )
110
124
}
111
- guard symbolOccurrence != nil else {
112
- return nil
113
- }
114
- return topLevelSymbolOccurrence
125
+ return symbolOccurences. first
115
126
}
116
127
128
+ /// Generates the SwiftDocC RenderNode for a given symbol, tutorial, or markdown file.
129
+ ///
130
+ /// - Parameters:
131
+ /// - symbolUSR: The USR of the symbol to render
132
+ /// - symbolGraph: The symbol graph that includes the given symbol USR
133
+ /// - markupFile: The markdown article or symbol extension to render
134
+ /// - tutorialFile: The tutorial file to render
135
+ /// - moduleName: The name of the Swift module that will be rendered
136
+ /// - catalogURL: The URL pointing to the docc catalog that this symbol, tutorial, or markdown file is a part of
137
+ /// - Throws: A ResponseError if something went wrong
138
+ /// - Returns: The DoccDocumentationResponse containing the RenderNode if successful
117
139
package func renderDocCDocumentation(
118
140
symbolUSR: String ? = nil ,
119
141
symbolGraph: String ? = nil ,
@@ -132,15 +154,15 @@ package struct DocCDocumentationManager: Sendable {
132
154
overridingDocumentationComments [ symbolUSR] = overrideDocComments
133
155
}
134
156
}
135
- var symbolGraphs = [ Data ] ( )
157
+ var symbolGraphs : [ Data ] = [ ]
136
158
if let symbolGraphData = symbolGraph? . data ( using: . utf8) {
137
159
symbolGraphs. append ( symbolGraphData)
138
160
}
139
- var markupFiles = [ Data ] ( )
161
+ var markupFiles : [ Data ] = [ ]
140
162
if let markupFile = markupFile? . data ( using: . utf8) {
141
163
markupFiles. append ( markupFile)
142
164
}
143
- var tutorialFiles = [ Data ] ( )
165
+ var tutorialFiles : [ Data ] = [ ]
144
166
if let tutorialFile = tutorialFile? . data ( using: . utf8) {
145
167
tutorialFiles. append ( tutorialFile)
146
168
}
0 commit comments