Skip to content

Commit fd9a406

Browse files
authored
Merge alternate symbol declarations across symbol graphs (#933)
* Merges alternate symbol declarations across symbol graphs Fixes a bug with platform availability of a symbol's alternate declarations. This bug resulted in alternate symbol declarations only ever showing as having one supported platform, regardless of the symbol being declared across different symbol graphs for different platforms. The issue was caused by alternate declarations not being merged across different symbol graphs, so that platform availability information was only stored for the first symbol graph that was processed, and further platform availability information was lost. To fix this issue, `Symbol.mergeDeclaration(...)` now takes an extra parameter which takes in a list of alternate declarations from the symbol being merged in. Platform names are now merged across alternate declarations from different symbol graphs. * Updates alternate declarations test to include multiple platforms Updates `testAlternateDeclarations()` to validate that all supported platforms are propagated from the main declaration to any alternate declarations. Resolves rdar://128573538.
1 parent 037f0bc commit fd9a406

File tree

5 files changed

+408
-5
lines changed

5 files changed

+408
-5
lines changed

Sources/SwiftDocC/Semantics/ReferenceResolver.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,7 @@ struct ReferenceResolver: SemanticVisitor {
493493
deprecatedSummaryVariants: newDeprecatedSummaryVariants,
494494
mixinsVariants: symbol.mixinsVariants,
495495
declarationVariants: symbol.declarationVariants,
496+
alternateDeclarationVariants: symbol.alternateDeclarationVariants,
496497
defaultImplementationsVariants: symbol.defaultImplementationsVariants,
497498
relationshipsVariants: symbol.relationshipsVariants,
498499
abstractSectionVariants: newAbstractVariants,

Sources/SwiftDocC/Semantics/Symbol/Symbol.swift

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ public final class Symbol: Semantic, Abstracted, Redirected, AutomaticTaskGroups
265265
deprecatedSummaryVariants: DocumentationDataVariants<DeprecatedSection>,
266266
mixinsVariants: DocumentationDataVariants<[String: Mixin]>,
267267
declarationVariants: DocumentationDataVariants<[[PlatformName?]: SymbolGraph.Symbol.DeclarationFragments]> = .init(defaultVariantValue: [:]),
268+
alternateDeclarationVariants: DocumentationDataVariants<[[PlatformName?]: [SymbolGraph.Symbol.DeclarationFragments]]> = .init(defaultVariantValue: [:]),
268269
defaultImplementationsVariants: DocumentationDataVariants<DefaultImplementationsSection> = .init(defaultVariantValue: .init()),
269270
relationshipsVariants: DocumentationDataVariants<RelationshipsSection> = .init(),
270271
abstractSectionVariants: DocumentationDataVariants<AbstractSection>,
@@ -303,6 +304,7 @@ public final class Symbol: Semantic, Abstracted, Redirected, AutomaticTaskGroups
303304

304305
self.deprecatedSummaryVariants = deprecatedSummaryVariants
305306
self.declarationVariants = declarationVariants
307+
self.alternateDeclarationVariants = alternateDeclarationVariants
306308

307309
self.mixinsVariants = mixinsVariants
308310

@@ -320,8 +322,10 @@ public final class Symbol: Semantic, Abstracted, Redirected, AutomaticTaskGroups
320322
case let spi as SymbolGraph.Symbol.SPI:
321323
self.isSPIVariants[trait] = spi.isSPI
322324
case let alternateDeclarations as SymbolGraph.Symbol.AlternateDeclarations:
323-
self.alternateDeclarationVariants[trait] = [[platformNameVariants[trait]]: alternateDeclarations.declarations]
324-
325+
// If alternate declarations weren't set explicitly use the ones from the mixins.
326+
if !self.alternateDeclarationVariants.hasVariant(for: trait) {
327+
self.alternateDeclarationVariants[trait] = [[platformNameVariants[trait]]: alternateDeclarations.declarations]
328+
}
325329
case let attribute as SymbolGraph.Symbol.Minimum:
326330
attributes[.minimum] = attribute.value
327331
case let attribute as SymbolGraph.Symbol.Maximum:
@@ -443,7 +447,7 @@ extension Symbol {
443447
/// When building multi-platform documentation symbols might have more than one declaration
444448
/// depending on variances in their implementation across platforms (e.g. use `NSPoint` vs `CGPoint` parameter in a method).
445449
/// This method finds matching symbols between graphs and merges their declarations in case there are differences.
446-
func mergeDeclaration(mergingDeclaration: SymbolGraph.Symbol.DeclarationFragments, identifier: String, symbolAvailability: SymbolGraph.Symbol.Availability?, selector: UnifiedSymbolGraph.Selector) throws {
450+
func mergeDeclaration(mergingDeclaration: SymbolGraph.Symbol.DeclarationFragments, identifier: String, symbolAvailability: SymbolGraph.Symbol.Availability?, alternateDeclarations: SymbolGraph.Symbol.AlternateDeclarations?, selector: UnifiedSymbolGraph.Selector) throws {
447451
let trait = DocumentationDataVariantsTrait(for: selector)
448452
let platformName = selector.platform
449453

@@ -472,6 +476,35 @@ extension Symbol {
472476
declarationVariants[trait]?[[nil]] = mergingDeclaration
473477
}
474478
}
479+
480+
if let alternateDeclarations {
481+
let mergingAlternateDeclarations = alternateDeclarations.declarations
482+
if let platformName,
483+
let existingKey = alternateDeclarationVariants[trait]?.first(
484+
where: { pair in
485+
return pair.value.map { $0.declarationFragments } == mergingAlternateDeclarations.map { $0.declarationFragments }
486+
}
487+
)?.key
488+
{
489+
guard !existingKey.contains(nil) else {
490+
throw DocumentationContext.ContextError.unexpectedEmptyPlatformName(identifier)
491+
}
492+
493+
let platform = PlatformName(operatingSystemName: platformName)
494+
if !existingKey.contains(platform) {
495+
// Matches one of the existing declarations, append to the existing key.
496+
let currentDeclaration = alternateDeclarationVariants[trait]?.removeValue(forKey: existingKey)!
497+
alternateDeclarationVariants[trait]?[existingKey + [platform]] = currentDeclaration
498+
}
499+
} else {
500+
// Add new declaration
501+
if let name = platformName {
502+
alternateDeclarationVariants[trait]?[[PlatformName.init(operatingSystemName: name)]] = mergingAlternateDeclarations
503+
} else {
504+
alternateDeclarationVariants[trait]?[[nil]] = mergingAlternateDeclarations
505+
}
506+
}
507+
}
475508

476509
// Merge the new symbol with the existing availability. If a value already exist, only override if it's for this platform.
477510
if let symbolAvailability,
@@ -503,8 +536,9 @@ extension Symbol {
503536
for (selector, mixins) in unifiedSymbol.mixins {
504537
if let mergingDeclaration = mixins[SymbolGraph.Symbol.DeclarationFragments.mixinKey] as? SymbolGraph.Symbol.DeclarationFragments {
505538
let availability = mixins[SymbolGraph.Symbol.Availability.mixinKey] as? SymbolGraph.Symbol.Availability
539+
let alternateDeclarations = mixins[SymbolGraph.Symbol.AlternateDeclarations.mixinKey] as? SymbolGraph.Symbol.AlternateDeclarations
506540

507-
try mergeDeclaration(mergingDeclaration: mergingDeclaration, identifier: unifiedSymbol.uniqueIdentifier, symbolAvailability: availability, selector: selector)
541+
try mergeDeclaration(mergingDeclaration: mergingDeclaration, identifier: unifiedSymbol.uniqueIdentifier, symbolAvailability: availability, alternateDeclarations: alternateDeclarations, selector: selector)
508542
}
509543
}
510544
}

Tests/SwiftDocCTests/Rendering/DeclarationsRenderSectionTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,6 @@ class DeclarationsRenderSectionTests: XCTestCase {
149149
let declarationsSection = try XCTUnwrap(renderNode.primaryContentSections.compactMap({ $0 as? DeclarationsRenderSection }).first)
150150

151151
XCTAssertEqual(declarationsSection.declarations.count, 2)
152-
XCTAssert(declarationsSection.declarations.allSatisfy({ $0.platforms == [.macOS] }))
152+
XCTAssert(declarationsSection.declarations.allSatisfy({ $0.platforms == [.iOS, .macOS] }))
153153
}
154154
}

0 commit comments

Comments
 (0)