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
4 changes: 2 additions & 2 deletions compiler/rustc_resolve/src/rustdoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,10 @@ 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>) {
) -> (ThinVec<DocFragment>, ThinVec<A>) {
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 doc_fragments = ThinVec::with_capacity(size_hint);
let mut other_attrs = ThinVec::<A>::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() {
Expand Down
54 changes: 34 additions & 20 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::fmt::Write;
use std::hash::Hash;
use std::path::PathBuf;
use std::sync::{Arc, OnceLock as OnceCell};
use std::sync::{Arc, OnceLock};
use std::{fmt, iter};

use arrayvec::ArrayVec;
Expand Down Expand Up @@ -483,22 +483,22 @@ impl Item {
.iter()
.filter_map(|attr| attr.deprecation_note().map(|note| note.span));

span_of_fragments(&self.attrs.doc_strings)
span_of_fragments(&self.attrs.doc_strings())
.into_iter()
.chain(deprecation_notes)
.reduce(|a, b| a.to(b))
.unwrap_or_else(|| self.span(tcx).map_or(DUMMY_SP, |span| span.inner()))
}

/// Combine all doc strings into a single value handling indentation and newlines as needed.
pub(crate) fn doc_value(&self) -> String {
pub(crate) fn doc_value(&self) -> &str {
self.attrs.doc_value()
}

/// Combine all doc strings into a single value handling indentation and newlines as needed.
/// Returns `None` is there's no documentation at all, and `Some("")` if there is some
/// documentation but it is empty (e.g. `#[doc = ""]`).
pub(crate) fn opt_doc_value(&self) -> Option<String> {
pub(crate) fn opt_doc_value(&self) -> Option<&str> {
self.attrs.opt_doc_value()
}

Expand Down Expand Up @@ -550,7 +550,7 @@ impl Item {
pub(crate) fn item_or_reexport_id(&self) -> ItemId {
// added documentation on a reexport is always prepended.
self.attrs
.doc_strings
.doc_strings()
.first()
.map(|x| x.item_id)
.flatten()
Expand Down Expand Up @@ -1004,11 +1004,21 @@ pub struct RenderedLink {
/// as well as doc comments.
#[derive(Clone, Debug, Default)]
pub(crate) struct Attributes {
pub(crate) doc_strings: Vec<DocFragment>,
/// IMPORTANT! This should not be mutated since then `doc_value_cache` will be invalid.
doc_strings: ThinVec<DocFragment>,
pub(crate) other_attrs: ThinVec<hir::Attribute>,
doc_value_cache: Box<OnceLock<Option<Box<str>>>>,
}

impl Attributes {
fn new(doc_strings: ThinVec<DocFragment>, other_attrs: ThinVec<hir::Attribute>) -> Self {
Self { doc_strings, other_attrs, doc_value_cache: Box::new(OnceLock::new()) }
}

pub(crate) fn doc_strings(&self) -> &[DocFragment] {
&self.doc_strings
}

pub(crate) fn has_doc_flag<F: Fn(&DocAttribute) -> bool>(&self, callback: F) -> bool {
find_attr!(&self.other_attrs, Doc(d) if callback(d))
}
Expand Down Expand Up @@ -1036,26 +1046,30 @@ impl Attributes {
doc_only: bool,
) -> Attributes {
let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only);
Attributes { doc_strings, other_attrs }
Attributes::new(doc_strings, other_attrs)
}

/// Combine all doc strings into a single value handling indentation and newlines as needed.
pub(crate) fn doc_value(&self) -> String {
pub(crate) fn doc_value(&self) -> &str {
self.opt_doc_value().unwrap_or_default()
}

/// Combine all doc strings into a single value handling indentation and newlines as needed.
/// Returns `None` is there's no documentation at all, and `Some("")` if there is some
/// documentation but it is empty (e.g. `#[doc = ""]`).
pub(crate) fn opt_doc_value(&self) -> Option<String> {
(!self.doc_strings.is_empty()).then(|| {
let mut res = String::new();
for frag in &self.doc_strings {
add_doc_fragment(&mut res, frag);
}
res.pop();
res
})
pub(crate) fn opt_doc_value(&self) -> Option<&str> {
self.doc_value_cache
.get_or_init(|| {
(!self.doc_strings.is_empty()).then(|| {
let mut res = String::new();
for frag in &self.doc_strings {
add_doc_fragment(&mut res, frag);
}
res.pop();
res.into_boxed_str()
})
})
.as_deref()
}

pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
Expand Down Expand Up @@ -1673,7 +1687,7 @@ impl PrimitiveType {
pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
use PrimitiveType::*;
use ty::{FloatTy, IntTy, UintTy};
static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
static CELL: OnceLock<SimplifiedTypes> = OnceLock::new();

let single = |x| iter::once(x).collect();
CELL.get_or_init(move || {
Expand Down Expand Up @@ -1779,7 +1793,7 @@ impl PrimitiveType {
/// `rustc_doc_primitive`, then it's entirely random whether `std` or the other crate is picked.
/// (no_std crates are usually fine unless multiple dependencies define a primitive.)
pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> {
static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new();
static PRIMITIVE_LOCATIONS: OnceLock<FxIndexMap<PrimitiveType, DefId>> = OnceLock::new();
PRIMITIVE_LOCATIONS.get_or_init(|| {
let mut primitive_locations = FxIndexMap::default();
// NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate.
Expand Down Expand Up @@ -2418,7 +2432,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, 136);
static_assert_size!(ItemKind, 48);
static_assert_size!(PathSegment, 32);
static_assert_size!(Type, 32);
Expand Down
8 changes: 4 additions & 4 deletions src/librustdoc/clean/types/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@ use rustc_span::create_default_session_globals_then;

use super::*;

fn create_doc_fragment(s: &str) -> Vec<DocFragment> {
vec![DocFragment {
fn create_doc_fragment(s: &str) -> ThinVec<DocFragment> {
ThinVec::from([DocFragment {
span: DUMMY_SP,
item_id: None,
doc: Symbol::intern(s),
kind: DocFragmentKind::Sugared(CommentKind::Line),
indent: 0,
from_expansion: false,
}]
}])
}

#[track_caller]
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::new(s, Default::default());
assert_eq!(attrs.doc_value(), expected);
});
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/doctest/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ impl HirCollector<'_> {
// anything else, this will combine them for us.
let attrs = Attributes::from_hir(ast_attrs);
if let Some(doc) = attrs.opt_doc_value() {
let span = span_of_fragments(&attrs.doc_strings).unwrap_or(sp);
let span = span_of_fragments(&attrs.doc_strings()).unwrap_or(sp);
self.collector.position = if span.edition().at_least_rust_2024() {
span
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/json/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ impl JsonRenderer<'_> {
(String::from(&**link), self.id_from_item_default(id.into()))
})
.collect();
let docs = item.opt_doc_value();
let docs = item.opt_doc_value().map(|s| s.to_owned());
let attrs = item
.attrs
.other_attrs
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/passes/calculate_doc_coverage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ impl DocVisitor<'_> for CoverageCalculator<'_, '_> {
// doesn't make sense, as all methods on a type are in one single impl block
clean::ImplItem(_) => {}
_ => {
let has_docs = !i.attrs.doc_strings.is_empty();
let has_docs = !i.attrs.doc_strings().is_empty();
let mut tests = Tests { found_tests: 0 };

find_testable_code(&i.doc_value(), &mut tests, ErrorCodes::No, None);
Expand Down
8 changes: 4 additions & 4 deletions src/librustdoc/passes/collect_intra_doc_links.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1095,7 +1095,7 @@ impl LinkCollector<'_, '_> {
// In the presence of re-exports, this is not the same as the module of the item.
// Rather than merging all documentation into one, resolve it one attribute at a time
// so we know which module it came from.
for (item_id, doc) in prepare_to_doc_link_resolution(&item.attrs.doc_strings) {
for (item_id, doc) in prepare_to_doc_link_resolution(&item.attrs.doc_strings()) {
if !may_have_doc_links(&doc) {
continue;
}
Expand Down Expand Up @@ -1464,7 +1464,7 @@ impl LinkCollector<'_, '_> {
self.cx.tcx,
dox,
ori_link.inner_range(),
&item.attrs.doc_strings,
&item.attrs.doc_strings(),
) {
Some((sp, _)) => sp,
None => item.attr_span(self.cx.tcx),
Expand Down Expand Up @@ -1911,7 +1911,7 @@ fn report_diagnostic(
MarkdownLinkRange::Destination(md_range) => {
let mut md_range = md_range.clone();
let sp =
source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs.doc_strings)
source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs.doc_strings())
.map(|(mut sp, _)| {
while dox.as_bytes().get(md_range.start) == Some(&b' ')
|| dox.as_bytes().get(md_range.start) == Some(&b'`')
Expand All @@ -1930,7 +1930,7 @@ fn report_diagnostic(
(sp, MarkdownLinkRange::Destination(md_range))
}
MarkdownLinkRange::WholeLink(md_range) => (
source_span_for_markdown_range(tcx, dox, md_range, &item.attrs.doc_strings)
source_span_for_markdown_range(tcx, dox, md_range, &item.attrs.doc_strings())
.map(|(sp, _)| sp),
link_range.clone(),
),
Expand Down
5 changes: 3 additions & 2 deletions src/librustdoc/passes/lint/bare_urls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &
msg: &'static str,
range: Range<usize>,
without_brackets: Option<&str>| {
let maybe_sp = source_span_for_markdown_range(cx.tcx, dox, &range, &item.attrs.doc_strings)
.map(|(sp, _)| sp);
let maybe_sp =
source_span_for_markdown_range(cx.tcx, dox, &range, &item.attrs.doc_strings())
.map(|(sp, _)| sp);
let sp = maybe_sp.unwrap_or_else(|| item.attr_span(cx.tcx));
cx.tcx.node_span_lint(crate::lint::BARE_URLS, hir_id, sp, |lint| {
lint.primary_message(msg)
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/passes/lint/check_code_block_syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ fn check_rust_syntax(
cx.tcx,
dox,
&code_block.range,
&item.attrs.doc_strings,
&item.attrs.doc_strings(),
) {
Some((sp, _)) => (sp, true),
None => (item.attr_span(cx.tcx), false),
Expand Down
4 changes: 2 additions & 2 deletions src/librustdoc/passes/lint/html_tags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::html::markdown::main_body_opts;
pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &str) {
let tcx = cx.tcx;
let report_diag = |msg: String, range: &Range<usize>, is_open_tag: bool| {
let sp = match source_span_for_markdown_range(tcx, dox, range, &item.attrs.doc_strings) {
let sp = match source_span_for_markdown_range(tcx, dox, range, &item.attrs.doc_strings()) {
Some((sp, _)) => sp,
None => item.attr_span(tcx),
};
Expand Down Expand Up @@ -55,7 +55,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &
tcx,
dox,
&(generics_start..generics_end),
&item.attrs.doc_strings,
&item.attrs.doc_strings(),
) {
Some((sp, _)) => sp,
None => item.attr_span(tcx),
Expand Down
58 changes: 32 additions & 26 deletions src/librustdoc/passes/lint/redundant_explicit_links.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ struct LinkData {
}

pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId) {
let hunks = prepare_to_doc_link_resolution(&item.attrs.doc_strings);
let hunks = prepare_to_doc_link_resolution(&item.attrs.doc_strings());
for (item_id, doc) in hunks {
if let Some(item_id) = item_id.or(item.def_id())
&& !doc.is_empty()
Expand Down Expand Up @@ -160,22 +160,25 @@ fn check_inline_or_reference_unknown_redundancy(
(find_resolution(resolutions, &dest)?, find_resolution(resolutions, resolvable_link)?);

if dest_res == display_res {
let link_span =
match source_span_for_markdown_range(cx.tcx, doc, &link_range, &item.attrs.doc_strings)
{
Some((sp, from_expansion)) => {
if from_expansion {
return None;
}
sp
let link_span = match source_span_for_markdown_range(
cx.tcx,
doc,
&link_range,
&item.attrs.doc_strings(),
) {
Some((sp, from_expansion)) => {
if from_expansion {
return None;
}
None => item.attr_span(cx.tcx),
};
sp
}
None => item.attr_span(cx.tcx),
};
let (explicit_span, false) = source_span_for_markdown_range(
cx.tcx,
doc,
&offset_explicit_range(doc, link_range, open, close),
&item.attrs.doc_strings,
&item.attrs.doc_strings(),
)?
else {
// This `span` comes from macro expansion so skipping it.
Expand All @@ -185,7 +188,7 @@ fn check_inline_or_reference_unknown_redundancy(
cx.tcx,
doc,
resolvable_link_range,
&item.attrs.doc_strings,
&item.attrs.doc_strings(),
)?
else {
// This `span` comes from macro expansion so skipping it.
Expand Down Expand Up @@ -221,22 +224,25 @@ fn check_reference_redundancy(
(find_resolution(resolutions, dest)?, find_resolution(resolutions, resolvable_link)?);

if dest_res == display_res {
let link_span =
match source_span_for_markdown_range(cx.tcx, doc, &link_range, &item.attrs.doc_strings)
{
Some((sp, from_expansion)) => {
if from_expansion {
return None;
}
sp
let link_span = match source_span_for_markdown_range(
cx.tcx,
doc,
&link_range,
&item.attrs.doc_strings(),
) {
Some((sp, from_expansion)) => {
if from_expansion {
return None;
}
None => item.attr_span(cx.tcx),
};
sp
}
None => item.attr_span(cx.tcx),
};
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,
&item.attrs.doc_strings(),
)?
else {
// This `span` comes from macro expansion so skipping it.
Expand All @@ -246,7 +252,7 @@ fn check_reference_redundancy(
cx.tcx,
doc,
resolvable_link_range,
&item.attrs.doc_strings,
&item.attrs.doc_strings(),
)?
else {
// This `span` comes from macro expansion so skipping it.
Expand All @@ -256,7 +262,7 @@ fn check_reference_redundancy(
cx.tcx,
doc,
&offset_reference_def_range(doc, dest, link_range),
&item.attrs.doc_strings,
&item.attrs.doc_strings(),
)?;

cx.tcx.node_span_lint(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, |lint| {
Expand Down
Loading
Loading