Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ impl PathSource<'_, '_, '_> {
/// At this point for most items we can answer whether that item is exported or not,
/// but some items like impls require type information to determine exported-ness, so we make a
/// conservative estimate for them (e.g. based on nominal visibility).
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Debug)]
enum MaybeExported<'a> {
Ok(NodeId),
Impl(Option<DefId>),
Expand Down Expand Up @@ -5503,9 +5503,10 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
// FIXME: This caching may be incorrect in case of multiple `macro_rules`
// items with the same name in the same module.
// Also hygiene is not considered.
let mod_id = self.parent_scope.module.nearest_parent_mod().expect_local();
let mut doc_link_resolutions = std::mem::take(&mut self.r.doc_link_resolutions);
let res = *doc_link_resolutions
.entry(self.parent_scope.module.nearest_parent_mod().expect_local())
.entry(mod_id)
.or_default()
.entry((Symbol::intern(path_str), ns))
.or_insert_with_key(|(path, ns)| {
Expand All @@ -5518,6 +5519,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
// because it will only store proc macros for it.
return None;
}
debug!("cached resolution of {mod_id:?} {path_str:?} as {res:?} in ns {ns:?}");
res
});
self.r.doc_link_resolutions = doc_link_resolutions;
Expand All @@ -5535,6 +5537,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
}

fn resolve_doc_links(&mut self, attrs: &[Attribute], maybe_exported: MaybeExported<'_>) {
debug!(?attrs, ?maybe_exported, ?self.r.tcx.sess.opts.resolve_doc_links);
match self.r.tcx.sess.opts.resolve_doc_links {
ResolveDocLinks::None => return,
ResolveDocLinks::ExportedMetadata
Expand All @@ -5560,6 +5563,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {

let mut need_traits_in_scope = false;
for path_str in rustdoc::attrs_to_preprocessed_links(attrs) {
debug!("resolving link {path_str:?}");
// Resolve all namespaces due to no disambiguator or for diagnostics.
let mut any_resolved = false;
let mut need_assoc = false;
Expand All @@ -5574,6 +5578,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
}

// Resolve all prefixes for type-relative resolution or for diagnostics.
debug!(?any_resolved, ?need_assoc);
if need_assoc || !any_resolved {
let mut path = &path_str[..];
while let Some(idx) = path.rfind("::") {
Expand Down
9 changes: 6 additions & 3 deletions compiler/rustc_resolve/src/rustdoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,12 @@ pub fn add_doc_fragment(out: &mut String, frag: &DocFragment) {
pub fn attrs_to_doc_fragments<'a, A: AttributeExt + Clone + 'a>(
attrs: impl Iterator<Item = (&'a A, Option<DefId>)>,
doc_only: bool,
) -> (Vec<DocFragment>, ThinVec<A>) {
) -> (Vec<DocFragment>, ThinVec<A>, ThinVec<Option<DefId>>) {
let (min_size, max_size) = attrs.size_hint();
let size_hint = max_size.unwrap_or(min_size);
let mut doc_fragments = Vec::with_capacity(size_hint);
let mut other_attrs = ThinVec::<A>::with_capacity(if doc_only { 0 } else { size_hint });
let mut other_attrs_src = ThinVec::with_capacity(if doc_only { 0 } else { size_hint });
for (attr, item_id) in attrs {
if let Some((doc_str, fragment_kind)) = attr.doc_str_and_fragment_kind() {
let doc = beautify_doc_string(doc_str, fragment_kind.comment_kind());
Expand All @@ -220,15 +221,17 @@ pub fn attrs_to_doc_fragments<'a, A: AttributeExt + Clone + 'a>(
doc_fragments.push(fragment);
} else if !doc_only {
other_attrs.push(attr.clone());
other_attrs_src.push(item_id);
}
}

doc_fragments.shrink_to_fit();
other_attrs.shrink_to_fit();
other_attrs_src.shrink_to_fit();

unindent_doc_fragments(&mut doc_fragments);

(doc_fragments, other_attrs)
(doc_fragments, other_attrs, other_attrs_src)
}

/// Return the doc-comments on this item, grouped by the module they came from.
Expand Down Expand Up @@ -410,7 +413,7 @@ pub fn may_be_doc_link(link_type: LinkType) -> bool {
/// Simplified version of `preprocessed_markdown_links` from rustdoc.
/// Must return at least the same links as it, but may add some more links on top of that.
pub(crate) fn attrs_to_preprocessed_links(attrs: &[ast::Attribute]) -> Vec<Box<str>> {
let (doc_fragments, other_attrs) =
let (doc_fragments, other_attrs, _) =
attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), false);
let doc = prepare_to_doc_link_resolution(&doc_fragments).into_values().next();
let mut links = doc.as_deref().map(parse_links).unwrap_or_default();
Expand Down
15 changes: 11 additions & 4 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,11 @@ pub struct RenderedLink {
pub(crate) struct Attributes {
pub(crate) doc_strings: Vec<DocFragment>,
pub(crate) other_attrs: ThinVec<hir::Attribute>,
/// The `DefId` the attribute is from, either the actual item or a re-exporting use item.
///
/// We need this to properly resolve intra-doc links in deprecation notes on a reexport.
// FIXME: currently deprecation of a reexport does not show in the docs
pub(crate) other_attrs_src: ThinVec<Option<DefId>>,
}

impl Attributes {
Expand Down Expand Up @@ -1091,8 +1096,8 @@ impl Attributes {
attrs: impl Iterator<Item = (&'a hir::Attribute, Option<DefId>)>,
doc_only: bool,
) -> Attributes {
let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only);
Attributes { doc_strings, other_attrs }
let (doc_strings, other_attrs, other_attrs_src) = attrs_to_doc_fragments(attrs, doc_only);
Attributes { doc_strings, other_attrs, other_attrs_src }
}

/// Combine all doc strings into a single value handling indentation and newlines as needed.
Expand Down Expand Up @@ -1128,9 +1133,11 @@ impl Attributes {
}

pub(crate) fn merge_with(&mut self, other: Self) {
let Self { doc_strings, other_attrs } = other;
let Self { doc_strings, other_attrs, other_attrs_src } = other;
self.doc_strings.extend(doc_strings);
self.other_attrs.extend(other_attrs);
self.other_attrs_src.extend(other_attrs_src);
assert_eq!(self.other_attrs.len(), self.other_attrs_src.len());
}
}

Expand Down Expand Up @@ -2518,7 +2525,7 @@ mod size_asserts {
static_assert_size!(GenericParamDef, 40);
static_assert_size!(Generics, 16);
static_assert_size!(Item, 8);
static_assert_size!(ItemInner, 144);
static_assert_size!(ItemInner, 152);
static_assert_size!(ItemKind, 48);
static_assert_size!(PathSegment, 32);
static_assert_size!(Type, 32);
Expand Down
6 changes: 5 additions & 1 deletion src/librustdoc/clean/types/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ fn run_test(input: &str, expected: &str) {
create_default_session_globals_then(|| {
let mut s = create_doc_fragment(input);
unindent_doc_fragments(&mut s);
let attrs = Attributes { doc_strings: s, other_attrs: Default::default() };
let attrs = Attributes {
doc_strings: s,
other_attrs: Default::default(),
other_attrs_src: Default::default(),
};
assert_eq!(attrs.doc_value(), expected);
});
}
Expand Down
29 changes: 6 additions & 23 deletions src/librustdoc/passes/collect_intra_doc_links.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::Namespace::*;
use rustc_hir::def::{DefKind, MacroKinds, Namespace, PerNS};
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE};
use rustc_hir::{Attribute, Mutability, Safety, find_attr};
use rustc_hir::{Attribute, Mutability, Safety};
use rustc_lint::Lint;
use rustc_middle::ty;
use rustc_middle::ty::{Ty, TyCtxt};
Expand All @@ -33,7 +33,7 @@ use smallvec::{SmallVec, smallvec};
use tracing::{debug, info, instrument, trace};

use crate::clean::utils::find_nearest_parent_module;
use crate::clean::{self, Crate, Item, ItemId, ItemLink, PrimitiveType, reexport_chain};
use crate::clean::{self, Crate, Item, ItemId, ItemLink, PrimitiveType};
use crate::core::DocContext;
use crate::html::markdown::{MarkdownLink, MarkdownLinkRange, markdown_links};
use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS};
Expand Down Expand Up @@ -1129,10 +1129,9 @@ impl LinkCollector<'_, '_> {
}

// Also resolve links in the note text of `#[deprecated]`.
for attr in &item.attrs.other_attrs {
let Attribute::Parsed(AttributeKind::Deprecated { span: depr_span, deprecation }) =
attr
else {
for (attr, item_id) in item.attrs.other_attrs.iter().zip(item.attrs.other_attrs_src.iter())
{
let Attribute::Parsed(AttributeKind::Deprecated { span: _, deprecation }) = attr else {
continue;
};
let Some(note_sym) = deprecation.note else { continue };
Expand All @@ -1146,23 +1145,7 @@ impl LinkCollector<'_, '_> {
// When resolving an intra-doc link inside a deprecation note that is on an inlined
// `use` statement, we need to use the `def_id` of the `use` statement, not the
// inlined item.
// <https://github.com/rust-lang/rust/pull/151120>
let item_id = if let Some(inline_stmt_id) = item.inline_stmt_id {
let target_def_id = item.item_id.expect_def_id();
reexport_chain(tcx, inline_stmt_id, target_def_id)
.iter()
.flat_map(|reexport| reexport.id())
.find(|&reexport_def_id| {
find_attr!(
tcx,
reexport_def_id,
Deprecated { span, .. } if span == depr_span
)
})
.unwrap_or(target_def_id)
} else {
item.item_id.expect_def_id()
};
let item_id = item_id.unwrap_or(item.item_id.expect_def_id());
try_insert_links(item_id, note)
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/tools/clippy/clippy_lints/src/doc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -876,7 +876,7 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
return None;
}

let (fragments, _) = attrs_to_doc_fragments(
let (fragments, _, _) = attrs_to_doc_fragments(
attrs.iter().filter_map(|attr| {
if attr.doc_str_and_fragment_kind().is_none() || attr.span().in_external_macro(cx.sess().source_map()) {
None
Expand Down
12 changes: 12 additions & 0 deletions tests/rustdoc-ui/ice-intra-doc-link-in-depr-note-157210.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//@ check-pass

pub mod inner {
// [123](a::b::c)
//#[deprecated = "[broken link](TypeAlias::x)"]
#[doc(no_inline)]
#[deprecated = "bar"]
pub use std::vec::Vec;
//#[deprecated = "[working link](std::range)"]
#[deprecated = "foo"]
pub use std::ops::Range;
}
Loading