@@ -518,78 +518,91 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
518
518
let results = Synchronized < [ LinkResolveResult ] > ( [ ] )
519
519
results. sync ( { $0. reserveCapacity ( references. count) } )
520
520
521
+ func inheritsDocumentationFromOtherModule( _ documentationNode: DocumentationNode , symbolOriginReference: ResolvedTopicReference ) -> Bool {
522
+ // Check that this symbol only has documentation from an in-source documentation comment
523
+ guard documentationNode. docChunks. count == 1 ,
524
+ case . sourceCode = documentationNode. docChunks. first? . source
525
+ else {
526
+ return false
527
+ }
528
+
529
+ // Check that that documentation comment is inherited from a symbol belonging to another module
530
+ guard let symbolSemantic = documentationNode. semantic as? Symbol ,
531
+ let originSymbolSemantic = documentationCache [ symbolOriginReference] ? . semantic as? Symbol
532
+ else {
533
+ return false
534
+ }
535
+ return symbolSemantic. moduleReference != originSymbolSemantic. moduleReference
536
+ }
537
+
521
538
let resolveNodeWithReference : ( ResolvedTopicReference ) -> Void = { [ unowned self] reference in
522
- if var documentationNode = try ? entity ( with: reference) , documentationNode. semantic is Article || documentationNode. semantic is Symbol {
523
- for doc in documentationNode. docChunks {
524
- let source : URL ?
525
- switch doc. source {
526
- case _ where documentationNode. semantic is Article ,
527
- . documentationExtension:
528
- source = documentLocationMap [ reference]
529
- case . sourceCode( let location, _) :
530
- // For symbols, first check if we should reference resolve
531
- // inherited docs or not. If we don't inherit the docs
532
- // we should also skip reference resolving the chunk.
533
- if let semantic = documentationNode. semantic as? Symbol ,
534
- let origin = semantic. origin, !externalMetadata. inheritDocs
535
- {
536
- // If the two symbols are coming from different modules,
537
- // regardless if they are in the same bundle
538
- // (for example Foundation and SwiftUI), skip link resolving.
539
- if let originSymbol = documentationCache [ origin. identifier] ? . semantic as? Symbol ,
540
- originSymbol. moduleReference != semantic. moduleReference {
541
- continue
542
- }
543
- }
544
-
545
- source = location? . url ( )
546
- }
547
-
548
- // Find the inheritance parent, if the docs are inherited.
549
- let inheritanceParentReference : ResolvedTopicReference ?
550
- if let origin = ( documentationNode. semantic as? Symbol ) ? . origin,
551
- let originReference = documentationCache. reference ( symbolID: origin. identifier)
552
- {
553
- inheritanceParentReference = originReference
554
- } else {
555
- inheritanceParentReference = nil
556
- }
557
-
558
- var resolver = ReferenceResolver ( context: self , bundle: bundle, source: source, rootReference: reference, inheritanceParentReference: inheritanceParentReference)
539
+ guard var documentationNode = try ? entity ( with: reference) ,
540
+ documentationNode. semantic is Article || documentationNode. semantic is Symbol
541
+ else {
542
+ return
543
+ }
559
544
560
- // Update the cache with the resolved node.
561
- // We aggressively release used memory, since we're copying all semantic objects
562
- // on the line below while rewriting nodes with the resolved content.
563
- documentationNode. semantic = autoreleasepool { resolver. visit ( documentationNode. semantic) }
545
+ let symbolOriginReference = ( documentationNode. semantic as? Symbol ) ? . origin. flatMap { origin in
546
+ documentationCache. reference ( symbolID: origin. identifier)
547
+ }
548
+ // Check if we should skip resolving links for inherited documentation from other modules.
549
+ if !externalMetadata. inheritDocs,
550
+ let symbolOriginReference,
551
+ inheritsDocumentationFromOtherModule ( documentationNode, symbolOriginReference: symbolOriginReference)
552
+ {
553
+ // Don't resolve any links for this symbol.
554
+ return
555
+ }
556
+
557
+ var resolver = ReferenceResolver ( context: self , bundle: bundle, rootReference: reference, inheritanceParentReference: symbolOriginReference)
558
+
559
+ // Update the node with the markup that contains resolved references instead of authored links.
560
+ documentationNode. semantic = autoreleasepool {
561
+ // We use an autorelease pool to release used memory as soon as possible, since the resolver will copy each semantic value
562
+ // to rewrite it and replace the authored links with resolved reference strings instead.
563
+ resolver. visit ( documentationNode. semantic)
564
+ }
565
+
566
+ let problems : [ Problem ]
567
+ if documentationNode. semantic is Article {
568
+ // Diagnostics for articles have correct source ranges and don't need to be modified.
569
+ problems = resolver. problems
570
+ } else {
571
+ // Diagnostics for in-source documentation comments need to be offset based on the start location of the comment in the source file.
572
+
573
+ // Get the source location
574
+ let inSourceDocumentationCommentInfo = documentationNode. inSourceDocumentationChunk
575
+
576
+ // Post-process and filter out unwanted diagnostics (for example from inherited documentation comments)
577
+ problems = resolver. problems. compactMap { problem in
578
+ guard let source = problem. diagnostic. source else {
579
+ // Ignore any diagnostic without a source location. These can't be meaningfully presented to the user.
580
+ return nil
581
+ }
564
582
565
- let pageImageProblems = documentationNode. metadata? . pageImages. compactMap { pageImage in
566
- return resolver. resolve (
567
- resource: pageImage. source,
568
- range: pageImage. originalMarkup. range,
569
- severity: . warning
570
- )
571
- } ?? [ ]
583
+ if source == inSourceDocumentationCommentInfo? . url, let offset = inSourceDocumentationCommentInfo? . offset {
584
+ // Diagnostics from an in-source documentation comment need to be offset based on the location of that documentation comment.
585
+ var modifiedProblem = problem
586
+ modifiedProblem. offsetWithRange ( offset)
587
+ return modifiedProblem
588
+ }
572
589
573
- resolver. problems. append ( contentsOf: pageImageProblems)
574
-
575
- var problems = resolver. problems
576
-
577
- if case . sourceCode( _, let offset) = doc. source, documentationNode. kind. isSymbol {
578
- // Offset all problem ranges by the start location of the
579
- // source comment in the context of the complete file.
580
- if let docRange = offset {
581
- for i in problems. indices {
582
- problems [ i] . offsetWithRange ( docRange)
583
- }
584
- } else {
585
- problems. removeAll ( )
586
- }
587
- }
588
-
589
- let result : LinkResolveResult = ( reference: reference, node: documentationNode, problems: problems)
590
- results. sync ( { $0. append ( result) } )
590
+ // Diagnostics from documentation extension files have correct source ranges and don't need to be modified.
591
+ return problem
591
592
}
592
593
}
594
+
595
+ // Also resolve the node's page images. This isn't part of the node's 'semantic' value (resolved above).
596
+ let pageImageProblems = documentationNode. metadata? . pageImages. compactMap { pageImage in
597
+ return resolver. resolve (
598
+ resource: pageImage. source,
599
+ range: pageImage. originalMarkup. range,
600
+ severity: . warning
601
+ )
602
+ } ?? [ ]
603
+
604
+ let result : LinkResolveResult = ( reference: reference, node: documentationNode, problems: problems + pageImageProblems)
605
+ results. sync ( { $0. append ( result) } )
593
606
}
594
607
595
608
// Resolve links concurrently if there are no external resolvers.
@@ -604,7 +617,8 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
604
617
// Record symbol links as symbol "mentions" for automatic cross references
605
618
// on rendered symbol documentation.
606
619
if let article = result. node. semantic as? Article ,
607
- case . article = DocumentationContentRenderer . roleForArticle ( article, nodeKind: result. node. kind) {
620
+ case . article = DocumentationContentRenderer . roleForArticle ( article, nodeKind: result. node. kind)
621
+ {
608
622
for markup in article. abstractSection? . content ?? [ ] {
609
623
var mentions = SymbolLinkCollector ( context: self , article: result. node. reference, baseWeight: 2 )
610
624
mentions. visit ( markup)
@@ -652,7 +666,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
652
666
autoreleasepool {
653
667
let url = technologyResult. source
654
668
let unresolvedTechnology = technologyResult. value
655
- var resolver = ReferenceResolver ( context: self , bundle: bundle, source : url )
669
+ var resolver = ReferenceResolver ( context: self , bundle: bundle)
656
670
let technology = resolver. visit ( unresolvedTechnology) as! Technology
657
671
diagnosticEngine. emit ( resolver. problems)
658
672
@@ -724,7 +738,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
724
738
autoreleasepool {
725
739
let url = tutorialResult. source
726
740
let unresolvedTutorial = tutorialResult. value
727
- var resolver = ReferenceResolver ( context: self , bundle: bundle, source : url )
741
+ var resolver = ReferenceResolver ( context: self , bundle: bundle)
728
742
let tutorial = resolver. visit ( unresolvedTutorial) as! Tutorial
729
743
diagnosticEngine. emit ( resolver. problems)
730
744
@@ -758,7 +772,7 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
758
772
autoreleasepool {
759
773
let url = articleResult. source
760
774
let unresolvedTutorialArticle = articleResult. value
761
- var resolver = ReferenceResolver ( context: self , bundle: bundle, source : url )
775
+ var resolver = ReferenceResolver ( context: self , bundle: bundle)
762
776
let article = resolver. visit ( unresolvedTutorialArticle) as! TutorialArticle
763
777
diagnosticEngine. emit ( resolver. problems)
764
778
0 commit comments