about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2025-06-10 14:45:10 +0200
committerGuillaume Gomez <guillaume1.gomez@gmail.com>2025-06-23 16:12:49 +0200
commit3b5525bc420551c9c32ad3b5b6c8d673dd25da0d (patch)
tree304f09c14866deb8a3586273143c2f29d7b42f6f
parent78cbcaffeadcb85e4ea5d347010b13b5c698cbbd (diff)
downloadrust-3b5525bc420551c9c32ad3b5b6c8d673dd25da0d.tar.gz
rust-3b5525bc420551c9c32ad3b5b6c8d673dd25da0d.zip
Improve code and documentation
-rw-r--r--compiler/rustc_resolve/src/rustdoc.rs39
-rw-r--r--src/librustdoc/passes/lint/redundant_explicit_links.rs34
-rw-r--r--tests/rustdoc-ui/lints/redundant_explicit_links-expansion.rs14
-rw-r--r--tests/rustdoc-ui/lints/redundant_explicit_links-expansion.stderr20
4 files changed, 77 insertions, 30 deletions
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index 2d84178bede..3fe5db8ca54 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -49,7 +49,7 @@ pub struct DocFragment {
     pub doc: Symbol,
     pub kind: DocFragmentKind,
     pub indent: usize,
-    /// Because we temper with the spans context, this information cannot be correctly retrieved
+    /// Because we tamper with the spans context, this information cannot be correctly retrieved
     /// later on. So instead, we compute it and store it here.
     pub from_expansion: bool,
 }
@@ -509,16 +509,20 @@ fn collect_link_data<'input, F: BrokenLinkCallback<'input>>(
     display_text.map(String::into_boxed_str)
 }
 
-/// Returns a span encompassing all the document fragments.
+/// Returns a tuple containing a span encompassing all the document fragments and a boolean that is
+/// `true` if any of the fragments are from a macro expansion.
 pub fn span_of_fragments_with_expansion(fragments: &[DocFragment]) -> Option<(Span, bool)> {
-    let Some(first_fragment) = fragments.first() else { return None };
+    let (first_fragment, last_fragment) = match fragments {
+        [] => return None,
+        [first, .., last] => (first, last),
+        [first] => (first, first),
+    };
     if first_fragment.span == DUMMY_SP {
         return None;
     }
-    let last_fragment = fragments.last().expect("no doc strings provided");
     Some((
         first_fragment.span.to(last_fragment.span),
-        first_fragment.from_expansion || last_fragment.from_expansion,
+        fragments.iter().any(|frag| frag.from_expansion),
     ))
 }
 
@@ -538,12 +542,16 @@ pub fn span_of_fragments(fragments: &[DocFragment]) -> Option<Span> {
 /// This method will return `Some` only if one of the following is true:
 ///
 /// - The doc is made entirely from sugared doc comments, which cannot contain escapes
-/// - The doc is entirely from a single doc fragment with a string literal exactly equal to `markdown`.
+/// - The doc is entirely from a single doc fragment with a string literal exactly equal to
+///   `markdown`.
 /// - The doc comes from `include_str!`
-/// - The doc includes exactly one substring matching `markdown[md_range]` which is contained in a single doc fragment.
+/// - The doc includes exactly one substring matching `markdown[md_range]` which is contained in a
+///   single doc fragment.
+///
+/// This function is defined in the compiler so it can be used by both `rustdoc` and `clippy`.
 ///
-/// This function is defined in the compiler so it can be used by
-/// both `rustdoc` and `clippy`.
+/// It returns a tuple containing a span encompassing all the document fragments and a boolean that
+/// is `true` if any of the *matched* fragments are from a macro expansion.
 pub fn source_span_for_markdown_range(
     tcx: TyCtxt<'_>,
     markdown: &str,
@@ -678,12 +686,13 @@ pub fn source_span_for_markdown_range_inner(
         }
     }
 
-    let (span, from_expansion) = span_of_fragments_with_expansion(fragments)?;
+    let (span, _) = span_of_fragments_with_expansion(fragments)?;
+    let src_span = span.from_inner(InnerSpan::new(
+        md_range.start + start_bytes,
+        md_range.end + start_bytes + end_bytes,
+    ));
     Some((
-        span.from_inner(InnerSpan::new(
-            md_range.start + start_bytes,
-            md_range.end + start_bytes + end_bytes,
-        )),
-        from_expansion,
+        src_span,
+        fragments.iter().any(|frag| frag.span.overlaps(src_span) && frag.from_expansion),
     ))
 }
diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs
index 0482bc1058f..5757b6a9740 100644
--- a/src/librustdoc/passes/lint/redundant_explicit_links.rs
+++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs
@@ -171,21 +171,26 @@ fn check_inline_or_reference_unknown_redundancy(
                 }
                 None => item.attr_span(cx.tcx),
             };
-        let (explicit_span, from_expansion) = source_span_for_markdown_range(
+        let (explicit_span, false) = source_span_for_markdown_range(
             cx.tcx,
             doc,
             &offset_explicit_range(doc, link_range, open, close),
             &item.attrs.doc_strings,
-        )?;
-        if from_expansion {
+        )?
+        else {
+            // This `span` comes from macro expansion so skipping it.
             return None;
-        }
-        let (display_span, _) = source_span_for_markdown_range(
+        };
+        let (display_span, false) = source_span_for_markdown_range(
             cx.tcx,
             doc,
             resolvable_link_range,
             &item.attrs.doc_strings,
-        )?;
+        )?
+        else {
+            // This `span` comes from macro expansion so skipping it.
+            return None;
+        };
 
         cx.tcx.node_span_lint(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, |lint| {
             lint.primary_message("redundant explicit link target")
@@ -227,21 +232,26 @@ fn check_reference_redundancy(
                 }
                 None => item.attr_span(cx.tcx),
             };
-        let (explicit_span, from_expansion) = source_span_for_markdown_range(
+        let (explicit_span, false) = source_span_for_markdown_range(
             cx.tcx,
             doc,
             &offset_explicit_range(doc, link_range.clone(), b'[', b']'),
             &item.attrs.doc_strings,
-        )?;
-        if from_expansion {
+        )?
+        else {
+            // This `span` comes from macro expansion so skipping it.
             return None;
-        }
-        let (display_span, _) = source_span_for_markdown_range(
+        };
+        let (display_span, false) = source_span_for_markdown_range(
             cx.tcx,
             doc,
             resolvable_link_range,
             &item.attrs.doc_strings,
-        )?;
+        )?
+        else {
+            // This `span` comes from macro expansion so skipping it.
+            return None;
+        };
         let (def_span, _) = source_span_for_markdown_range(
             cx.tcx,
             doc,
diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links-expansion.rs b/tests/rustdoc-ui/lints/redundant_explicit_links-expansion.rs
index 8cb75ba4e18..2e42a0a5c5d 100644
--- a/tests/rustdoc-ui/lints/redundant_explicit_links-expansion.rs
+++ b/tests/rustdoc-ui/lints/redundant_explicit_links-expansion.rs
@@ -16,6 +16,12 @@ macro_rules! mac2 {
     }
 }
 
+macro_rules! mac3 {
+    () => {
+        "Provided by"
+    };
+}
+
 // Should not lint.
 #[doc = mac1!()]
 pub struct Foo;
@@ -24,5 +30,11 @@ pub struct Foo;
 mac2!{}
 
 #[doc = "provided by a [`BufferProvider`](crate::BufferProvider)."]
-//~^ ERROR: redundant_explicit_links
+/// bla
+//~^^ ERROR: redundant_explicit_links
 pub struct Bla;
+
+#[doc = mac3!()]
+/// a [`BufferProvider`](crate::BufferProvider).
+//~^ ERROR: redundant_explicit_links
+pub fn f() {}
diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links-expansion.stderr b/tests/rustdoc-ui/lints/redundant_explicit_links-expansion.stderr
index 0a38ec2aa6a..a81931fb073 100644
--- a/tests/rustdoc-ui/lints/redundant_explicit_links-expansion.stderr
+++ b/tests/rustdoc-ui/lints/redundant_explicit_links-expansion.stderr
@@ -1,5 +1,5 @@
 error: redundant explicit link target
-  --> $DIR/redundant_explicit_links-expansion.rs:26:43
+  --> $DIR/redundant_explicit_links-expansion.rs:32:43
    |
 LL | #[doc = "provided by a [`BufferProvider`](crate::BufferProvider)."]
    |                         ----------------  ^^^^^^^^^^^^^^^^^^^^^ explicit target is redundant
@@ -19,5 +19,21 @@ LL - #[doc = "provided by a [`BufferProvider`](crate::BufferProvider)."]
 LL + #[doc = "provided by a [`BufferProvider`]."]
    |
 
-error: aborting due to 1 previous error
+error: redundant explicit link target
+  --> $DIR/redundant_explicit_links-expansion.rs:38:26
+   |
+LL | /// a [`BufferProvider`](crate::BufferProvider).
+   |        ----------------  ^^^^^^^^^^^^^^^^^^^^^ explicit target is redundant
+   |        |
+   |        because label contains path that resolves to same destination
+   |
+   = note: when a link's destination is not specified,
+           the label is used to resolve intra-doc links
+help: remove explicit link target
+   |
+LL - /// a [`BufferProvider`](crate::BufferProvider).
+LL + /// a [`BufferProvider`].
+   |
+
+error: aborting due to 2 previous errors