|
1 | 1 | use std::fmt::Write; |
2 | 2 | use std::hash::Hash; |
3 | 3 | use std::path::PathBuf; |
4 | | -use std::sync::{Arc, OnceLock as OnceCell}; |
| 4 | +use std::sync::{Arc, OnceLock}; |
5 | 5 | use std::{fmt, iter}; |
6 | 6 |
|
7 | 7 | use arrayvec::ArrayVec; |
@@ -483,22 +483,22 @@ impl Item { |
483 | 483 | .iter() |
484 | 484 | .filter_map(|attr| attr.deprecation_note().map(|note| note.span)); |
485 | 485 |
|
486 | | - span_of_fragments(&self.attrs.doc_strings) |
| 486 | + span_of_fragments(&self.attrs.doc_strings()) |
487 | 487 | .into_iter() |
488 | 488 | .chain(deprecation_notes) |
489 | 489 | .reduce(|a, b| a.to(b)) |
490 | 490 | .unwrap_or_else(|| self.span(tcx).map_or(DUMMY_SP, |span| span.inner())) |
491 | 491 | } |
492 | 492 |
|
493 | 493 | /// Combine all doc strings into a single value handling indentation and newlines as needed. |
494 | | - pub(crate) fn doc_value(&self) -> String { |
| 494 | + pub(crate) fn doc_value(&self) -> &str { |
495 | 495 | self.attrs.doc_value() |
496 | 496 | } |
497 | 497 |
|
498 | 498 | /// Combine all doc strings into a single value handling indentation and newlines as needed. |
499 | 499 | /// Returns `None` is there's no documentation at all, and `Some("")` if there is some |
500 | 500 | /// documentation but it is empty (e.g. `#[doc = ""]`). |
501 | | - pub(crate) fn opt_doc_value(&self) -> Option<String> { |
| 501 | + pub(crate) fn opt_doc_value(&self) -> Option<&str> { |
502 | 502 | self.attrs.opt_doc_value() |
503 | 503 | } |
504 | 504 |
|
@@ -550,7 +550,7 @@ impl Item { |
550 | 550 | pub(crate) fn item_or_reexport_id(&self) -> ItemId { |
551 | 551 | // added documentation on a reexport is always prepended. |
552 | 552 | self.attrs |
553 | | - .doc_strings |
| 553 | + .doc_strings() |
554 | 554 | .first() |
555 | 555 | .map(|x| x.item_id) |
556 | 556 | .flatten() |
@@ -1004,11 +1004,21 @@ pub struct RenderedLink { |
1004 | 1004 | /// as well as doc comments. |
1005 | 1005 | #[derive(Clone, Debug, Default)] |
1006 | 1006 | pub(crate) struct Attributes { |
1007 | | - pub(crate) doc_strings: Vec<DocFragment>, |
| 1007 | + /// IMPORTANT! This should not be mutated since then `doc_value_cache` will be invalid. |
| 1008 | + doc_strings: Vec<DocFragment>, |
1008 | 1009 | pub(crate) other_attrs: ThinVec<hir::Attribute>, |
| 1010 | + doc_value_cache: OnceLock<Option<String>>, |
1009 | 1011 | } |
1010 | 1012 |
|
1011 | 1013 | impl Attributes { |
| 1014 | + fn new(doc_strings: Vec<DocFragment>, other_attrs: ThinVec<hir::Attribute>) -> Self { |
| 1015 | + Self { doc_strings, other_attrs, doc_value_cache: OnceLock::new() } |
| 1016 | + } |
| 1017 | + |
| 1018 | + pub(crate) fn doc_strings(&self) -> &[DocFragment] { |
| 1019 | + &self.doc_strings |
| 1020 | + } |
| 1021 | + |
1012 | 1022 | pub(crate) fn has_doc_flag<F: Fn(&DocAttribute) -> bool>(&self, callback: F) -> bool { |
1013 | 1023 | find_attr!(&self.other_attrs, Doc(d) if callback(d)) |
1014 | 1024 | } |
@@ -1036,26 +1046,30 @@ impl Attributes { |
1036 | 1046 | doc_only: bool, |
1037 | 1047 | ) -> Attributes { |
1038 | 1048 | let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only); |
1039 | | - Attributes { doc_strings, other_attrs } |
| 1049 | + Attributes::new(doc_strings, other_attrs) |
1040 | 1050 | } |
1041 | 1051 |
|
1042 | 1052 | /// Combine all doc strings into a single value handling indentation and newlines as needed. |
1043 | | - pub(crate) fn doc_value(&self) -> String { |
| 1053 | + pub(crate) fn doc_value(&self) -> &str { |
1044 | 1054 | self.opt_doc_value().unwrap_or_default() |
1045 | 1055 | } |
1046 | 1056 |
|
1047 | 1057 | /// Combine all doc strings into a single value handling indentation and newlines as needed. |
1048 | 1058 | /// Returns `None` is there's no documentation at all, and `Some("")` if there is some |
1049 | 1059 | /// documentation but it is empty (e.g. `#[doc = ""]`). |
1050 | | - pub(crate) fn opt_doc_value(&self) -> Option<String> { |
1051 | | - (!self.doc_strings.is_empty()).then(|| { |
1052 | | - let mut res = String::new(); |
1053 | | - for frag in &self.doc_strings { |
1054 | | - add_doc_fragment(&mut res, frag); |
1055 | | - } |
1056 | | - res.pop(); |
1057 | | - res |
1058 | | - }) |
| 1060 | + pub(crate) fn opt_doc_value(&self) -> Option<&str> { |
| 1061 | + self.doc_value_cache |
| 1062 | + .get_or_init(|| { |
| 1063 | + (!self.doc_strings.is_empty()).then(|| { |
| 1064 | + let mut res = String::new(); |
| 1065 | + for frag in &self.doc_strings { |
| 1066 | + add_doc_fragment(&mut res, frag); |
| 1067 | + } |
| 1068 | + res.pop(); |
| 1069 | + res |
| 1070 | + }) |
| 1071 | + }) |
| 1072 | + .as_deref() |
1059 | 1073 | } |
1060 | 1074 |
|
1061 | 1075 | pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> { |
@@ -1673,7 +1687,7 @@ impl PrimitiveType { |
1673 | 1687 | pub(crate) fn simplified_types() -> &'static SimplifiedTypes { |
1674 | 1688 | use PrimitiveType::*; |
1675 | 1689 | use ty::{FloatTy, IntTy, UintTy}; |
1676 | | - static CELL: OnceCell<SimplifiedTypes> = OnceCell::new(); |
| 1690 | + static CELL: OnceLock<SimplifiedTypes> = OnceLock::new(); |
1677 | 1691 |
|
1678 | 1692 | let single = |x| iter::once(x).collect(); |
1679 | 1693 | CELL.get_or_init(move || { |
@@ -1779,7 +1793,7 @@ impl PrimitiveType { |
1779 | 1793 | /// `rustc_doc_primitive`, then it's entirely random whether `std` or the other crate is picked. |
1780 | 1794 | /// (no_std crates are usually fine unless multiple dependencies define a primitive.) |
1781 | 1795 | pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> { |
1782 | | - static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new(); |
| 1796 | + static PRIMITIVE_LOCATIONS: OnceLock<FxIndexMap<PrimitiveType, DefId>> = OnceLock::new(); |
1783 | 1797 | PRIMITIVE_LOCATIONS.get_or_init(|| { |
1784 | 1798 | let mut primitive_locations = FxIndexMap::default(); |
1785 | 1799 | // NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate. |
@@ -2418,7 +2432,7 @@ mod size_asserts { |
2418 | 2432 | static_assert_size!(GenericParamDef, 40); |
2419 | 2433 | static_assert_size!(Generics, 16); |
2420 | 2434 | static_assert_size!(Item, 8); |
2421 | | - static_assert_size!(ItemInner, 144); |
| 2435 | + static_assert_size!(ItemInner, 176); |
2422 | 2436 | static_assert_size!(ItemKind, 48); |
2423 | 2437 | static_assert_size!(PathSegment, 32); |
2424 | 2438 | static_assert_size!(Type, 32); |
|
0 commit comments