@@ -49,6 +49,9 @@ pub struct DocFragment {
49
49
pub doc : Symbol ,
50
50
pub kind : DocFragmentKind ,
51
51
pub indent : usize ,
52
+ /// Because we tamper with the spans context, this information cannot be correctly retrieved
53
+ /// later on. So instead, we compute it and store it here.
54
+ pub from_expansion : bool ,
52
55
}
53
56
54
57
#[ derive( Clone , Copy , Debug ) ]
@@ -208,17 +211,18 @@ pub fn attrs_to_doc_fragments<'a, A: AttributeExt + Clone + 'a>(
208
211
for ( attr, item_id) in attrs {
209
212
if let Some ( ( doc_str, comment_kind) ) = attr. doc_str_and_comment_kind ( ) {
210
213
let doc = beautify_doc_string ( doc_str, comment_kind) ;
211
- let ( span, kind) = if attr. is_doc_comment ( ) {
212
- ( attr. span ( ) , DocFragmentKind :: SugaredDoc )
214
+ let ( span, kind, from_expansion) = if attr. is_doc_comment ( ) {
215
+ let span = attr. span ( ) ;
216
+ ( span, DocFragmentKind :: SugaredDoc , span. from_expansion ( ) )
213
217
} else {
214
- (
215
- attr. value_span ( )
216
- . map ( |i| i . with_ctxt ( attr . span ( ) . ctxt ( ) ) )
217
- . unwrap_or ( attr . span ( ) ) ,
218
- DocFragmentKind :: RawDoc ,
219
- )
218
+ let attr_span = attr . span ( ) ;
219
+ let ( span , from_expansion ) = match attr. value_span ( ) {
220
+ Some ( sp ) => ( sp . with_ctxt ( attr_span . ctxt ( ) ) , sp . from_expansion ( ) ) ,
221
+ None => ( attr_span , attr_span . from_expansion ( ) ) ,
222
+ } ;
223
+ ( span , DocFragmentKind :: RawDoc , from_expansion )
220
224
} ;
221
- let fragment = DocFragment { span, doc, kind, item_id, indent : 0 } ;
225
+ let fragment = DocFragment { span, doc, kind, item_id, indent : 0 , from_expansion } ;
222
226
doc_fragments. push ( fragment) ;
223
227
} else if !doc_only {
224
228
other_attrs. push ( attr. clone ( ) ) ;
@@ -505,17 +509,26 @@ fn collect_link_data<'input, F: BrokenLinkCallback<'input>>(
505
509
display_text. map ( String :: into_boxed_str)
506
510
}
507
511
508
- /// Returns a span encompassing all the document fragments.
509
- pub fn span_of_fragments ( fragments : & [ DocFragment ] ) -> Option < Span > {
510
- if fragments. is_empty ( ) {
511
- return None ;
512
- }
513
- let start = fragments[ 0 ] . span ;
514
- if start == DUMMY_SP {
512
+ /// Returns a tuple containing a span encompassing all the document fragments and a boolean that is
513
+ /// `true` if any of the fragments are from a macro expansion.
514
+ pub fn span_of_fragments_with_expansion ( fragments : & [ DocFragment ] ) -> Option < ( Span , bool ) > {
515
+ let ( first_fragment, last_fragment) = match fragments {
516
+ [ ] => return None ,
517
+ [ first, .., last] => ( first, last) ,
518
+ [ first] => ( first, first) ,
519
+ } ;
520
+ if first_fragment. span == DUMMY_SP {
515
521
return None ;
516
522
}
517
- let end = fragments. last ( ) . expect ( "no doc strings provided" ) . span ;
518
- Some ( start. to ( end) )
523
+ Some ( (
524
+ first_fragment. span . to ( last_fragment. span ) ,
525
+ fragments. iter ( ) . any ( |frag| frag. from_expansion ) ,
526
+ ) )
527
+ }
528
+
529
+ /// Returns a span encompassing all the document fragments.
530
+ pub fn span_of_fragments ( fragments : & [ DocFragment ] ) -> Option < Span > {
531
+ span_of_fragments_with_expansion ( fragments) . map ( |( sp, _) | sp)
519
532
}
520
533
521
534
/// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code.
@@ -529,18 +542,22 @@ pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> {
529
542
/// This method will return `Some` only if one of the following is true:
530
543
///
531
544
/// - The doc is made entirely from sugared doc comments, which cannot contain escapes
532
- /// - The doc is entirely from a single doc fragment with a string literal exactly equal to `markdown`.
545
+ /// - The doc is entirely from a single doc fragment with a string literal exactly equal to
546
+ /// `markdown`.
533
547
/// - The doc comes from `include_str!`
534
- /// - The doc includes exactly one substring matching `markdown[md_range]` which is contained in a single doc fragment.
548
+ /// - The doc includes exactly one substring matching `markdown[md_range]` which is contained in a
549
+ /// single doc fragment.
550
+ ///
551
+ /// This function is defined in the compiler so it can be used by both `rustdoc` and `clippy`.
535
552
///
536
- /// This function is defined in the compiler so it can be used by
537
- /// both `rustdoc` and `clippy` .
553
+ /// It returns a tuple containing a span encompassing all the document fragments and a boolean that
554
+ /// is `true` if any of the *matched* fragments are from a macro expansion .
538
555
pub fn source_span_for_markdown_range (
539
556
tcx : TyCtxt < ' _ > ,
540
557
markdown : & str ,
541
558
md_range : & Range < usize > ,
542
559
fragments : & [ DocFragment ] ,
543
- ) -> Option < Span > {
560
+ ) -> Option < ( Span , bool ) > {
544
561
let map = tcx. sess . source_map ( ) ;
545
562
source_span_for_markdown_range_inner ( map, markdown, md_range, fragments)
546
563
}
@@ -551,7 +568,7 @@ pub fn source_span_for_markdown_range_inner(
551
568
markdown : & str ,
552
569
md_range : & Range < usize > ,
553
570
fragments : & [ DocFragment ] ,
554
- ) -> Option < Span > {
571
+ ) -> Option < ( Span , bool ) > {
555
572
use rustc_span:: BytePos ;
556
573
557
574
if let & [ fragment] = & fragments
@@ -562,11 +579,14 @@ pub fn source_span_for_markdown_range_inner(
562
579
&& let Ok ( md_range_hi) = u32:: try_from ( md_range. end )
563
580
{
564
581
// Single fragment with string that contains same bytes as doc.
565
- return Some ( Span :: new (
566
- fragment. span . lo ( ) + rustc_span:: BytePos ( md_range_lo) ,
567
- fragment. span . lo ( ) + rustc_span:: BytePos ( md_range_hi) ,
568
- fragment. span . ctxt ( ) ,
569
- fragment. span . parent ( ) ,
582
+ return Some ( (
583
+ Span :: new (
584
+ fragment. span . lo ( ) + rustc_span:: BytePos ( md_range_lo) ,
585
+ fragment. span . lo ( ) + rustc_span:: BytePos ( md_range_hi) ,
586
+ fragment. span . ctxt ( ) ,
587
+ fragment. span . parent ( ) ,
588
+ ) ,
589
+ fragment. from_expansion ,
570
590
) ) ;
571
591
}
572
592
@@ -598,19 +618,21 @@ pub fn source_span_for_markdown_range_inner(
598
618
{
599
619
match_data = Some ( ( i, match_start) ) ;
600
620
} else {
601
- // Heirustic produced ambiguity, return nothing.
621
+ // Heuristic produced ambiguity, return nothing.
602
622
return None ;
603
623
}
604
624
}
605
625
}
606
626
if let Some ( ( i, match_start) ) = match_data {
607
- let sp = fragments[ i] . span ;
627
+ let fragment = & fragments[ i] ;
628
+ let sp = fragment. span ;
608
629
// we need to calculate the span start,
609
630
// then use that in our calulations for the span end
610
631
let lo = sp. lo ( ) + BytePos ( match_start as u32 ) ;
611
- return Some (
632
+ return Some ( (
612
633
sp. with_lo ( lo) . with_hi ( lo + BytePos ( ( md_range. end - md_range. start ) as u32 ) ) ,
613
- ) ;
634
+ fragment. from_expansion ,
635
+ ) ) ;
614
636
}
615
637
return None ;
616
638
}
@@ -664,8 +686,13 @@ pub fn source_span_for_markdown_range_inner(
664
686
}
665
687
}
666
688
667
- Some ( span_of_fragments ( fragments) ?. from_inner ( InnerSpan :: new (
689
+ let ( span, _) = span_of_fragments_with_expansion ( fragments) ?;
690
+ let src_span = span. from_inner ( InnerSpan :: new (
668
691
md_range. start + start_bytes,
669
692
md_range. end + start_bytes + end_bytes,
670
- ) ) )
693
+ ) ) ;
694
+ Some ( (
695
+ src_span,
696
+ fragments. iter ( ) . any ( |frag| frag. span . overlaps ( src_span) && frag. from_expansion ) ,
697
+ ) )
671
698
}
0 commit comments