From bc6df5117b120f17d27faf51451a61215ab141fc Mon Sep 17 00:00:00 2001 From: Andrea Fernandez Buitrago <15234535+anferbui@users.noreply.github.com> Date: Tue, 19 Nov 2024 12:40:20 +0000 Subject: [PATCH] More checks for clashing source languages --- .../Infrastructure/DocumentationContext.swift | 37 ++++++++++++++++++- .../Semantics/Metadata/Metadata.swift | 2 +- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/Sources/SwiftDocC/Infrastructure/DocumentationContext.swift b/Sources/SwiftDocC/Infrastructure/DocumentationContext.swift index 1beb5a39c..6d8bee694 100644 --- a/Sources/SwiftDocC/Infrastructure/DocumentationContext.swift +++ b/Sources/SwiftDocC/Infrastructure/DocumentationContext.swift @@ -3136,12 +3136,14 @@ extension DocumentationContext { for node in topicGraph.nodes.values { guard let entity = try? self.entity(with: node.reference) else { continue } + var sourceLanguageToReference: [SourceLanguage: AlternateDeclaration] = [:] for alternateDeclaration in entity.metadata?.alternateDeclarations ?? [] { guard case .resolved(.success(let counterpartReference)) = alternateDeclaration.counterpart, let counterpartEntity = try? self.entity(with: counterpartReference) else { continue } + // Case where the original symbol already was defined in the languages of the counterpart symbol. let duplicateSourceLanguages = counterpartEntity.availableSourceLanguages.intersection(entity.availableSourceLanguages) duplicateSourceLanguages.forEach { duplicateSourceLanguage in problems @@ -3151,13 +3153,46 @@ extension DocumentationContext { source: alternateDeclaration.originalMarkup.range?.source, severity: .warning, range: alternateDeclaration.originalMarkup.range, - identifier: "org.swift.docc.AlternateDeclaration.DuplicateSourceLanguage", + identifier: "org.swift.docc.AlternateDeclaration.DuplicateLanguageDefinition", summary: "This node already has a declaration in \(duplicateSourceLanguage.name)", + explanation: "This node is already available in \(entity.availableSourceLanguages.map { $0.name }.joined(separator: ", ")).", ), possibleSolutions: [Solution(summary: "Replace the counterpart link with a node which isn't available in \(entity.availableSourceLanguages.map { $0.name }.joined(separator: ", "))", replacements: [])] ) ) } + + let duplicateCounterpartLanguages = Set(sourceLanguageToReference.keys).intersection(counterpartEntity.availableSourceLanguages) + duplicateCounterpartLanguages.forEach { duplicateSourceLanguage in + let replacements = alternateDeclaration.originalMarkup.range.flatMap { [Replacement(range: $0, replacement: "")] } ?? [] + let notes: [DiagnosticNote] = sourceLanguageToReference[duplicateSourceLanguage].flatMap { + guard let range = $0.originalMarkup.range, let source = range.source else { return nil } + + return [ + DiagnosticNote(source: source, range: range, message: """ + An alternate declaration for \(duplicateSourceLanguage.name) has already been defined by an @\(AlternateDeclaration.self) directive. + """) + ] + } ?? [] + problems + .append( + Problem( + diagnostic: Diagnostic( + source: alternateDeclaration.originalMarkup.range?.source, + severity: .warning, + range: alternateDeclaration.originalMarkup.range, + identifier: "org.swift.docc.AlternateDeclaration.DuplicateLanguageDefinition", + summary: "An alternate declaration for \(duplicateSourceLanguage.name) already exists", + explanation: "This node is already available in \(sourceLanguageToReference.keys.map { $0.name }.joined(separator: ", ")).", + notes: notes + ), + possibleSolutions: [Solution(summary: "Remove this alternate declaration", replacements: replacements)] + ) + ) + } + + // Update mapping from source language to alternate declaration, for diagnostic purposes + counterpartEntity.availableSourceLanguages.forEach { sourceLanguageToReference[$0] = alternateDeclaration } } } diff --git a/Sources/SwiftDocC/Semantics/Metadata/Metadata.swift b/Sources/SwiftDocC/Semantics/Metadata/Metadata.swift index c85a22a68..6e29d5134 100644 --- a/Sources/SwiftDocC/Semantics/Metadata/Metadata.swift +++ b/Sources/SwiftDocC/Semantics/Metadata/Metadata.swift @@ -124,7 +124,7 @@ public final class Metadata: Semantic, AutomaticDirectiveConvertible { validateDuplicates(in: pageImages, uniqueBy: \.purpose, keyName: "purpose", problems: &problems) validateDuplicates(in: availability, uniqueBy: \.platform, keyName: "platform", problems: &problems) - validateDuplicates(in: alternateDeclarations, uniqueBy: \.counterpart, keyName: "language", problems: &problems) + validateDuplicates(in: alternateDeclarations, uniqueBy: \.counterpart, keyName: "counterpart", problems: &problems) return true }