Auto merge of #113167 - ChAoSUnItY:redundant_explicit_link, r=GuillaumeGomez
rustdoc: Add lint `redundant_explicit_links` Closes #87799. - Lint warns by default - Reworks link parser to cache original link's display text r? `@jyn514`
This commit is contained in:
commit
9c699a40cc
24 changed files with 2066 additions and 118 deletions
|
@ -30,7 +30,7 @@ pub use super::{
|
|||
/// will be retrieved.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum ConsumerOptions {
|
||||
/// Retrieve the [`Body`] along with the [`BorrowSet`](super::borrow_set::BorrowSet)
|
||||
/// Retrieve the [`Body`] along with the [`BorrowSet`]
|
||||
/// and [`RegionInferenceContext`]. If you would like the body only, use
|
||||
/// [`TyCtxt::mir_promoted`].
|
||||
///
|
||||
|
|
|
@ -452,11 +452,11 @@ struct HandlerInner {
|
|||
/// have been converted.
|
||||
check_unstable_expect_diagnostics: bool,
|
||||
|
||||
/// Expected [`Diagnostic`][diagnostic::Diagnostic]s store a [`LintExpectationId`] as part of
|
||||
/// Expected [`Diagnostic`][struct@diagnostic::Diagnostic]s store a [`LintExpectationId`] as part of
|
||||
/// the lint level. [`LintExpectationId`]s created early during the compilation
|
||||
/// (before `HirId`s have been defined) are not stable and can therefore not be
|
||||
/// stored on disk. This buffer stores these diagnostics until the ID has been
|
||||
/// replaced by a stable [`LintExpectationId`]. The [`Diagnostic`][diagnostic::Diagnostic]s are the
|
||||
/// replaced by a stable [`LintExpectationId`]. The [`Diagnostic`][struct@diagnostic::Diagnostic]s are the
|
||||
/// submitted for storage and added to the list of fulfilled expectations.
|
||||
unstable_expect_diagnostics: Vec<Diagnostic>,
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use pulldown_cmark::{BrokenLink, Event, LinkType, Options, Parser, Tag};
|
||||
use pulldown_cmark::{BrokenLink, CowStr, Event, LinkType, Options, Parser, Tag};
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::util::comments::beautify_doc_string;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
@ -392,16 +392,73 @@ pub(crate) fn attrs_to_preprocessed_links(attrs: &[ast::Attribute]) -> Vec<Box<s
|
|||
let (doc_fragments, _) = attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), true);
|
||||
let doc = prepare_to_doc_link_resolution(&doc_fragments).into_values().next().unwrap();
|
||||
|
||||
Parser::new_with_broken_link_callback(
|
||||
parse_links(&doc)
|
||||
}
|
||||
|
||||
/// Similiar version of `markdown_links` from rustdoc.
|
||||
/// This will collect destination links and display text if exists.
|
||||
fn parse_links<'md>(doc: &'md str) -> Vec<Box<str>> {
|
||||
let mut broken_link_callback = |link: BrokenLink<'md>| Some((link.reference, "".into()));
|
||||
let mut event_iter = Parser::new_with_broken_link_callback(
|
||||
&doc,
|
||||
main_body_opts(),
|
||||
Some(&mut |link: BrokenLink<'_>| Some((link.reference, "".into()))),
|
||||
Some(&mut broken_link_callback),
|
||||
)
|
||||
.filter_map(|event| match event {
|
||||
Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => {
|
||||
Some(preprocess_link(&dest))
|
||||
.into_iter();
|
||||
let mut links = Vec::new();
|
||||
|
||||
while let Some(event) = event_iter.next() {
|
||||
match event {
|
||||
Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => {
|
||||
if matches!(
|
||||
link_type,
|
||||
LinkType::Inline
|
||||
| LinkType::ReferenceUnknown
|
||||
| LinkType::Reference
|
||||
| LinkType::Shortcut
|
||||
| LinkType::ShortcutUnknown
|
||||
) {
|
||||
if let Some(display_text) = collect_link_data(&mut event_iter) {
|
||||
links.push(display_text);
|
||||
}
|
||||
}
|
||||
|
||||
links.push(preprocess_link(&dest));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
links
|
||||
}
|
||||
|
||||
/// Collects additional data of link.
|
||||
fn collect_link_data<'input, 'callback>(
|
||||
event_iter: &mut Parser<'input, 'callback>,
|
||||
) -> Option<Box<str>> {
|
||||
let mut display_text: Option<String> = None;
|
||||
let mut append_text = |text: CowStr<'_>| {
|
||||
if let Some(display_text) = &mut display_text {
|
||||
display_text.push_str(&text);
|
||||
} else {
|
||||
display_text = Some(text.to_string());
|
||||
}
|
||||
};
|
||||
|
||||
while let Some(event) = event_iter.next() {
|
||||
match event {
|
||||
Event::Text(text) => {
|
||||
append_text(text);
|
||||
}
|
||||
Event::Code(code) => {
|
||||
append_text(code);
|
||||
}
|
||||
Event::End(_) => {
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
display_text.map(String::into_boxed_str)
|
||||
}
|
||||
|
|
|
@ -89,6 +89,7 @@
|
|||
#![allow(explicit_outlives_requirements)]
|
||||
#![warn(multiple_supertrait_upcastable)]
|
||||
#![cfg_attr(not(bootstrap), allow(internal_features))]
|
||||
#![cfg_attr(not(bootstrap), allow(rustdoc::redundant_explicit_links))]
|
||||
//
|
||||
// Library features:
|
||||
// tidy-alphabetical-start
|
||||
|
|
|
@ -153,7 +153,7 @@ macro_rules! acquire {
|
|||
///
|
||||
/// ## `Deref` behavior
|
||||
///
|
||||
/// `Arc<T>` automatically dereferences to `T` (via the [`Deref`][deref] trait),
|
||||
/// `Arc<T>` automatically dereferences to `T` (via the [`Deref`] trait),
|
||||
/// so you can call `T`'s methods on a value of type `Arc<T>`. To avoid name
|
||||
/// clashes with `T`'s methods, the methods of `Arc<T>` itself are associated
|
||||
/// functions, called using [fully qualified syntax]:
|
||||
|
@ -187,7 +187,6 @@ macro_rules! acquire {
|
|||
/// [mutex]: ../../std/sync/struct.Mutex.html
|
||||
/// [rwlock]: ../../std/sync/struct.RwLock.html
|
||||
/// [atomic]: core::sync::atomic
|
||||
/// [deref]: core::ops::Deref
|
||||
/// [downgrade]: Arc::downgrade
|
||||
/// [upgrade]: Weak::upgrade
|
||||
/// [RefCell\<T>]: core::cell::RefCell
|
||||
|
@ -1495,7 +1494,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
|
|||
/// alignment as `T`. This is trivially true if `U` is `T`.
|
||||
/// Note that if `U` is not `T` but has the same size and alignment, this is
|
||||
/// basically like transmuting references of different types. See
|
||||
/// [`mem::transmute`][transmute] for more information on what
|
||||
/// [`mem::transmute`] for more information on what
|
||||
/// restrictions apply in this case.
|
||||
///
|
||||
/// The raw pointer must point to a block of memory allocated by `alloc`
|
||||
|
@ -1507,7 +1506,6 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
|
|||
/// even if the returned `Arc<T>` is never accessed.
|
||||
///
|
||||
/// [into_raw]: Arc::into_raw
|
||||
/// [transmute]: core::mem::transmute
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
@ -97,6 +97,8 @@
|
|||
#![allow(incomplete_features)]
|
||||
#![warn(multiple_supertrait_upcastable)]
|
||||
#![cfg_attr(not(bootstrap), allow(internal_features))]
|
||||
// Do not check link redundancy on bootstraping phase
|
||||
#![cfg_attr(not(bootstrap), allow(rustdoc::redundant_explicit_links))]
|
||||
//
|
||||
// Library features:
|
||||
// tidy-alphabetical-start
|
||||
|
|
|
@ -223,6 +223,7 @@
|
|||
#![cfg_attr(not(bootstrap), allow(internal_features))]
|
||||
#![deny(rustc::existing_doc_keyword)]
|
||||
#![deny(fuzzy_provenance_casts)]
|
||||
#![cfg_attr(not(bootstrap), allow(rustdoc::redundant_explicit_links))]
|
||||
// Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind`
|
||||
#![deny(ffi_unwind_calls)]
|
||||
// std may use features in a platform-specific way
|
||||
|
|
|
@ -412,3 +412,37 @@ help: if you meant to use a literal backtick, escape it
|
|||
|
||||
warning: 1 warning emitted
|
||||
```
|
||||
|
||||
## `redundant_explicit_links`
|
||||
|
||||
This lint is **warned by default**. It detects explicit links that are same
|
||||
as computed automatic links.
|
||||
This usually means the explicit links is removeable. For example:
|
||||
|
||||
```rust
|
||||
#![warn(rustdoc::redundant_explicit_links)] // note: unnecessary - warns by default.
|
||||
|
||||
/// add takes 2 [`usize`](usize) and performs addition
|
||||
/// on them, then returns result.
|
||||
pub fn add(left: usize, right: usize) -> usize {
|
||||
left + right
|
||||
}
|
||||
```
|
||||
|
||||
Which will give:
|
||||
|
||||
```text
|
||||
error: redundant explicit rustdoc link
|
||||
--> src/lib.rs:3:27
|
||||
|
|
||||
3 | /// add takes 2 [`usize`](usize) and performs addition
|
||||
| ^^^^^
|
||||
|
|
||||
= note: Explicit link does not affect the original link
|
||||
note: the lint level is defined here
|
||||
--> src/lib.rs:1:9
|
||||
|
|
||||
1 | #![deny(rustdoc::redundant_explicit_links)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= help: Remove explicit link instead
|
||||
```
|
||||
|
|
|
@ -50,7 +50,7 @@ use crate::html::render::small_url_encode;
|
|||
use crate::html::toc::TocBuilder;
|
||||
|
||||
use pulldown_cmark::{
|
||||
html, BrokenLink, CodeBlockKind, CowStr, Event, LinkType, Options, Parser, Tag,
|
||||
html, BrokenLink, CodeBlockKind, CowStr, Event, LinkType, OffsetIter, Options, Parser, Tag,
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1240,6 +1240,7 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin
|
|||
pub(crate) struct MarkdownLink {
|
||||
pub kind: LinkType,
|
||||
pub link: String,
|
||||
pub display_text: Option<String>,
|
||||
pub range: MarkdownLinkRange,
|
||||
}
|
||||
|
||||
|
@ -1263,8 +1264,8 @@ impl MarkdownLinkRange {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn markdown_links<R>(
|
||||
md: &str,
|
||||
pub(crate) fn markdown_links<'md, R>(
|
||||
md: &'md str,
|
||||
preprocess_link: impl Fn(MarkdownLink) -> Option<R>,
|
||||
) -> Vec<R> {
|
||||
if md.is_empty() {
|
||||
|
@ -1375,32 +1376,90 @@ pub(crate) fn markdown_links<R>(
|
|||
MarkdownLinkRange::Destination(range.clone())
|
||||
};
|
||||
|
||||
Parser::new_with_broken_link_callback(
|
||||
let mut broken_link_callback = |link: BrokenLink<'md>| Some((link.reference, "".into()));
|
||||
let mut event_iter = Parser::new_with_broken_link_callback(
|
||||
md,
|
||||
main_body_opts(),
|
||||
Some(&mut |link: BrokenLink<'_>| Some((link.reference, "".into()))),
|
||||
Some(&mut broken_link_callback),
|
||||
)
|
||||
.into_offset_iter()
|
||||
.filter_map(|(event, span)| match event {
|
||||
Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => {
|
||||
let range = match link_type {
|
||||
// Link is pulled from the link itself.
|
||||
LinkType::ReferenceUnknown | LinkType::ShortcutUnknown => {
|
||||
span_for_offset_backward(span, b'[', b']')
|
||||
.into_offset_iter();
|
||||
let mut links = Vec::new();
|
||||
|
||||
while let Some((event, span)) = event_iter.next() {
|
||||
match event {
|
||||
Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => {
|
||||
let range = match link_type {
|
||||
// Link is pulled from the link itself.
|
||||
LinkType::ReferenceUnknown | LinkType::ShortcutUnknown => {
|
||||
span_for_offset_backward(span, b'[', b']')
|
||||
}
|
||||
LinkType::CollapsedUnknown => span_for_offset_forward(span, b'[', b']'),
|
||||
LinkType::Inline => span_for_offset_backward(span, b'(', b')'),
|
||||
// Link is pulled from elsewhere in the document.
|
||||
LinkType::Reference | LinkType::Collapsed | LinkType::Shortcut => {
|
||||
span_for_link(&dest, span)
|
||||
}
|
||||
LinkType::Autolink | LinkType::Email => unreachable!(),
|
||||
};
|
||||
|
||||
let display_text = if matches!(
|
||||
link_type,
|
||||
LinkType::Inline
|
||||
| LinkType::ReferenceUnknown
|
||||
| LinkType::Reference
|
||||
| LinkType::Shortcut
|
||||
| LinkType::ShortcutUnknown
|
||||
) {
|
||||
collect_link_data(&mut event_iter)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(link) = preprocess_link(MarkdownLink {
|
||||
kind: link_type,
|
||||
link: dest.into_string(),
|
||||
display_text,
|
||||
range,
|
||||
}) {
|
||||
links.push(link);
|
||||
}
|
||||
LinkType::CollapsedUnknown => span_for_offset_forward(span, b'[', b']'),
|
||||
LinkType::Inline => span_for_offset_backward(span, b'(', b')'),
|
||||
// Link is pulled from elsewhere in the document.
|
||||
LinkType::Reference | LinkType::Collapsed | LinkType::Shortcut => {
|
||||
span_for_link(&dest, span)
|
||||
}
|
||||
LinkType::Autolink | LinkType::Email => unreachable!(),
|
||||
};
|
||||
preprocess_link(MarkdownLink { kind: link_type, range, link: dest.into_string() })
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
links
|
||||
}
|
||||
|
||||
/// Collects additional data of link.
|
||||
fn collect_link_data<'input, 'callback>(
|
||||
event_iter: &mut OffsetIter<'input, 'callback>,
|
||||
) -> Option<String> {
|
||||
let mut display_text: Option<String> = None;
|
||||
let mut append_text = |text: CowStr<'_>| {
|
||||
if let Some(display_text) = &mut display_text {
|
||||
display_text.push_str(&text);
|
||||
} else {
|
||||
display_text = Some(text.to_string());
|
||||
}
|
||||
};
|
||||
|
||||
while let Some((event, _span)) = event_iter.next() {
|
||||
match event {
|
||||
Event::Text(text) => {
|
||||
append_text(text);
|
||||
}
|
||||
Event::Code(code) => {
|
||||
append_text(code);
|
||||
}
|
||||
Event::End(_) => {
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
display_text
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -185,6 +185,17 @@ declare_rustdoc_lint! {
|
|||
"detects unescaped backticks in doc comments"
|
||||
}
|
||||
|
||||
declare_rustdoc_lint! {
|
||||
/// This lint is **warned by default**. It detects explicit links that are same
|
||||
/// as computed automatic links. This usually means the explicit links is removeable.
|
||||
/// This is a `rustdoc` only lint, see the documentation in the [rustdoc book].
|
||||
///
|
||||
/// [rustdoc book]: ../../../rustdoc/lints.html#redundant_explicit_links
|
||||
REDUNDANT_EXPLICIT_LINKS,
|
||||
Warn,
|
||||
"detects redundant explicit links in doc comments"
|
||||
}
|
||||
|
||||
pub(crate) static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| {
|
||||
vec![
|
||||
BROKEN_INTRA_DOC_LINKS,
|
||||
|
@ -197,6 +208,7 @@ pub(crate) static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| {
|
|||
BARE_URLS,
|
||||
MISSING_CRATE_LEVEL_DOCS,
|
||||
UNESCAPED_BACKTICKS,
|
||||
REDUNDANT_EXPLICIT_LINKS,
|
||||
]
|
||||
});
|
||||
|
||||
|
|
|
@ -994,7 +994,7 @@ impl LinkCollector<'_, '_> {
|
|||
_ => find_nearest_parent_module(self.cx.tcx, item_id).unwrap(),
|
||||
};
|
||||
for md_link in preprocessed_markdown_links(&doc) {
|
||||
let link = self.resolve_link(item, item_id, module_id, &doc, &md_link);
|
||||
let link = self.resolve_link(&doc, item, item_id, module_id, &md_link);
|
||||
if let Some(link) = link {
|
||||
self.cx.cache.intra_doc_links.entry(item.item_id).or_default().insert(link);
|
||||
}
|
||||
|
@ -1007,13 +1007,12 @@ impl LinkCollector<'_, '_> {
|
|||
/// FIXME(jynelson): this is way too many arguments
|
||||
fn resolve_link(
|
||||
&mut self,
|
||||
dox: &String,
|
||||
item: &Item,
|
||||
item_id: DefId,
|
||||
module_id: DefId,
|
||||
dox: &str,
|
||||
link: &PreprocessedMarkdownLink,
|
||||
PreprocessedMarkdownLink(pp_link, ori_link): &PreprocessedMarkdownLink,
|
||||
) -> Option<ItemLink> {
|
||||
let PreprocessedMarkdownLink(pp_link, ori_link) = link;
|
||||
trace!("considering link '{}'", ori_link.link);
|
||||
|
||||
let diag_info = DiagnosticInfo {
|
||||
|
@ -1022,7 +1021,6 @@ impl LinkCollector<'_, '_> {
|
|||
ori_link: &ori_link.link,
|
||||
link_range: ori_link.range.clone(),
|
||||
};
|
||||
|
||||
let PreprocessingInfo { path_str, disambiguator, extra_fragment, link_text } =
|
||||
pp_link.as_ref().map_err(|err| err.report(self.cx, diag_info.clone())).ok()?;
|
||||
let disambiguator = *disambiguator;
|
||||
|
@ -1040,8 +1038,24 @@ impl LinkCollector<'_, '_> {
|
|||
// resolutions are cached, for other links we want to report an error every
|
||||
// time so they are not cached.
|
||||
matches!(ori_link.kind, LinkType::Reference | LinkType::Shortcut),
|
||||
false,
|
||||
)?;
|
||||
|
||||
if ori_link.display_text.is_some() {
|
||||
self.resolve_display_text(
|
||||
path_str,
|
||||
ResolutionInfo {
|
||||
item_id,
|
||||
module_id,
|
||||
dis: disambiguator,
|
||||
path_str: ori_link.display_text.clone()?.into_boxed_str(),
|
||||
extra_fragment: extra_fragment.clone(),
|
||||
},
|
||||
&ori_link,
|
||||
&diag_info,
|
||||
);
|
||||
}
|
||||
|
||||
// Check for a primitive which might conflict with a module
|
||||
// Report the ambiguity and require that the user specify which one they meant.
|
||||
// FIXME: could there ever be a primitive not in the type namespace?
|
||||
|
@ -1221,6 +1235,9 @@ impl LinkCollector<'_, '_> {
|
|||
// If errors are cached then they are only reported on first occurrence
|
||||
// which we want in some cases but not in others.
|
||||
cache_errors: bool,
|
||||
// If this call is intended to be recoverable, then pass true to silence.
|
||||
// This is only recoverable when path is failed to resolved.
|
||||
recoverable: bool,
|
||||
) -> Option<(Res, Option<UrlFragment>)> {
|
||||
if let Some(res) = self.visited_links.get(&key) {
|
||||
if res.is_some() || cache_errors {
|
||||
|
@ -1228,7 +1245,7 @@ impl LinkCollector<'_, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
let mut candidates = self.resolve_with_disambiguator(&key, diag.clone());
|
||||
let mut candidates = self.resolve_with_disambiguator(&key, diag.clone(), recoverable);
|
||||
|
||||
// FIXME: it would be nice to check that the feature gate was enabled in the original crate, not just ignore it altogether.
|
||||
// However I'm not sure how to check that across crates.
|
||||
|
@ -1279,6 +1296,9 @@ impl LinkCollector<'_, '_> {
|
|||
&mut self,
|
||||
key: &ResolutionInfo,
|
||||
diag: DiagnosticInfo<'_>,
|
||||
// If this call is intended to be recoverable, then pass true to silence.
|
||||
// This is only recoverable when path is failed to resolved.
|
||||
recoverable: bool,
|
||||
) -> Vec<(Res, Option<DefId>)> {
|
||||
let disambiguator = key.dis;
|
||||
let path_str = &key.path_str;
|
||||
|
@ -1308,7 +1328,9 @@ impl LinkCollector<'_, '_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
resolution_failure(self, diag, path_str, disambiguator, smallvec![err]);
|
||||
if !recoverable {
|
||||
resolution_failure(self, diag, path_str, disambiguator, smallvec![err]);
|
||||
}
|
||||
return vec![];
|
||||
}
|
||||
}
|
||||
|
@ -1345,13 +1367,15 @@ impl LinkCollector<'_, '_> {
|
|||
.fold(0, |acc, res| if let Ok(res) = res { acc + res.len() } else { acc });
|
||||
|
||||
if len == 0 {
|
||||
resolution_failure(
|
||||
self,
|
||||
diag,
|
||||
path_str,
|
||||
disambiguator,
|
||||
candidates.into_iter().filter_map(|res| res.err()).collect(),
|
||||
);
|
||||
if !recoverable {
|
||||
resolution_failure(
|
||||
self,
|
||||
diag,
|
||||
path_str,
|
||||
disambiguator,
|
||||
candidates.into_iter().filter_map(|res| res.err()).collect(),
|
||||
);
|
||||
}
|
||||
return vec![];
|
||||
} else if len == 1 {
|
||||
candidates.into_iter().filter_map(|res| res.ok()).flatten().collect::<Vec<_>>()
|
||||
|
@ -1372,6 +1396,63 @@ impl LinkCollector<'_, '_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve display text if the provided link has separated parts of links.
|
||||
///
|
||||
/// For example:
|
||||
/// Inline link `[display_text](dest_link)` and reference link `[display_text][reference_link]` has
|
||||
/// separated parts of links.
|
||||
fn resolve_display_text(
|
||||
&mut self,
|
||||
explicit_link: &Box<str>,
|
||||
display_res_info: ResolutionInfo,
|
||||
ori_link: &MarkdownLink,
|
||||
diag_info: &DiagnosticInfo<'_>,
|
||||
) {
|
||||
// Check if explicit resolution's path is same as resolution of original link's display text path, see
|
||||
// tests/rustdoc-ui/lint/redundant_explicit_links.rs for more cases.
|
||||
//
|
||||
// To avoid disambiguator from panicking, we check if display text path is possible to be disambiguated
|
||||
// into explicit path.
|
||||
if !matches!(
|
||||
ori_link.kind,
|
||||
LinkType::Inline | LinkType::Reference | LinkType::ReferenceUnknown
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Algorithm to check if display text could possibly be the explicit link:
|
||||
//
|
||||
// Consider 2 links which are display text and explicit link, pick the shorter
|
||||
// one as symbol and longer one as full qualified path, and tries to match symbol
|
||||
// to the full qualified path's last symbol.
|
||||
//
|
||||
// Otherwise, check if 2 links are same, if so, skip the resolve process.
|
||||
//
|
||||
// Notice that this algorithm is passive, might possibly miss actual redudant cases.
|
||||
let explicit_link = &explicit_link.to_string();
|
||||
let display_text = ori_link.display_text.as_ref().unwrap();
|
||||
let display_len = display_text.len();
|
||||
let explicit_len = explicit_link.len();
|
||||
|
||||
if display_len == explicit_len {
|
||||
// Whether they are same or not, skip the resolve process.
|
||||
return;
|
||||
}
|
||||
|
||||
if (explicit_len >= display_len
|
||||
&& &explicit_link[(explicit_len - display_len)..] == display_text)
|
||||
|| (display_len >= explicit_len
|
||||
&& &display_text[(display_len - explicit_len)..] == explicit_link)
|
||||
{
|
||||
self.resolve_with_disambiguator_cached(
|
||||
display_res_info,
|
||||
diag_info.clone(), // this struct should really be Copy, but Range is not :(
|
||||
false,
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the section of a link between the backticks,
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
mod bare_urls;
|
||||
mod check_code_block_syntax;
|
||||
mod html_tags;
|
||||
mod redundant_explicit_links;
|
||||
mod unescaped_backticks;
|
||||
|
||||
use super::Pass;
|
||||
|
@ -29,6 +30,7 @@ impl<'a, 'tcx> DocVisitor for Linter<'a, 'tcx> {
|
|||
check_code_block_syntax::visit_item(self.cx, item);
|
||||
html_tags::visit_item(self.cx, item);
|
||||
unescaped_backticks::visit_item(self.cx, item);
|
||||
redundant_explicit_links::visit_item(self.cx, item);
|
||||
|
||||
self.visit_item_recur(item)
|
||||
}
|
||||
|
|
352
src/librustdoc/passes/lint/redundant_explicit_links.rs
Normal file
352
src/librustdoc/passes/lint/redundant_explicit_links.rs
Normal file
|
@ -0,0 +1,352 @@
|
|||
use std::ops::Range;
|
||||
|
||||
use pulldown_cmark::{BrokenLink, CowStr, Event, LinkType, OffsetIter, Parser, Tag};
|
||||
use rustc_ast::NodeId;
|
||||
use rustc_errors::SuggestionStyle;
|
||||
use rustc_hir::def::{DefKind, DocLinkResMap, Namespace, Res};
|
||||
use rustc_hir::HirId;
|
||||
use rustc_lint_defs::Applicability;
|
||||
use rustc_span::Symbol;
|
||||
|
||||
use crate::clean::utils::find_nearest_parent_module;
|
||||
use crate::clean::utils::inherits_doc_hidden;
|
||||
use crate::clean::Item;
|
||||
use crate::core::DocContext;
|
||||
use crate::html::markdown::main_body_opts;
|
||||
use crate::passes::source_span_for_markdown_range;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct LinkData {
|
||||
resolvable_link: Option<String>,
|
||||
resolvable_link_range: Option<Range<usize>>,
|
||||
display_link: String,
|
||||
}
|
||||
|
||||
pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
|
||||
let Some(hir_id) = DocContext::as_local_hir_id(cx.tcx, item.item_id) else {
|
||||
// If non-local, no need to check anything.
|
||||
return;
|
||||
};
|
||||
|
||||
let doc = item.doc_value();
|
||||
if doc.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
if item.link_names(&cx.cache).is_empty() {
|
||||
// If there's no link names in this item,
|
||||
// then we skip resolution querying to
|
||||
// avoid from panicking.
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(item_id) = item.def_id() else {
|
||||
return;
|
||||
};
|
||||
let Some(local_item_id) = item_id.as_local() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let is_hidden = !cx.render_options.document_hidden
|
||||
&& (item.is_doc_hidden() || inherits_doc_hidden(cx.tcx, local_item_id, None));
|
||||
if is_hidden {
|
||||
return;
|
||||
}
|
||||
let is_private = !cx.render_options.document_private
|
||||
&& !cx.cache.effective_visibilities.is_directly_public(cx.tcx, item_id);
|
||||
if is_private {
|
||||
return;
|
||||
}
|
||||
|
||||
check_redundant_explicit_link(cx, item, hir_id, &doc);
|
||||
}
|
||||
|
||||
fn check_redundant_explicit_link<'md>(
|
||||
cx: &DocContext<'_>,
|
||||
item: &Item,
|
||||
hir_id: HirId,
|
||||
doc: &'md str,
|
||||
) -> Option<()> {
|
||||
let mut broken_line_callback = |link: BrokenLink<'md>| Some((link.reference, "".into()));
|
||||
let mut offset_iter = Parser::new_with_broken_link_callback(
|
||||
&doc,
|
||||
main_body_opts(),
|
||||
Some(&mut broken_line_callback),
|
||||
)
|
||||
.into_offset_iter();
|
||||
let item_id = item.def_id()?;
|
||||
let module_id = match cx.tcx.def_kind(item_id) {
|
||||
DefKind::Mod if item.inner_docs(cx.tcx) => item_id,
|
||||
_ => find_nearest_parent_module(cx.tcx, item_id).unwrap(),
|
||||
};
|
||||
let resolutions = cx.tcx.doc_link_resolutions(module_id);
|
||||
|
||||
while let Some((event, link_range)) = offset_iter.next() {
|
||||
match event {
|
||||
Event::Start(Tag::Link(link_type, dest, _)) => {
|
||||
let link_data = collect_link_data(&mut offset_iter);
|
||||
|
||||
if let Some(resolvable_link) = link_data.resolvable_link.as_ref() {
|
||||
if &link_data.display_link.replace("`", "") != resolvable_link {
|
||||
// Skips if display link does not match to actual
|
||||
// resolvable link, usually happens if display link
|
||||
// has several segments, e.g.
|
||||
// [this is just an `Option`](Option)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let explicit_link = dest.to_string();
|
||||
let display_link = link_data.resolvable_link.clone()?;
|
||||
let explicit_len = explicit_link.len();
|
||||
let display_len = display_link.len();
|
||||
|
||||
if (explicit_len >= display_len
|
||||
&& &explicit_link[(explicit_len - display_len)..] == display_link)
|
||||
|| (display_len >= explicit_len
|
||||
&& &display_link[(display_len - explicit_len)..] == explicit_link)
|
||||
{
|
||||
match link_type {
|
||||
LinkType::Inline | LinkType::ReferenceUnknown => {
|
||||
check_inline_or_reference_unknown_redundancy(
|
||||
cx,
|
||||
item,
|
||||
hir_id,
|
||||
doc,
|
||||
resolutions,
|
||||
link_range,
|
||||
dest.to_string(),
|
||||
link_data,
|
||||
if link_type == LinkType::Inline {
|
||||
(b'(', b')')
|
||||
} else {
|
||||
(b'[', b']')
|
||||
},
|
||||
);
|
||||
}
|
||||
LinkType::Reference => {
|
||||
check_reference_redundancy(
|
||||
cx,
|
||||
item,
|
||||
hir_id,
|
||||
doc,
|
||||
resolutions,
|
||||
link_range,
|
||||
&dest,
|
||||
link_data,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// FIXME(ChAoSUnItY): Too many arguments.
|
||||
fn check_inline_or_reference_unknown_redundancy(
|
||||
cx: &DocContext<'_>,
|
||||
item: &Item,
|
||||
hir_id: HirId,
|
||||
doc: &str,
|
||||
resolutions: &DocLinkResMap,
|
||||
link_range: Range<usize>,
|
||||
dest: String,
|
||||
link_data: LinkData,
|
||||
(open, close): (u8, u8),
|
||||
) -> Option<()> {
|
||||
let (resolvable_link, resolvable_link_range) =
|
||||
(&link_data.resolvable_link?, &link_data.resolvable_link_range?);
|
||||
let (dest_res, display_res) =
|
||||
(find_resolution(resolutions, &dest)?, find_resolution(resolutions, resolvable_link)?);
|
||||
|
||||
if dest_res == display_res {
|
||||
let link_span = source_span_for_markdown_range(cx.tcx, &doc, &link_range, &item.attrs)
|
||||
.unwrap_or(item.attr_span(cx.tcx));
|
||||
let explicit_span = source_span_for_markdown_range(
|
||||
cx.tcx,
|
||||
&doc,
|
||||
&offset_explicit_range(doc, link_range, open, close),
|
||||
&item.attrs,
|
||||
)?;
|
||||
let display_span =
|
||||
source_span_for_markdown_range(cx.tcx, &doc, &resolvable_link_range, &item.attrs)?;
|
||||
|
||||
cx.tcx.struct_span_lint_hir(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, "redundant explicit link target", |lint| {
|
||||
lint.span_label(explicit_span, "explicit target is redundant")
|
||||
.span_label(display_span, "because label contains path that resolves to same destination")
|
||||
.note("when a link's destination is not specified,\nthe label is used to resolve intra-doc links")
|
||||
.span_suggestion_with_style(link_span, "remove explicit link target", format!("[{}]", link_data.display_link), Applicability::MaybeIncorrect, SuggestionStyle::ShowAlways);
|
||||
|
||||
lint
|
||||
});
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// FIXME(ChAoSUnItY): Too many arguments.
|
||||
fn check_reference_redundancy(
|
||||
cx: &DocContext<'_>,
|
||||
item: &Item,
|
||||
hir_id: HirId,
|
||||
doc: &str,
|
||||
resolutions: &DocLinkResMap,
|
||||
link_range: Range<usize>,
|
||||
dest: &CowStr<'_>,
|
||||
link_data: LinkData,
|
||||
) -> Option<()> {
|
||||
let (resolvable_link, resolvable_link_range) =
|
||||
(&link_data.resolvable_link?, &link_data.resolvable_link_range?);
|
||||
let (dest_res, display_res) =
|
||||
(find_resolution(resolutions, &dest)?, find_resolution(resolutions, resolvable_link)?);
|
||||
|
||||
if dest_res == display_res {
|
||||
let link_span = source_span_for_markdown_range(cx.tcx, &doc, &link_range, &item.attrs)
|
||||
.unwrap_or(item.attr_span(cx.tcx));
|
||||
let explicit_span = source_span_for_markdown_range(
|
||||
cx.tcx,
|
||||
&doc,
|
||||
&offset_explicit_range(doc, link_range.clone(), b'[', b']'),
|
||||
&item.attrs,
|
||||
)?;
|
||||
let display_span =
|
||||
source_span_for_markdown_range(cx.tcx, &doc, &resolvable_link_range, &item.attrs)?;
|
||||
let def_span = source_span_for_markdown_range(
|
||||
cx.tcx,
|
||||
&doc,
|
||||
&offset_reference_def_range(doc, dest, link_range),
|
||||
&item.attrs,
|
||||
)?;
|
||||
|
||||
cx.tcx.struct_span_lint_hir(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, "redundant explicit link target", |lint| {
|
||||
lint.span_label(explicit_span, "explicit target is redundant")
|
||||
.span_label(display_span, "because label contains path that resolves to same destination")
|
||||
.span_note(def_span, "referenced explicit link target defined here")
|
||||
.note("when a link's destination is not specified,\nthe label is used to resolve intra-doc links")
|
||||
.span_suggestion_with_style(link_span, "remove explicit link target", format!("[{}]", link_data.display_link), Applicability::MaybeIncorrect, SuggestionStyle::ShowAlways);
|
||||
|
||||
lint
|
||||
});
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn find_resolution(resolutions: &DocLinkResMap, path: &str) -> Option<Res<NodeId>> {
|
||||
[Namespace::TypeNS, Namespace::ValueNS, Namespace::MacroNS]
|
||||
.into_iter()
|
||||
.find_map(|ns| resolutions.get(&(Symbol::intern(path), ns)).copied().flatten())
|
||||
}
|
||||
|
||||
/// Collects all neccessary data of link.
|
||||
fn collect_link_data(offset_iter: &mut OffsetIter<'_, '_>) -> LinkData {
|
||||
let mut resolvable_link = None;
|
||||
let mut resolvable_link_range = None;
|
||||
let mut display_link = String::new();
|
||||
|
||||
while let Some((event, range)) = offset_iter.next() {
|
||||
match event {
|
||||
Event::Text(code) => {
|
||||
let code = code.to_string();
|
||||
display_link.push_str(&code);
|
||||
resolvable_link = Some(code);
|
||||
resolvable_link_range = Some(range);
|
||||
}
|
||||
Event::Code(code) => {
|
||||
let code = code.to_string();
|
||||
display_link.push('`');
|
||||
display_link.push_str(&code);
|
||||
display_link.push('`');
|
||||
resolvable_link = Some(code);
|
||||
resolvable_link_range = Some(range);
|
||||
}
|
||||
Event::End(_) => {
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
LinkData { resolvable_link, resolvable_link_range, display_link }
|
||||
}
|
||||
|
||||
fn offset_explicit_range(md: &str, link_range: Range<usize>, open: u8, close: u8) -> Range<usize> {
|
||||
let mut open_brace = !0;
|
||||
let mut close_brace = !0;
|
||||
for (i, b) in md.as_bytes()[link_range.clone()].iter().copied().enumerate().rev() {
|
||||
let i = i + link_range.start;
|
||||
if b == close {
|
||||
close_brace = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if close_brace < link_range.start || close_brace >= link_range.end {
|
||||
return link_range;
|
||||
}
|
||||
|
||||
let mut nesting = 1;
|
||||
|
||||
for (i, b) in md.as_bytes()[link_range.start..close_brace].iter().copied().enumerate().rev() {
|
||||
let i = i + link_range.start;
|
||||
if b == close {
|
||||
nesting += 1;
|
||||
}
|
||||
if b == open {
|
||||
nesting -= 1;
|
||||
}
|
||||
if nesting == 0 {
|
||||
open_brace = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert!(open_brace != close_brace);
|
||||
|
||||
if open_brace < link_range.start || open_brace >= link_range.end {
|
||||
return link_range;
|
||||
}
|
||||
// do not actually include braces in the span
|
||||
(open_brace + 1)..close_brace
|
||||
}
|
||||
|
||||
fn offset_reference_def_range(
|
||||
md: &str,
|
||||
dest: &CowStr<'_>,
|
||||
link_range: Range<usize>,
|
||||
) -> Range<usize> {
|
||||
// For diagnostics, we want to underline the link's definition but `span` will point at
|
||||
// where the link is used. This is a problem for reference-style links, where the definition
|
||||
// is separate from the usage.
|
||||
|
||||
match dest {
|
||||
// `Borrowed` variant means the string (the link's destination) may come directly from
|
||||
// the markdown text and we can locate the original link destination.
|
||||
// NOTE: LinkReplacer also provides `Borrowed` but possibly from other sources,
|
||||
// so `locate()` can fall back to use `span`.
|
||||
CowStr::Borrowed(s) => {
|
||||
// FIXME: remove this function once pulldown_cmark can provide spans for link definitions.
|
||||
unsafe {
|
||||
let s_start = dest.as_ptr();
|
||||
let s_end = s_start.add(s.len());
|
||||
let md_start = md.as_ptr();
|
||||
let md_end = md_start.add(md.len());
|
||||
if md_start <= s_start && s_end <= md_end {
|
||||
let start = s_start.offset_from(md_start) as usize;
|
||||
let end = s_end.offset_from(md_start) as usize;
|
||||
start..end
|
||||
} else {
|
||||
link_range
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For anything else, we can only use the provided range.
|
||||
CowStr::Boxed(_) | CowStr::Inlined(_) => link_range,
|
||||
}
|
||||
}
|
13
tests/rustdoc-ui/lints/inline-doc-link.rs
Normal file
13
tests/rustdoc-ui/lints/inline-doc-link.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
// Regression test for <https://github.com/rust-lang/rust/pull/113167>
|
||||
|
||||
// check-pass
|
||||
#![deny(rustdoc::redundant_explicit_links)]
|
||||
|
||||
mod m {
|
||||
pub enum ValueEnum {}
|
||||
}
|
||||
mod m2 {
|
||||
/// [`ValueEnum`]
|
||||
pub use crate::m::ValueEnum;
|
||||
}
|
||||
pub use m2::ValueEnum;
|
7
tests/rustdoc-ui/lints/no-redundancy.rs
Normal file
7
tests/rustdoc-ui/lints/no-redundancy.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
// check-pass
|
||||
|
||||
#![deny(rustdoc::redundant_explicit_links)]
|
||||
|
||||
/// [Vec][std::vec::Vec#examples] should not warn, because it's not actually redundant!
|
||||
/// [This is just an `Option`][std::option::Option] has different display content to actual link!
|
||||
pub fn func() {}
|
158
tests/rustdoc-ui/lints/redundant_explicit_links.fixed
Normal file
158
tests/rustdoc-ui/lints/redundant_explicit_links.fixed
Normal file
|
@ -0,0 +1,158 @@
|
|||
// run-rustfix
|
||||
|
||||
#![deny(rustdoc::redundant_explicit_links)]
|
||||
|
||||
pub fn dummy_target() {}
|
||||
|
||||
/// [dummy_target]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`dummy_target`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
///
|
||||
/// [Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`Vec`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`Vec`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::vec::Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::vec::Vec`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::vec::Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::vec::Vec`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
///
|
||||
/// [usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`usize`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`usize`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::primitive::usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::primitive::usize`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::primitive::usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::primitive::usize`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
///
|
||||
/// [dummy_target] TEXT
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`dummy_target`] TEXT
|
||||
//~^ ERROR redundant explicit link target
|
||||
pub fn should_warn_inline() {}
|
||||
|
||||
/// [`Vec<T>`](Vec)
|
||||
/// [`Vec<T>`](std::vec::Vec)
|
||||
pub fn should_not_warn_inline() {}
|
||||
|
||||
/// [dummy_target]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`dummy_target`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
///
|
||||
/// [Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`Vec`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`Vec`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::vec::Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::vec::Vec`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::vec::Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::vec::Vec`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
///
|
||||
/// [usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`usize`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`usize`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::primitive::usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::primitive::usize`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::primitive::usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::primitive::usize`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
///
|
||||
/// [dummy_target] TEXT
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`dummy_target`] TEXT
|
||||
//~^ ERROR redundant explicit link target
|
||||
pub fn should_warn_reference_unknown() {}
|
||||
|
||||
/// [`Vec<T>`][Vec]
|
||||
/// [`Vec<T>`][std::vec::Vec]
|
||||
pub fn should_not_warn_reference_unknown() {}
|
||||
|
||||
/// [dummy_target]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`dummy_target`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
///
|
||||
/// [Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`Vec`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`Vec`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::vec::Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::vec::Vec`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::vec::Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::vec::Vec`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
///
|
||||
/// [usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`usize`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`usize`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::primitive::usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::primitive::usize`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::primitive::usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::primitive::usize`]
|
||||
//~^ ERROR redundant explicit link target
|
||||
///
|
||||
/// [dummy_target] TEXT
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`dummy_target`] TEXT
|
||||
//~^ ERROR redundant explicit link target
|
||||
///
|
||||
/// [dummy_target]: dummy_target
|
||||
/// [Vec]: Vec
|
||||
/// [std::vec::Vec]: Vec
|
||||
/// [usize]: usize
|
||||
/// [std::primitive::usize]: usize
|
||||
pub fn should_warn_reference() {}
|
||||
|
||||
/// [`Vec<T>`]: Vec
|
||||
/// [`Vec<T>`]: std::vec::Vec
|
||||
pub fn should_not_warn_reference() {}
|
158
tests/rustdoc-ui/lints/redundant_explicit_links.rs
Normal file
158
tests/rustdoc-ui/lints/redundant_explicit_links.rs
Normal file
|
@ -0,0 +1,158 @@
|
|||
// run-rustfix
|
||||
|
||||
#![deny(rustdoc::redundant_explicit_links)]
|
||||
|
||||
pub fn dummy_target() {}
|
||||
|
||||
/// [dummy_target](dummy_target)
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`dummy_target`](dummy_target)
|
||||
//~^ ERROR redundant explicit link target
|
||||
///
|
||||
/// [Vec](Vec)
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`Vec`](Vec)
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [Vec](std::vec::Vec)
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`Vec`](std::vec::Vec)
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::vec::Vec](Vec)
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::vec::Vec`](Vec)
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::vec::Vec](std::vec::Vec)
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::vec::Vec`](std::vec::Vec)
|
||||
//~^ ERROR redundant explicit link target
|
||||
///
|
||||
/// [usize](usize)
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`usize`](usize)
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [usize](std::primitive::usize)
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`usize`](std::primitive::usize)
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::primitive::usize](usize)
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::primitive::usize`](usize)
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::primitive::usize](std::primitive::usize)
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::primitive::usize`](std::primitive::usize)
|
||||
//~^ ERROR redundant explicit link target
|
||||
///
|
||||
/// [dummy_target](dummy_target) TEXT
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`dummy_target`](dummy_target) TEXT
|
||||
//~^ ERROR redundant explicit link target
|
||||
pub fn should_warn_inline() {}
|
||||
|
||||
/// [`Vec<T>`](Vec)
|
||||
/// [`Vec<T>`](std::vec::Vec)
|
||||
pub fn should_not_warn_inline() {}
|
||||
|
||||
/// [dummy_target][dummy_target]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`dummy_target`][dummy_target]
|
||||
//~^ ERROR redundant explicit link target
|
||||
///
|
||||
/// [Vec][Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`Vec`][Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [Vec][std::vec::Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`Vec`][std::vec::Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::vec::Vec][Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::vec::Vec`][Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::vec::Vec][std::vec::Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::vec::Vec`][std::vec::Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
///
|
||||
/// [usize][usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`usize`][usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [usize][std::primitive::usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`usize`][std::primitive::usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::primitive::usize][usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::primitive::usize`][usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::primitive::usize][std::primitive::usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::primitive::usize`][std::primitive::usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
///
|
||||
/// [dummy_target][dummy_target] TEXT
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`dummy_target`][dummy_target] TEXT
|
||||
//~^ ERROR redundant explicit link target
|
||||
pub fn should_warn_reference_unknown() {}
|
||||
|
||||
/// [`Vec<T>`][Vec]
|
||||
/// [`Vec<T>`][std::vec::Vec]
|
||||
pub fn should_not_warn_reference_unknown() {}
|
||||
|
||||
/// [dummy_target][dummy_target]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`dummy_target`][dummy_target]
|
||||
//~^ ERROR redundant explicit link target
|
||||
///
|
||||
/// [Vec][Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`Vec`][Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [Vec][std::vec::Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`Vec`][std::vec::Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::vec::Vec][Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::vec::Vec`][Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::vec::Vec][std::vec::Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::vec::Vec`][std::vec::Vec]
|
||||
//~^ ERROR redundant explicit link target
|
||||
///
|
||||
/// [usize][usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`usize`][usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [usize][std::primitive::usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`usize`][std::primitive::usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::primitive::usize][usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::primitive::usize`][usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [std::primitive::usize][std::primitive::usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`std::primitive::usize`][std::primitive::usize]
|
||||
//~^ ERROR redundant explicit link target
|
||||
///
|
||||
/// [dummy_target][dummy_target] TEXT
|
||||
//~^ ERROR redundant explicit link target
|
||||
/// [`dummy_target`][dummy_target] TEXT
|
||||
//~^ ERROR redundant explicit link target
|
||||
///
|
||||
/// [dummy_target]: dummy_target
|
||||
/// [Vec]: Vec
|
||||
/// [std::vec::Vec]: Vec
|
||||
/// [usize]: usize
|
||||
/// [std::primitive::usize]: usize
|
||||
pub fn should_warn_reference() {}
|
||||
|
||||
/// [`Vec<T>`]: Vec
|
||||
/// [`Vec<T>`]: std::vec::Vec
|
||||
pub fn should_not_warn_reference() {}
|
1007
tests/rustdoc-ui/lints/redundant_explicit_links.stderr
Normal file
1007
tests/rustdoc-ui/lints/redundant_explicit_links.stderr
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,7 @@
|
|||
#![deny(rustdoc::unescaped_backticks)]
|
||||
#![allow(rustdoc::broken_intra_doc_links)]
|
||||
#![allow(rustdoc::invalid_html_tags)]
|
||||
#![allow(rustdoc::redundant_explicit_links)]
|
||||
|
||||
///
|
||||
pub fn empty() {}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:186:70
|
||||
--> $DIR/unescaped_backticks.rs:187:70
|
||||
|
|
||||
LL | /// if you want your MIR to be modified by the full MIR pipeline, or `#![custom_mir(dialect =
|
||||
| ^
|
||||
|
@ -19,7 +19,7 @@ LL | /// if you want your MIR to be modified by the full MIR pipeline, or \`#![c
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:231:13
|
||||
--> $DIR/unescaped_backticks.rs:232:13
|
||||
|
|
||||
LL | //! `#![rustc_expected_cgu_reuse(module="spike", cfg="rpass2", kind="post-lto")]
|
||||
| ^
|
||||
|
@ -34,7 +34,7 @@ LL | //! \`#![rustc_expected_cgu_reuse(module="spike", cfg="rpass2", kin
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:236:13
|
||||
--> $DIR/unescaped_backticks.rs:237:13
|
||||
|
|
||||
LL | /// `cfg=...
|
||||
| ^
|
||||
|
@ -49,7 +49,7 @@ LL | /// \`cfg=...
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:240:42
|
||||
--> $DIR/unescaped_backticks.rs:241:42
|
||||
|
|
||||
LL | /// `cfg=... and not `#[cfg_attr]`
|
||||
| ^
|
||||
|
@ -64,7 +64,7 @@ LL | /// `cfg=... and not `#[cfg_attr]\`
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:192:91
|
||||
--> $DIR/unescaped_backticks.rs:193:91
|
||||
|
|
||||
LL | /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg to
|
||||
| ^
|
||||
|
@ -79,7 +79,7 @@ LL | /// Constructs a `TyKind::Error` type and registers a `delay_span_bug`
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:201:34
|
||||
--> $DIR/unescaped_backticks.rs:202:34
|
||||
|
|
||||
LL | /// in `nt_to_tokenstream`
|
||||
| ^
|
||||
|
@ -94,7 +94,7 @@ LL | /// in `nt_to_tokenstream\`
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:207:62
|
||||
--> $DIR/unescaped_backticks.rs:208:62
|
||||
|
|
||||
LL | /// that `Option<Symbol>` only takes up 4 bytes, because `newtype_index! reserves
|
||||
| ^
|
||||
|
@ -109,7 +109,7 @@ LL | /// that `Option<Symbol>` only takes up 4 bytes, because \`newtype_inde
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:215:52
|
||||
--> $DIR/unescaped_backticks.rs:216:52
|
||||
|
|
||||
LL | /// also avoids the need to import `OpenOptions`.
|
||||
| ^
|
||||
|
@ -124,7 +124,7 @@ LL | /// also avoids the need to import `OpenOptions\`.
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:220:46
|
||||
--> $DIR/unescaped_backticks.rs:221:46
|
||||
|
|
||||
LL | /// `HybridBitSet`. Has no effect if `row` does not exist.
|
||||
| ^
|
||||
|
@ -139,7 +139,7 @@ LL | /// `HybridBitSet`. Has no effect if `row\` does not exist.
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:246:12
|
||||
--> $DIR/unescaped_backticks.rs:247:12
|
||||
|
|
||||
LL | /// RWU`s can get very large, so it uses a more compact representation.
|
||||
| ^
|
||||
|
@ -154,7 +154,7 @@ LL | /// RWU\`s can get very large, so it uses a more compact representation
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:253:15
|
||||
--> $DIR/unescaped_backticks.rs:254:15
|
||||
|
|
||||
LL | /// in `U2`.
|
||||
| ^
|
||||
|
@ -169,7 +169,7 @@ LL | /// in `U2\`.
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:270:42
|
||||
--> $DIR/unescaped_backticks.rs:271:42
|
||||
|
|
||||
LL | /// because it contains `[type error]`. Yuck! (See issue #29857 for
|
||||
| ^
|
||||
|
@ -184,7 +184,7 @@ LL | /// because it contains `[type error]\`. Yuck! (See issue #29857 for
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:280:53
|
||||
--> $DIR/unescaped_backticks.rs:281:53
|
||||
|
|
||||
LL | /// well as the second instance of `A: AutoTrait`) to suppress
|
||||
| ^
|
||||
|
@ -199,7 +199,7 @@ LL | /// well as the second instance of `A: AutoTrait\`) to suppress
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:290:40
|
||||
--> $DIR/unescaped_backticks.rs:291:40
|
||||
|
|
||||
LL | /// `'a` with `'b` and not `'static`. But it will have to do for
|
||||
| ^
|
||||
|
@ -211,7 +211,7 @@ LL | /// `'a` with `'b` and not `'static\`. But it will have to do for
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:299:54
|
||||
--> $DIR/unescaped_backticks.rs:300:54
|
||||
|
|
||||
LL | /// `None`. Otherwise, it will return `Some(Dispatch)`.
|
||||
| ^
|
||||
|
@ -226,7 +226,7 @@ LL | /// `None`. Otherwise, it will return `Some(Dispatch)\`.
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:303:13
|
||||
--> $DIR/unescaped_backticks.rs:304:13
|
||||
|
|
||||
LL | /// or `None` if it isn't.
|
||||
| ^
|
||||
|
@ -238,7 +238,7 @@ LL | /// or `None\` if it isn't.
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:307:14
|
||||
--> $DIR/unescaped_backticks.rs:308:14
|
||||
|
|
||||
LL | /// `on_event` should be called.
|
||||
| ^
|
||||
|
@ -253,7 +253,7 @@ LL | /// `on_event\` should be called.
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:312:29
|
||||
--> $DIR/unescaped_backticks.rs:313:29
|
||||
|
|
||||
LL | /// [`rebuild_interest_cache`][rebuild] is called after the value of the max
|
||||
| ^
|
||||
|
@ -268,7 +268,7 @@ LL | /// [`rebuild_interest_cache\`][rebuild] is called after the value of the m
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:322:5
|
||||
--> $DIR/unescaped_backticks.rs:323:5
|
||||
|
|
||||
LL | / /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`],
|
||||
LL | |
|
||||
|
@ -287,7 +287,7 @@ LL | | /// level changes.
|
|||
to this: `None`. Otherwise, it will return `Some(Dispatch)\`.
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:322:5
|
||||
--> $DIR/unescaped_backticks.rs:323:5
|
||||
|
|
||||
LL | / /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`],
|
||||
LL | |
|
||||
|
@ -304,7 +304,7 @@ LL | | /// level changes.
|
|||
to this: or `None\` if it isn't.
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:322:5
|
||||
--> $DIR/unescaped_backticks.rs:323:5
|
||||
|
|
||||
LL | / /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`],
|
||||
LL | |
|
||||
|
@ -323,7 +323,7 @@ LL | | /// level changes.
|
|||
to this: `on_event\` should be called.
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:322:5
|
||||
--> $DIR/unescaped_backticks.rs:323:5
|
||||
|
|
||||
LL | / /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`],
|
||||
LL | |
|
||||
|
@ -342,7 +342,7 @@ LL | | /// level changes.
|
|||
to this: [`rebuild_interest_cache\`][rebuild] is called after the value of the max
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:348:56
|
||||
--> $DIR/unescaped_backticks.rs:349:56
|
||||
|
|
||||
LL | /// instead and use [`CloneCounterObserver::counter`] to increment.
|
||||
| ^
|
||||
|
@ -354,7 +354,7 @@ LL | /// instead and use [`CloneCounterObserver::counter\`] to increment.
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:11:5
|
||||
--> $DIR/unescaped_backticks.rs:12:5
|
||||
|
|
||||
LL | /// `
|
||||
| ^
|
||||
|
@ -366,7 +366,7 @@ LL | /// \`
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:18:7
|
||||
--> $DIR/unescaped_backticks.rs:19:7
|
||||
|
|
||||
LL | /// \`
|
||||
| ^
|
||||
|
@ -381,7 +381,7 @@ LL | /// \\`
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:25:6
|
||||
--> $DIR/unescaped_backticks.rs:26:6
|
||||
|
|
||||
LL | /// [`link1]
|
||||
| ^
|
||||
|
@ -396,7 +396,7 @@ LL | /// [\`link1]
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:29:11
|
||||
--> $DIR/unescaped_backticks.rs:30:11
|
||||
|
|
||||
LL | /// [link2`]
|
||||
| ^
|
||||
|
@ -411,7 +411,7 @@ LL | /// [link2\`]
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:33:6
|
||||
--> $DIR/unescaped_backticks.rs:34:6
|
||||
|
|
||||
LL | /// [`link_long](link_long)
|
||||
| ^
|
||||
|
@ -426,7 +426,7 @@ LL | /// [\`link_long](link_long)
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:37:6
|
||||
--> $DIR/unescaped_backticks.rs:38:6
|
||||
|
|
||||
LL | /// [`broken-link]
|
||||
| ^
|
||||
|
@ -441,7 +441,7 @@ LL | /// [\`broken-link]
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:44:8
|
||||
--> $DIR/unescaped_backticks.rs:45:8
|
||||
|
|
||||
LL | /// <x:`>
|
||||
| ^
|
||||
|
@ -456,7 +456,7 @@ LL | /// <x:\`>
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:54:6
|
||||
--> $DIR/unescaped_backticks.rs:55:6
|
||||
|
|
||||
LL | /// 🦀`🦀
|
||||
| ^
|
||||
|
@ -475,7 +475,7 @@ LL | /// 🦀\`🦀
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:58:5
|
||||
--> $DIR/unescaped_backticks.rs:59:5
|
||||
|
|
||||
LL | /// `foo(
|
||||
| ^
|
||||
|
@ -490,7 +490,7 @@ LL | /// \`foo(
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:64:14
|
||||
--> $DIR/unescaped_backticks.rs:65:14
|
||||
|
|
||||
LL | /// `foo `bar`
|
||||
| ^
|
||||
|
@ -505,7 +505,7 @@ LL | /// `foo `bar\`
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:70:5
|
||||
--> $DIR/unescaped_backticks.rs:71:5
|
||||
|
|
||||
LL | /// `foo(
|
||||
| ^
|
||||
|
@ -520,7 +520,7 @@ LL | /// \`foo(
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:75:83
|
||||
--> $DIR/unescaped_backticks.rs:76:83
|
||||
|
|
||||
LL | /// Addition is commutative, which means that add(a, b)` is the same as `add(b, a)`.
|
||||
| ^
|
||||
|
@ -535,7 +535,7 @@ LL | /// Addition is commutative, which means that add(a, b)` is the same as `ad
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:79:51
|
||||
--> $DIR/unescaped_backticks.rs:80:51
|
||||
|
|
||||
LL | /// or even to add a number `n` to 42 (`add(42, b)`)!
|
||||
| ^
|
||||
|
@ -550,7 +550,7 @@ LL | /// or even to add a number `n` to 42 (`add(42, b)\`)!
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:83:83
|
||||
--> $DIR/unescaped_backticks.rs:84:83
|
||||
|
|
||||
LL | /// Addition is commutative, which means that `add(a, b) is the same as `add(b, a)`.
|
||||
| ^
|
||||
|
@ -565,7 +565,7 @@ LL | /// Addition is commutative, which means that `add(a, b) is the same as `ad
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:87:51
|
||||
--> $DIR/unescaped_backticks.rs:88:51
|
||||
|
|
||||
LL | /// or even to add a number `n` to 42 (`add(42, n)`)!
|
||||
| ^
|
||||
|
@ -580,7 +580,7 @@ LL | /// or even to add a number `n` to 42 (`add(42, n)\`)!
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:91:83
|
||||
--> $DIR/unescaped_backticks.rs:92:83
|
||||
|
|
||||
LL | /// Addition is commutative, which means that `add(a, b)` is the same as add(b, a)`.
|
||||
| ^
|
||||
|
@ -595,7 +595,7 @@ LL | /// Addition is commutative, which means that `add(a, b)` is the same as ad
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:95:50
|
||||
--> $DIR/unescaped_backticks.rs:96:50
|
||||
|
|
||||
LL | /// or even to add a number `n` to 42 (add(42, n)`)!
|
||||
| ^
|
||||
|
@ -610,7 +610,7 @@ LL | /// or even to add a number `n` to 42 (add(42, n)\`)!
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:99:74
|
||||
--> $DIR/unescaped_backticks.rs:100:74
|
||||
|
|
||||
LL | /// Addition is commutative, which means that `add(a, b)` is the same as `add(b, a).
|
||||
| ^
|
||||
|
@ -625,7 +625,7 @@ LL | /// Addition is commutative, which means that `add(a, b)` is the same as \`
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:103:51
|
||||
--> $DIR/unescaped_backticks.rs:104:51
|
||||
|
|
||||
LL | /// or even to add a number `n` to 42 (`add(42, n)`)!
|
||||
| ^
|
||||
|
@ -640,7 +640,7 @@ LL | /// or even to add a number `n` to 42 (`add(42, n)\`)!
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:107:1
|
||||
--> $DIR/unescaped_backticks.rs:108:1
|
||||
|
|
||||
LL | #[doc = "`"]
|
||||
| ^^^^^^^^^^^^
|
||||
|
@ -651,7 +651,7 @@ LL | #[doc = "`"]
|
|||
to this: \`
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:114:1
|
||||
--> $DIR/unescaped_backticks.rs:115:1
|
||||
|
|
||||
LL | #[doc = concat!("\\", "`")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -664,7 +664,7 @@ LL | #[doc = concat!("\\", "`")]
|
|||
to this: \\`
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:118:1
|
||||
--> $DIR/unescaped_backticks.rs:119:1
|
||||
|
|
||||
LL | #[doc = "Addition is commutative, which means that add(a, b)` is the same as `add(b, a)`."]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -677,7 +677,7 @@ LL | #[doc = "Addition is commutative, which means that add(a, b)` is the same a
|
|||
to this: Addition is commutative, which means that add(a, b)` is the same as `add(b, a)\`.
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:122:1
|
||||
--> $DIR/unescaped_backticks.rs:123:1
|
||||
|
|
||||
LL | #[doc = "Addition is commutative, which means that `add(a, b) is the same as `add(b, a)`."]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -690,7 +690,7 @@ LL | #[doc = "Addition is commutative, which means that `add(a, b) is the same a
|
|||
to this: Addition is commutative, which means that `add(a, b) is the same as `add(b, a)\`.
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:126:1
|
||||
--> $DIR/unescaped_backticks.rs:127:1
|
||||
|
|
||||
LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same as add(b, a)`."]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -703,7 +703,7 @@ LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same
|
|||
to this: Addition is commutative, which means that `add(a, b)` is the same as add(b, a)\`.
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:130:1
|
||||
--> $DIR/unescaped_backticks.rs:131:1
|
||||
|
|
||||
LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same as `add(b, a)."]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -716,7 +716,7 @@ LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same
|
|||
to this: Addition is commutative, which means that `add(a, b)` is the same as \`add(b, a).
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:135:5
|
||||
--> $DIR/unescaped_backticks.rs:136:5
|
||||
|
|
||||
LL | /// `foo
|
||||
| ^
|
||||
|
@ -731,7 +731,7 @@ LL | /// \`foo
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:139:7
|
||||
--> $DIR/unescaped_backticks.rs:140:7
|
||||
|
|
||||
LL | /// # `(heading
|
||||
| ^
|
||||
|
@ -746,7 +746,7 @@ LL | /// # \`(heading
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:141:17
|
||||
--> $DIR/unescaped_backticks.rs:142:17
|
||||
|
|
||||
LL | /// ## heading2)`
|
||||
| ^
|
||||
|
@ -761,7 +761,7 @@ LL | /// ## heading2)\`
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:144:11
|
||||
--> $DIR/unescaped_backticks.rs:145:11
|
||||
|
|
||||
LL | /// multi `(
|
||||
| ^
|
||||
|
@ -776,7 +776,7 @@ LL | /// multi \`(
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:150:10
|
||||
--> $DIR/unescaped_backticks.rs:151:10
|
||||
|
|
||||
LL | /// para)`(graph
|
||||
| ^
|
||||
|
@ -795,7 +795,7 @@ LL | /// para)\`(graph
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:153:10
|
||||
--> $DIR/unescaped_backticks.rs:154:10
|
||||
|
|
||||
LL | /// para)`(graph2
|
||||
| ^
|
||||
|
@ -814,7 +814,7 @@ LL | /// para)\`(graph2
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:156:12
|
||||
--> $DIR/unescaped_backticks.rs:157:12
|
||||
|
|
||||
LL | /// 1. foo)`
|
||||
| ^
|
||||
|
@ -829,7 +829,7 @@ LL | /// 1. foo)\`
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:158:8
|
||||
--> $DIR/unescaped_backticks.rs:159:8
|
||||
|
|
||||
LL | /// 2. `(bar
|
||||
| ^
|
||||
|
@ -844,7 +844,7 @@ LL | /// 2. \`(bar
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:160:11
|
||||
--> $DIR/unescaped_backticks.rs:161:11
|
||||
|
|
||||
LL | /// * baz)`
|
||||
| ^
|
||||
|
@ -859,7 +859,7 @@ LL | /// * baz)\`
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:162:7
|
||||
--> $DIR/unescaped_backticks.rs:163:7
|
||||
|
|
||||
LL | /// * `(quux
|
||||
| ^
|
||||
|
@ -874,7 +874,7 @@ LL | /// * \`(quux
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:165:5
|
||||
--> $DIR/unescaped_backticks.rs:166:5
|
||||
|
|
||||
LL | /// `#![this_is_actually_an_image(and(not), an = "attribute")]
|
||||
| ^
|
||||
|
@ -889,7 +889,7 @@ LL | /// \`#![this_is_actually_an_image(and(not), an = "attribute")]
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:168:62
|
||||
--> $DIR/unescaped_backticks.rs:169:62
|
||||
|
|
||||
LL | /// #![this_is_actually_an_image(and(not), an = "attribute")]`
|
||||
| ^
|
||||
|
@ -904,7 +904,7 @@ LL | /// #![this_is_actually_an_image(and(not), an = "attribute")]\`
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:173:7
|
||||
--> $DIR/unescaped_backticks.rs:174:7
|
||||
|
|
||||
LL | /// | `table( | )head` |
|
||||
| ^
|
||||
|
@ -919,7 +919,7 @@ LL | /// | \`table( | )head` |
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:173:22
|
||||
--> $DIR/unescaped_backticks.rs:174:22
|
||||
|
|
||||
LL | /// | `table( | )head` |
|
||||
| ^
|
||||
|
@ -934,7 +934,7 @@ LL | /// | `table( | )head\` |
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:177:12
|
||||
--> $DIR/unescaped_backticks.rs:178:12
|
||||
|
|
||||
LL | /// | table`( | )`body |
|
||||
| ^
|
||||
|
@ -949,7 +949,7 @@ LL | /// | table\`( | )`body |
|
|||
| +
|
||||
|
||||
error: unescaped backtick
|
||||
--> $DIR/unescaped_backticks.rs:177:18
|
||||
--> $DIR/unescaped_backticks.rs:178:18
|
||||
|
|
||||
LL | /// | table`( | )`body |
|
||||
| ^
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#![crate_name = "foo"]
|
||||
#![allow(rustdoc::redundant_explicit_links)]
|
||||
//! # Description test crate
|
||||
//!
|
||||
//! This is the contents of the test crate docstring.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(rustdoc::redundant_explicit_links)]
|
||||
|
||||
// @has basic/index.html
|
||||
// @has - '//a/@href' 'struct.ThisType.html'
|
||||
// @has - '//a/@title' 'struct basic::ThisType'
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// ignore-tidy-linelength
|
||||
|
||||
#![crate_name = "foo"]
|
||||
#![allow(rustdoc::redundant_explicit_links)]
|
||||
|
||||
//! Here's a link to [`Vec<T>`] and one to [`Box<Vec<Option<T>>>`].
|
||||
//! Here's a link to [`Iterator<Box<T>>::Item`].
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#![deny(rustdoc::broken_intra_doc_links)]
|
||||
#![allow(rustdoc::redundant_explicit_links)]
|
||||
|
||||
pub struct S;
|
||||
pub mod char {}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue