Skip to content

Commit 1340fd2

Browse files
authored
Store only the resolved reference in DocumentationContext.symbolIndex (#543)
* Store only the resolved reference in DocumentationContext.symbolIndex rdar://106654403 * Add test that references in symbol index have nodes in doc cache
1 parent c74237d commit 1340fd2

22 files changed

+240
-180
lines changed

Sources/SwiftDocC/Infrastructure/CoverageDataEntry.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This source file is part of the Swift.org open source project
33

4-
Copyright (c) 2021 Apple Inc. and the Swift project authors
4+
Copyright (c) 2021-2023 Apple Inc. and the Swift project authors
55
Licensed under Apache License v2.0 with Runtime Library Exception
66

77
See https://swift.org/LICENSE.txt for license information
@@ -371,9 +371,7 @@ extension CoverageDataEntry {
371371
)
372372
let total = children.count
373373
let documented = children.filter {
374-
(context.symbolIndex[$0.reference.description]?.semantic as? Symbol)?
375-
.abstractSection
376-
!= nil
374+
(context.nodeWithSymbolIdentifier($0.reference.description)?.semantic as? Symbol)?.abstractSection != nil
377375
}.count
378376

379377
if total == 0 {

Sources/SwiftDocC/Infrastructure/DocumentationContext.swift

Lines changed: 42 additions & 29 deletions
Large diffs are not rendered by default.

Sources/SwiftDocC/Infrastructure/Link Resolution/DocumentationCacheBasedLinkResolver.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ final class DocumentationCacheBasedLinkResolver {
511511
/// Method called when walking the symbol url tree that checks if a parent of a symbol has had its
512512
/// path modified during loading the symbol graph. If that's the case the method replaces
513513
/// `reference` with an updated reference with a correct reference path.
514-
func updateNodeWithReferenceIfCollisionChild(_ reference: ResolvedTopicReference, symbolsURLHierarchy: inout BidirectionalTree<ResolvedTopicReference>, symbolIndex: inout [String: DocumentationNode], context: DocumentationContext) throws {
514+
func updateNodeWithReferenceIfCollisionChild(_ reference: ResolvedTopicReference, symbolsURLHierarchy: inout BidirectionalTree<ResolvedTopicReference>, symbolIndex: inout [String: ResolvedTopicReference], context: DocumentationContext) throws {
515515
let newReference = try currentReferenceFor(reference: reference, symbolsURLHierarchy: &symbolsURLHierarchy)
516516
guard newReference != reference else { return }
517517

@@ -523,7 +523,7 @@ final class DocumentationCacheBasedLinkResolver {
523523
// Rewrite the symbol index
524524
if let symbolIdentifier = documentationNode?.symbol?.identifier {
525525
symbolIndex.removeValue(forKey: symbolIdentifier.precise)
526-
symbolIndex[symbolIdentifier.precise] = documentationNode
526+
symbolIndex[symbolIdentifier.precise] = newReference
527527
}
528528

529529
// Replace the topic graph node

Sources/SwiftDocC/Infrastructure/Link Resolution/PathHierarchy.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1135,7 +1135,7 @@ private extension PathHierarchy.Node {
11351135
if let fragments = symbol[mixin: SymbolGraph.Symbol.DeclarationFragments.self]?.declarationFragments {
11361136
return fragments.map(\.spelling).joined().split(whereSeparator: { $0.isWhitespace || $0.isNewline }).joined(separator: " ")
11371137
}
1138-
return context.symbolIndex[symbol.identifier.precise]!.name.description
1138+
return context.nodeWithSymbolIdentifier(symbol.identifier.precise)!.name.description
11391139
}
11401140
// This only gets called for PathHierarchy error messages, so hierarchyBasedLinkResolver is never nil.
11411141
let reference = context.hierarchyBasedLinkResolver!.resolvedReferenceMap[identifier]!

Sources/SwiftDocC/Infrastructure/Link Resolution/PathHierarchyBasedLinkResolver.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,12 @@ final class PathHierarchyBasedLinkResolver {
7373
}
7474

7575
/// Map the resolved identifiers to resolved topic references for all symbols in the given symbol index.
76-
func addMappingForSymbols(symbolIndex: [String: DocumentationNode]) {
76+
func addMappingForSymbols(symbolIndex: [String: ResolvedTopicReference]) {
7777
for (id, node) in pathHierarchy.lookup {
78-
guard let symbol = node.symbol, let node = symbolIndex[symbol.identifier.precise] else {
78+
guard let symbol = node.symbol, let reference = symbolIndex[symbol.identifier.precise] else {
7979
continue
8080
}
81-
resolvedReferenceMap[id] = node.reference
81+
resolvedReferenceMap[id] = reference
8282
}
8383
}
8484

@@ -164,9 +164,9 @@ final class PathHierarchyBasedLinkResolver {
164164
}
165165

166166
/// Adds the headings for all symbols in the symbol index to the path hierarchy.
167-
func addAnchorForSymbols(symbolIndex: [String: DocumentationNode]) {
167+
func addAnchorForSymbols(symbolIndex: [String: ResolvedTopicReference], documentationCache: [ResolvedTopicReference: DocumentationNode]) {
168168
for (id, node) in pathHierarchy.lookup {
169-
guard let symbol = node.symbol, let node = symbolIndex[symbol.identifier.precise] else { continue }
169+
guard let symbol = node.symbol, let reference = symbolIndex[symbol.identifier.precise], let node = documentationCache[reference] else { continue }
170170
addAnchors(node.anchorSections, to: id)
171171
}
172172
}

Sources/SwiftDocC/Infrastructure/Symbol Graph/GeneratedDocumentationTopics.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This source file is part of the Swift.org open source project
33

4-
Copyright (c) 2021-2022 Apple Inc. and the Swift project authors
4+
Copyright (c) 2021-2023 Apple Inc. and the Swift project authors
55
Licensed under Apache License v2.0 with Runtime Library Exception
66

77
See https://swift.org/LICENSE.txt for license information
@@ -255,14 +255,15 @@ enum GeneratedDocumentationTopics {
255255
// Check that there is origin information (i.e. the symbol is inherited)
256256
let origin = relationship.mixins[SymbolGraph.Relationship.SourceOrigin.mixinKey] as? SymbolGraph.Relationship.SourceOrigin,
257257
// Resolve the containing type
258-
let parent = context.symbolIndex[relationship.target],
258+
let parent = context.nodeWithSymbolIdentifier(relationship.target),
259259
// Resolve the child
260-
let child = context.symbolIndex[relationship.source],
260+
let child = context.nodeWithSymbolIdentifier(relationship.source),
261261
// Get the child symbol
262262
let childSymbol = child.symbol,
263263
// Get the swift extension data
264-
let extends = childSymbol.mixins[SymbolGraph.Symbol.Swift.Extension.mixinKey] as? SymbolGraph.Symbol.Swift.Extension {
265-
let originSymbol = context.symbolIndex[origin.identifier]?.symbol
264+
let extends = childSymbol.mixins[SymbolGraph.Symbol.Swift.Extension.mixinKey] as? SymbolGraph.Symbol.Swift.Extension
265+
{
266+
let originSymbol = context.nodeWithSymbolIdentifier(origin.identifier)?.symbol
266267

267268
// Add the inherited symbol to the index.
268269
try inheritanceIndex.add(child.reference, to: parent.reference, childSymbol: childSymbol, originDisplayName: origin.displayName, originSymbol: originSymbol, extendedModuleName: extends.extendedModule)

Sources/SwiftDocC/Infrastructure/Symbol Graph/SymbolGraphRelationshipsBuilder.swift

Lines changed: 53 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This source file is part of the Swift.org open source project
33

4-
Copyright (c) 2021-2022 Apple Inc. and the Swift project authors
4+
Copyright (c) 2021-2023 Apple Inc. and the Swift project authors
55
Licensed under Apache License v2.0 with Runtime Library Exception
66

77
See https://swift.org/LICENSE.txt for license information
@@ -39,27 +39,29 @@ struct SymbolGraphRelationshipsBuilder {
3939
selector: UnifiedSymbolGraph.Selector,
4040
in bundle: DocumentationBundle,
4141
context: DocumentationContext,
42-
symbolIndex: inout [String: DocumentationNode],
42+
symbolIndex: inout [String: ResolvedTopicReference],
43+
documentationCache: [ResolvedTopicReference: DocumentationNode],
4344
engine: DiagnosticEngine
4445
) {
4546
// Resolve source symbol
46-
guard let implementorNode = symbolIndex[edge.source],
47-
let implementorSymbol = implementorNode.semantic as? Symbol else {
47+
guard let implementorNode = symbolIndex[edge.source].flatMap({ documentationCache[$0] }),
48+
let implementorSymbol = implementorNode.semantic as? Symbol
49+
else {
4850
// The source node for implementation relationship not found.
4951
engine.emit(NodeProblem.notFound(edge.source))
5052
return
5153
}
5254

5355
// Resolve target symbol if possible
54-
let optionalInterfaceNode = symbolIndex[edge.target]
56+
let optionalInterfaceNode = symbolIndex[edge.target].flatMap { documentationCache[$0] }
5557

5658
if optionalInterfaceNode == nil {
5759
// Take the interface language of the target symbol
5860
// or if external - default to the language of the current symbol.
59-
let language = symbolIndex[edge.target]?.reference.sourceLanguage
61+
let language = symbolIndex[edge.target]?.sourceLanguage
6062
?? implementorNode.reference.sourceLanguage
6163

62-
let symbolReference = SymbolReference(edge.target, interfaceLanguage: language, symbol: symbolIndex[edge.target]?.symbol)
64+
let symbolReference = SymbolReference(edge.target, interfaceLanguage: language, symbol: symbolIndex[edge.target].flatMap { documentationCache[$0]?.symbol })
6365
guard let unresolved = UnresolvedTopicReference(symbolReference: symbolReference, bundle: bundle) else {
6466
// The symbol reference format is invalid.
6567
engine.emit(NodeProblem.invalidReference(symbolReference.path))
@@ -74,9 +76,10 @@ struct SymbolGraphRelationshipsBuilder {
7476
// Find out the parent's title
7577
let parentName: String?
7678

77-
if let reference = symbolIndex[edge.source]?.reference,
78-
let parentNode = try? context.entity(with: reference.removingLastPathComponent()),
79-
let title = (parentNode.semantic as? Symbol)?.title {
79+
if let reference = symbolIndex[edge.source],
80+
let parentNode = try? context.entity(with: reference.removingLastPathComponent()),
81+
let title = (parentNode.semantic as? Symbol)?.title
82+
{
8083
parentName = title
8184
} else {
8285
parentName = nil
@@ -93,14 +96,14 @@ struct SymbolGraphRelationshipsBuilder {
9396
)
9497

9598
// Make the implementation a child of the requirement
96-
guard let childReference = symbolIndex[edge.source]?.reference else {
99+
guard let childReference = symbolIndex[edge.source] else {
97100
// The child wasn't found, invalid reference in relationship.
98101
engine.emit(SymbolGraphRelationshipsBuilder.NodeProblem.notFound(edge.source))
99102
return
100103
}
101104

102105
if let child = context.topicGraph.nodeWithReference(childReference),
103-
let targetReference = symbolIndex[edge.target]?.reference,
106+
let targetReference = symbolIndex[edge.target],
104107
let parent = context.topicGraph.nodeWithReference(targetReference) {
105108
context.topicGraph.addEdge(from: parent, to: child)
106109
}
@@ -119,30 +122,32 @@ struct SymbolGraphRelationshipsBuilder {
119122
edge: SymbolGraph.Relationship,
120123
selector: UnifiedSymbolGraph.Selector,
121124
in bundle: DocumentationBundle,
122-
symbolIndex: inout [String: DocumentationNode],
125+
symbolIndex: inout [String: ResolvedTopicReference],
126+
documentationCache: [ResolvedTopicReference: DocumentationNode],
123127
engine: DiagnosticEngine
124128
) {
125129
// Resolve source symbol
126-
guard let conformingNode = symbolIndex[edge.source],
127-
let conformingSymbol = conformingNode.semantic as? Symbol else {
128-
// The source node for coformance relationship not found.
130+
guard let conformingNode = symbolIndex[edge.source].flatMap({ documentationCache[$0] }),
131+
let conformingSymbol = conformingNode.semantic as? Symbol
132+
else {
133+
// The source node for conformance relationship not found.
129134
engine.emit(NodeProblem.notFound(edge.source))
130135
return
131136
}
132137

133138
// Resolve target symbol if possible
134-
let optionalConformanceNode = symbolIndex[edge.target]
139+
let optionalConformanceNode = symbolIndex[edge.target].flatMap { documentationCache[$0] }
135140
let conformanceNodeReference: TopicReference
136141

137142
if let conformanceNode = optionalConformanceNode {
138143
conformanceNodeReference = .successfullyResolved(conformanceNode.reference)
139144
} else {
140145
// Take the interface language of the target symbol
141146
// or if external - default to the language of the current symbol.
142-
let language = symbolIndex[edge.target]?.reference.sourceLanguage
147+
let language = symbolIndex[edge.target]?.sourceLanguage
143148
?? conformingNode.reference.sourceLanguage
144149

145-
let symbolReference = SymbolReference(edge.target, interfaceLanguage: language, symbol: symbolIndex[edge.target]?.symbol)
150+
let symbolReference = SymbolReference(edge.target, interfaceLanguage: language, symbol: symbolIndex[edge.target].flatMap { documentationCache[$0]?.symbol })
146151
guard let unresolved = UnresolvedTopicReference(symbolReference: symbolReference, bundle: bundle) else {
147152
// The symbol reference format is invalid.
148153
engine.emit(NodeProblem.invalidReference(symbolReference.path))
@@ -203,29 +208,32 @@ struct SymbolGraphRelationshipsBuilder {
203208
edge: SymbolGraph.Relationship,
204209
selector: UnifiedSymbolGraph.Selector,
205210
in bundle: DocumentationBundle,
206-
symbolIndex: inout [String: DocumentationNode],
211+
symbolIndex: inout [String: ResolvedTopicReference],
212+
documentationCache: [ResolvedTopicReference: DocumentationNode],
207213
engine: DiagnosticEngine
208214
) {
209215
// Resolve source symbol
210-
guard let childNode = symbolIndex[edge.source],
211-
let childSymbol = childNode.semantic as? Symbol else {
216+
guard let childNode = symbolIndex[edge.source].flatMap({ documentationCache[$0] }),
217+
let childSymbol = childNode.semantic as? Symbol
218+
else {
212219
// The source node for inheritance relationship not found.
213220
engine.emit(NodeProblem.notFound(edge.source))
214221
return
215222
}
216223

217224
// Resolve target symbol if possible
218-
let optionalParentNode = symbolIndex[edge.target]
225+
let optionalParentNode = symbolIndex[edge.target].flatMap { documentationCache[$0] }
219226
let parentNodeReference: TopicReference
220227

221228
if let parentNode = optionalParentNode {
222229
parentNodeReference = .successfullyResolved(parentNode.reference)
223230
} else {
224-
// Use the target symbol language, if external - fallback on child symbol's langauge
225-
let language = symbolIndex[edge.target]?.symbol.map({ SourceLanguage(id: $0.identifier.interfaceLanguage) })
226-
?? childNode.reference.sourceLanguage
231+
// Use the target symbol language, if external - fallback on child symbol's language
232+
let language: SourceLanguage = symbolIndex[edge.target].flatMap {
233+
documentationCache[$0]?.symbol.map({ SourceLanguage(id: $0.identifier.interfaceLanguage) })
234+
} ?? childNode.reference.sourceLanguage
227235

228-
let symbolReference = SymbolReference(edge.target, interfaceLanguage: language, symbol: symbolIndex[edge.target]?.symbol)
236+
let symbolReference = SymbolReference(edge.target, interfaceLanguage: language, symbol: symbolIndex[edge.target].flatMap { documentationCache[$0]?.symbol })
229237
guard let unresolved = UnresolvedTopicReference(symbolReference: symbolReference, bundle: bundle) else {
230238
// The symbol reference format is invalid.
231239
engine.emit(NodeProblem.invalidReference(symbolReference.path))
@@ -267,14 +275,16 @@ struct SymbolGraphRelationshipsBuilder {
267275
edge: SymbolGraph.Relationship,
268276
selector: UnifiedSymbolGraph.Selector,
269277
in bundle: DocumentationBundle,
270-
symbolIndex: inout [String: DocumentationNode],
278+
symbolIndex: inout [String: ResolvedTopicReference],
279+
documentationCache: [ResolvedTopicReference: DocumentationNode],
271280
engine: DiagnosticEngine
272281
) {
273282
addProtocolRelationship(
274283
edge: edge,
275284
selector: selector,
276285
in: bundle,
277286
symbolIndex: &symbolIndex,
287+
documentationCache: documentationCache,
278288
engine: engine,
279289
required: true
280290
)
@@ -291,14 +301,16 @@ struct SymbolGraphRelationshipsBuilder {
291301
edge: SymbolGraph.Relationship,
292302
selector: UnifiedSymbolGraph.Selector,
293303
in bundle: DocumentationBundle,
294-
symbolIndex: inout [String: DocumentationNode],
304+
symbolIndex: inout [String: ResolvedTopicReference],
305+
documentationCache: [ResolvedTopicReference: DocumentationNode],
295306
engine: DiagnosticEngine
296307
) {
297308
addProtocolRelationship(
298309
edge: edge,
299310
selector: selector,
300311
in: bundle,
301312
symbolIndex: &symbolIndex,
313+
documentationCache: documentationCache,
302314
engine: engine,
303315
required: false
304316
)
@@ -316,12 +328,15 @@ struct SymbolGraphRelationshipsBuilder {
316328
edge: SymbolGraph.Relationship,
317329
selector: UnifiedSymbolGraph.Selector,
318330
in bundle: DocumentationBundle,
319-
symbolIndex: inout [String: DocumentationNode],
331+
symbolIndex: inout [String: ResolvedTopicReference],
332+
documentationCache: [ResolvedTopicReference: DocumentationNode],
320333
engine: DiagnosticEngine, required: Bool
321334
) {
322335
// Resolve source symbol
323-
guard let requiredNode = symbolIndex[edge.source],
324-
let requiredSymbol = requiredNode.semantic as? Symbol else {
336+
guard let requiredNodeRef = symbolIndex[edge.source],
337+
let requiredNode = documentationCache[requiredNodeRef],
338+
let requiredSymbol = requiredNode.semantic as? Symbol
339+
else {
325340
// The source node for requirement relationship not found.
326341
engine.emit(NodeProblem.notFound(edge.source))
327342
return
@@ -341,8 +356,8 @@ struct SymbolGraphRelationshipsBuilder {
341356
static func addInheritedDefaultImplementation(
342357
edge: SymbolGraph.Relationship,
343358
context: DocumentationContext,
344-
symbolIndex: inout [String: DocumentationNode],
345-
moduleName: String,
359+
symbolIndex: inout [String: ResolvedTopicReference],
360+
moduleName: String,
346361
engine: DiagnosticEngine
347362
) {
348363
func setAsInheritedSymbol(origin: SymbolGraph.Relationship.SourceOrigin, for node: inout DocumentationNode, originNode: DocumentationNode?) {
@@ -374,13 +389,11 @@ struct SymbolGraphRelationshipsBuilder {
374389
// verify we have the matching data in symbolIndex and documentationCache
375390
// and add the origin data to the symbol.
376391
if let origin = edge.mixins[SymbolGraph.Relationship.SourceOrigin.mixinKey] as? SymbolGraph.Relationship.SourceOrigin,
377-
let node = symbolIndex[edge.source],
378-
node.semantic is Symbol,
379-
context.documentationCache.keys.contains(node.reference) {
380-
392+
let reference = symbolIndex[edge.source],
393+
context.documentationCache[reference]?.semantic is Symbol
394+
{
381395
// OK to unwrap - we've verified the existence of the key above.
382-
setAsInheritedSymbol(origin: origin, for: &symbolIndex[edge.source]!, originNode: symbolIndex[origin.identifier])
383-
setAsInheritedSymbol(origin: origin, for: &context.documentationCache[node.reference]!, originNode: symbolIndex[origin.identifier])
396+
setAsInheritedSymbol(origin: origin, for: &context.documentationCache[reference]!, originNode: symbolIndex[origin.identifier].flatMap { context.documentationCache[$0] })
384397
}
385398
}
386399
}

0 commit comments

Comments
 (0)