summaryrefslogtreecommitdiffstats
path: root/src/librustdoc
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustdoc')
-rw-r--r--src/librustdoc/clean/auto_trait.rs20
-rw-r--r--src/librustdoc/clean/blanket_impl.rs35
-rw-r--r--src/librustdoc/clean/cfg.rs31
-rw-r--r--src/librustdoc/clean/inline.rs61
-rw-r--r--src/librustdoc/clean/mod.rs464
-rw-r--r--src/librustdoc/clean/render_macro_matchers.rs14
-rw-r--r--src/librustdoc/clean/simplify.rs39
-rw-r--r--src/librustdoc/clean/types.rs117
-rw-r--r--src/librustdoc/clean/types/tests.rs2
-rw-r--r--src/librustdoc/clean/utils.rs123
-rw-r--r--src/librustdoc/config.rs26
-rw-r--r--src/librustdoc/core.rs56
-rw-r--r--src/librustdoc/docfs.rs6
-rw-r--r--src/librustdoc/doctest.rs80
-rw-r--r--src/librustdoc/externalfiles.rs12
-rw-r--r--src/librustdoc/formats/cache.rs9
-rw-r--r--src/librustdoc/formats/item_type.rs3
-rw-r--r--src/librustdoc/formats/renderer.rs7
-rw-r--r--src/librustdoc/html/format.rs138
-rw-r--r--src/librustdoc/html/highlight.rs38
-rw-r--r--src/librustdoc/html/highlight/tests.rs2
-rw-r--r--src/librustdoc/html/length_limit.rs7
-rw-r--r--src/librustdoc/html/markdown.rs145
-rw-r--r--src/librustdoc/html/markdown/tests.rs2
-rw-r--r--src/librustdoc/html/render/context.rs39
-rw-r--r--src/librustdoc/html/render/mod.rs266
-rw-r--r--src/librustdoc/html/render/print_item.rs114
-rw-r--r--src/librustdoc/html/render/sidebar.rs14
-rw-r--r--src/librustdoc/html/render/span_map.rs97
-rw-r--r--src/librustdoc/html/render/type_layout.rs2
-rw-r--r--src/librustdoc/html/render/write_shared.rs29
-rw-r--r--src/librustdoc/html/sources.rs7
-rw-r--r--src/librustdoc/html/static/css/noscript.css2
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css74
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css14
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css6
-rw-r--r--src/librustdoc/html/static/css/themes/light.css6
-rw-r--r--src/librustdoc/html/static/js/search.js29
-rw-r--r--src/librustdoc/html/static/js/src-script.js (renamed from src/librustdoc/html/static/js/source-script.js)32
-rw-r--r--src/librustdoc/html/static/js/storage.js2
-rw-r--r--src/librustdoc/html/static_files.rs4
-rw-r--r--src/librustdoc/html/templates/STYLE.md2
-rw-r--r--src/librustdoc/html/templates/page.html16
-rw-r--r--src/librustdoc/html/templates/print_item.html2
-rw-r--r--src/librustdoc/html/templates/type_layout.html5
-rw-r--r--src/librustdoc/json/conversions.rs9
-rw-r--r--src/librustdoc/json/mod.rs6
-rw-r--r--src/librustdoc/lib.rs15
-rw-r--r--src/librustdoc/lint.rs12
-rw-r--r--src/librustdoc/markdown.rs12
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs8
-rw-r--r--src/librustdoc/passes/check_doc_test_visibility.rs11
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs222
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs4
-rw-r--r--src/librustdoc/passes/lint.rs2
-rw-r--r--src/librustdoc/passes/lint/bare_urls.rs13
-rw-r--r--src/librustdoc/passes/lint/check_code_block_syntax.rs19
-rw-r--r--src/librustdoc/passes/lint/html_tags.rs14
-rw-r--r--src/librustdoc/passes/lint/redundant_explicit_links.rs347
-rw-r--r--src/librustdoc/passes/propagate_doc_cfg.rs5
-rw-r--r--src/librustdoc/passes/strip_hidden.rs3
-rw-r--r--src/librustdoc/passes/strip_priv_imports.rs7
-rw-r--r--src/librustdoc/passes/strip_private.rs9
-rw-r--r--src/librustdoc/passes/stripper.rs19
-rw-r--r--src/librustdoc/scrape_examples.rs8
-rw-r--r--src/librustdoc/visit_ast.rs85
-rw-r--r--src/librustdoc/visit_lib.rs4
67 files changed, 1946 insertions, 1087 deletions
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 92bae5516..a06f31a93 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -46,7 +46,7 @@ where
let tcx = self.cx.tcx;
let trait_ref = ty::Binder::dummy(ty::TraitRef::new(tcx, trait_def_id, [ty]));
if !self.cx.generated_synthetics.insert((ty, trait_def_id)) {
- debug!("get_auto_trait_impl_for({:?}): already generated, aborting", trait_ref);
+ debug!("get_auto_trait_impl_for({trait_ref:?}): already generated, aborting");
return None;
}
@@ -137,10 +137,10 @@ where
pub(crate) fn get_auto_trait_impls(&mut self, item_def_id: DefId) -> Vec<Item> {
let tcx = self.cx.tcx;
let param_env = tcx.param_env(item_def_id);
- let ty = tcx.type_of(item_def_id).subst_identity();
+ let ty = tcx.type_of(item_def_id).instantiate_identity();
let f = auto_trait::AutoTraitFinder::new(tcx);
- debug!("get_auto_trait_impls({:?})", ty);
+ debug!("get_auto_trait_impls({ty:?})");
let auto_traits: Vec<_> = self.cx.auto_traits.to_vec();
let mut auto_traits: Vec<Item> = auto_traits
.into_iter()
@@ -163,9 +163,9 @@ where
fn get_lifetime(region: Region<'_>, names_map: &FxHashMap<Symbol, Lifetime>) -> Lifetime {
region_name(region)
.map(|name| {
- names_map.get(&name).unwrap_or_else(|| {
- panic!("Missing lifetime with name {:?} for {:?}", name.as_str(), region)
- })
+ names_map
+ .get(&name)
+ .unwrap_or_else(|| panic!("Missing lifetime with name {name:?} for {region:?}"))
})
.unwrap_or(&Lifetime::statik())
.clone()
@@ -372,7 +372,7 @@ where
let output = output.as_ref().cloned().map(Box::new);
if old_output.is_some() && old_output != output {
- panic!("Output mismatch for {:?} {:?} {:?}", ty, old_output, output);
+ panic!("Output mismatch for {ty:?} {old_output:?} {output:?}");
}
let new_params = GenericArgs::Parenthesized { inputs: old_input, output };
@@ -462,7 +462,7 @@ where
);
let mut generic_params = raw_generics.params;
- debug!("param_env_to_generics({:?}): generic_params={:?}", item_def_id, generic_params);
+ debug!("param_env_to_generics({item_def_id:?}): generic_params={generic_params:?}");
let mut has_sized = FxHashSet::default();
let mut ty_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default();
@@ -623,7 +623,7 @@ where
// loop
ty_to_traits.entry(ty.clone()).or_default().insert(trait_.clone());
}
- _ => panic!("Unexpected LHS {:?} for {:?}", lhs, item_def_id),
+ _ => panic!("Unexpected LHS {lhs:?} for {item_def_id:?}"),
}
}
};
@@ -710,7 +710,7 @@ where
/// involved (impls rarely have more than a few bounds) means that it
/// shouldn't matter in practice.
fn unstable_debug_sort<T: Debug>(&self, vec: &mut [T]) {
- vec.sort_by_cached_key(|x| format!("{:?}", x))
+ vec.sort_by_cached_key(|x| format!("{x:?}"))
}
fn is_fn_trait(&self, path: &Path) -> bool {
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index a36041588..dad2aa406 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -17,7 +17,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
let param_env = cx.tcx.param_env(item_def_id);
let ty = cx.tcx.type_of(item_def_id);
- trace!("get_blanket_impls({:?})", ty);
+ trace!("get_blanket_impls({ty:?})");
let mut impls = Vec::new();
for trait_def_id in cx.tcx.all_traits() {
if !cx.cache.effective_visibilities.is_reachable(cx.tcx, trait_def_id)
@@ -38,18 +38,22 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
continue;
}
let infcx = cx.tcx.infer_ctxt().build();
- let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id);
- let impl_ty = ty.subst(infcx.tcx, substs);
- let param_env = EarlyBinder::bind(param_env).subst(infcx.tcx, substs);
+ let args = infcx.fresh_args_for_item(DUMMY_SP, item_def_id);
+ let impl_ty = ty.instantiate(infcx.tcx, args);
+ let param_env = EarlyBinder::bind(param_env).instantiate(infcx.tcx, args);
- let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
- let impl_trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
+ let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
+ let impl_trait_ref = trait_ref.instantiate(infcx.tcx, impl_args);
// Require the type the impl is implemented on to match
// our type, and ignore the impl if there was a mismatch.
- let Ok(eq_result) = infcx.at(&traits::ObligationCause::dummy(), param_env).eq(DefineOpaqueTypes::No, impl_trait_ref.self_ty(), impl_ty) else {
- continue
- };
+ let Ok(eq_result) = infcx.at(&traits::ObligationCause::dummy(), param_env).eq(
+ DefineOpaqueTypes::No,
+ impl_trait_ref.self_ty(),
+ impl_ty,
+ ) else {
+ continue;
+ };
let InferOk { value: (), obligations } = eq_result;
// FIXME(eddyb) ignoring `obligations` might cause false positives.
drop(obligations);
@@ -63,12 +67,12 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
let predicates = cx
.tcx
.predicates_of(impl_def_id)
- .instantiate(cx.tcx, impl_substs)
+ .instantiate(cx.tcx, impl_args)
.predicates
.into_iter()
.chain(Some(ty::Binder::dummy(impl_trait_ref).to_predicate(infcx.tcx)));
for predicate in predicates {
- debug!("testing predicate {:?}", predicate);
+ debug!("testing predicate {predicate:?}");
let obligation = traits::Obligation::new(
infcx.tcx,
traits::ObligationCause::dummy(),
@@ -104,11 +108,11 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
// the post-inference `trait_ref`, as it's more accurate.
trait_: Some(clean_trait_ref_with_bindings(
cx,
- ty::Binder::dummy(trait_ref.subst_identity()),
+ ty::Binder::dummy(trait_ref.instantiate_identity()),
ThinVec::new(),
)),
for_: clean_middle_ty(
- ty::Binder::dummy(ty.subst_identity()),
+ ty::Binder::dummy(ty.instantiate_identity()),
cx,
None,
None,
@@ -117,11 +121,12 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
.tcx
.associated_items(impl_def_id)
.in_definition_order()
- .map(|x| clean_middle_assoc_item(x, cx))
+ .filter(|item| !item.is_impl_trait_in_trait())
+ .map(|item| clean_middle_assoc_item(item, cx))
.collect::<Vec<_>>(),
polarity: ty::ImplPolarity::Positive,
kind: ImplKind::Blanket(Box::new(clean_middle_ty(
- ty::Binder::dummy(trait_ref.subst_identity().self_ty()),
+ ty::Binder::dummy(trait_ref.instantiate_identity().self_ty()),
cx,
None,
None,
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index 5177cffe6..ab5aec12f 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -434,9 +434,9 @@ impl<'a> fmt::Display for Display<'a> {
}
if let (true, Cfg::Cfg(_, Some(feat))) = (short_longhand, sub_cfg) {
if self.1.is_html() {
- write!(fmt, "<code>{}</code>", feat)?;
+ write!(fmt, "<code>{feat}</code>")?;
} else {
- write!(fmt, "`{}`", feat)?;
+ write!(fmt, "`{feat}`")?;
}
} else {
write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))?;
@@ -471,9 +471,9 @@ impl<'a> fmt::Display for Display<'a> {
}
if let (true, Cfg::Cfg(_, Some(feat))) = (short_longhand, sub_cfg) {
if self.1.is_html() {
- write!(fmt, "<code>{}</code>", feat)?;
+ write!(fmt, "<code>{feat}</code>")?;
} else {
- write!(fmt, "`{}`", feat)?;
+ write!(fmt, "`{feat}`")?;
}
} else {
write_with_opt_paren(fmt, !sub_cfg.is_simple(), Display(sub_cfg, self.1))?;
@@ -519,8 +519,11 @@ impl<'a> fmt::Display for Display<'a> {
"asmjs" => "JavaScript",
"loongarch64" => "LoongArch LA64",
"m68k" => "M68k",
+ "csky" => "CSKY",
"mips" => "MIPS",
+ "mips32r6" => "MIPS Release 6",
"mips64" => "MIPS-64",
+ "mips64r6" => "MIPS-64 Release 6",
"msp430" => "MSP430",
"powerpc" => "PowerPC",
"powerpc64" => "PowerPC-64",
@@ -549,21 +552,21 @@ impl<'a> fmt::Display for Display<'a> {
"sgx" => "SGX",
_ => "",
},
- (sym::target_endian, Some(endian)) => return write!(fmt, "{}-endian", endian),
- (sym::target_pointer_width, Some(bits)) => return write!(fmt, "{}-bit", bits),
+ (sym::target_endian, Some(endian)) => return write!(fmt, "{endian}-endian"),
+ (sym::target_pointer_width, Some(bits)) => return write!(fmt, "{bits}-bit"),
(sym::target_feature, Some(feat)) => match self.1 {
Format::LongHtml => {
- return write!(fmt, "target feature <code>{}</code>", feat);
+ return write!(fmt, "target feature <code>{feat}</code>");
}
- Format::LongPlain => return write!(fmt, "target feature `{}`", feat),
- Format::ShortHtml => return write!(fmt, "<code>{}</code>", feat),
+ Format::LongPlain => return write!(fmt, "target feature `{feat}`"),
+ Format::ShortHtml => return write!(fmt, "<code>{feat}</code>"),
},
(sym::feature, Some(feat)) => match self.1 {
Format::LongHtml => {
- return write!(fmt, "crate feature <code>{}</code>", feat);
+ return write!(fmt, "crate feature <code>{feat}</code>");
}
- Format::LongPlain => return write!(fmt, "crate feature `{}`", feat),
- Format::ShortHtml => return write!(fmt, "<code>{}</code>", feat),
+ Format::LongPlain => return write!(fmt, "crate feature `{feat}`"),
+ Format::ShortHtml => return write!(fmt, "<code>{feat}</code>"),
},
_ => "",
};
@@ -578,12 +581,12 @@ impl<'a> fmt::Display for Display<'a> {
Escape(v.as_str())
)
} else {
- write!(fmt, r#"`{}="{}"`"#, name, v)
+ write!(fmt, r#"`{name}="{v}"`"#)
}
} else if self.1.is_html() {
write!(fmt, "<code>{}</code>", Escape(name.as_str()))
} else {
- write!(fmt, "`{}`", name)
+ write!(fmt, "`{name}`")
}
}
}
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 870cfa930..cac211307 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -9,9 +9,10 @@ use rustc_ast as ast;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, DefIdSet, LocalDefId};
+use rustc_hir::def_id::{DefId, DefIdSet, LocalModDefId};
use rustc_hir::Mutability;
use rustc_metadata::creader::{CStore, LoadedMacro};
+use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Symbol};
@@ -49,7 +50,7 @@ pub(crate) fn try_inline(
}
let mut ret = Vec::new();
- debug!("attrs={:?}", attrs);
+ debug!("attrs={attrs:?}");
let attrs_without_docs = attrs.map(|(attrs, def_id)| {
(attrs.into_iter().filter(|a| a.doc_str().is_none()).cloned().collect::<Vec<_>>(), def_id)
@@ -78,7 +79,7 @@ pub(crate) fn try_inline(
build_impls(cx, did, attrs_without_docs, &mut ret);
clean::UnionItem(build_union(cx, did))
}
- Res::Def(DefKind::TyAlias, did) => {
+ Res::Def(DefKind::TyAlias { .. }, did) => {
record_extern_fqn(cx, did, ItemType::Typedef);
build_impls(cx, did, attrs_without_docs, &mut ret);
clean::TypedefItem(build_type_alias(cx, did))
@@ -137,9 +138,10 @@ pub(crate) fn try_inline(
pub(crate) fn try_inline_glob(
cx: &mut DocContext<'_>,
res: Res,
- current_mod: LocalDefId,
+ current_mod: LocalModDefId,
visited: &mut DefIdSet,
inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
+ import: &hir::Item<'_>,
) -> Option<Vec<clean::Item>> {
let did = res.opt_def_id()?;
if did.is_local() {
@@ -152,12 +154,20 @@ pub(crate) fn try_inline_glob(
// reexported by the glob, e.g. because they are shadowed by something else.
let reexports = cx
.tcx
- .module_children_local(current_mod)
+ .module_children_local(current_mod.to_local_def_id())
.iter()
.filter(|child| !child.reexport_chain.is_empty())
.filter_map(|child| child.res.opt_def_id())
.collect();
- let mut items = build_module_items(cx, did, visited, inlined_names, Some(&reexports));
+ let attrs = cx.tcx.hir().attrs(import.hir_id());
+ let mut items = build_module_items(
+ cx,
+ did,
+ visited,
+ inlined_names,
+ Some(&reexports),
+ Some((attrs, Some(import.owner_id.def_id.to_def_id()))),
+ );
items.retain(|item| {
if let Some(name) = item.name {
// If an item with the same type and name already exists,
@@ -190,7 +200,7 @@ pub(crate) fn record_extern_fqn(cx: &mut DocContext<'_>, did: DefId, kind: ItemT
let fqn = if let ItemType::Macro = kind {
// Check to see if it is a macro 2.0 or built-in macro
if matches!(
- CStore::from_tcx(cx.tcx).load_macro_untracked(did, cx.sess()),
+ CStore::from_tcx(cx.tcx).load_macro_untracked(did, cx.tcx),
LoadedMacro::MacroDef(def, _)
if matches!(&def.kind, ast::ItemKind::MacroDef(ast_def)
if !ast_def.macro_rules)
@@ -215,6 +225,7 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean
.tcx
.associated_items(did)
.in_definition_order()
+ .filter(|item| !item.is_impl_trait_in_trait())
.map(|item| clean_middle_assoc_item(item, cx))
.collect();
@@ -226,7 +237,7 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean
}
fn build_external_function<'tcx>(cx: &mut DocContext<'tcx>, did: DefId) -> Box<clean::Function> {
- let sig = cx.tcx.fn_sig(did).subst_identity();
+ let sig = cx.tcx.fn_sig(did).instantiate_identity();
let late_bound_regions = sig.bound_vars().into_iter().filter_map(|var| match var {
ty::BoundVariableKind::Region(ty::BrNamed(_, name)) if name != kw::UnderscoreLifetime => {
@@ -279,7 +290,7 @@ fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union {
fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> Box<clean::Typedef> {
let predicates = cx.tcx.explicit_predicates_of(did);
let type_ = clean_middle_ty(
- ty::Binder::dummy(cx.tcx.type_of(did).subst_identity()),
+ ty::Binder::dummy(cx.tcx.type_of(did).instantiate_identity()),
cx,
Some(did),
None,
@@ -314,9 +325,8 @@ pub(crate) fn build_impls(
// * https://github.com/rust-lang/rust/pull/99917 — where the feature got used
// * https://github.com/rust-lang/rust/issues/53487 — overall tracking issue for Error
if tcx.has_attr(did, sym::rustc_has_incoherent_inherent_impls) {
- use rustc_middle::ty::fast_reject::SimplifiedType::*;
let type_ =
- if tcx.is_trait(did) { TraitSimplifiedType(did) } else { AdtSimplifiedType(did) };
+ if tcx.is_trait(did) { SimplifiedType::Trait(did) } else { SimplifiedType::Adt(did) };
for &did in tcx.incoherent_impls(type_) {
build_impl(cx, did, attrs, ret);
}
@@ -391,7 +401,7 @@ pub(crate) fn build_impl(
let for_ = match &impl_item {
Some(impl_) => clean_ty(impl_.self_ty, cx),
None => clean_middle_ty(
- ty::Binder::dummy(tcx.type_of(did).subst_identity()),
+ ty::Binder::dummy(tcx.type_of(did).instantiate_identity()),
cx,
Some(did),
None,
@@ -459,6 +469,7 @@ pub(crate) fn build_impl(
None => (
tcx.associated_items(did)
.in_definition_order()
+ .filter(|item| !item.is_impl_trait_in_trait())
.filter(|item| {
// If this is a trait impl, filter out associated items whose corresponding item
// in the associated trait is marked `doc(hidden)`.
@@ -473,7 +484,7 @@ pub(crate) fn build_impl(
associated_trait.def_id,
)
.unwrap(); // corresponding associated item has to exist
- !tcx.is_doc_hidden(trait_item.def_id)
+ document_hidden || !tcx.is_doc_hidden(trait_item.def_id)
} else {
item.visibility(tcx).is_public()
}
@@ -496,7 +507,7 @@ pub(crate) fn build_impl(
let mut stack: Vec<&Type> = vec![&for_];
if let Some(did) = trait_.as_ref().map(|t| t.def_id()) {
- if tcx.is_doc_hidden(did) {
+ if !document_hidden && tcx.is_doc_hidden(did) {
return;
}
}
@@ -505,7 +516,7 @@ pub(crate) fn build_impl(
}
while let Some(ty) = stack.pop() {
- if let Some(did) = ty.def_id(&cx.cache) && tcx.is_doc_hidden(did) {
+ if let Some(did) = ty.def_id(&cx.cache) && !document_hidden && tcx.is_doc_hidden(did) {
return;
}
if let Some(generics) = ty.generics() {
@@ -518,7 +529,7 @@ pub(crate) fn build_impl(
}
let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs);
- trace!("merged_attrs={:?}", merged_attrs);
+ trace!("merged_attrs={merged_attrs:?}");
trace!(
"build_impl: impl {:?} for {:?}",
@@ -547,7 +558,7 @@ pub(crate) fn build_impl(
}
fn build_module(cx: &mut DocContext<'_>, did: DefId, visited: &mut DefIdSet) -> clean::Module {
- let items = build_module_items(cx, did, visited, &mut FxHashSet::default(), None);
+ let items = build_module_items(cx, did, visited, &mut FxHashSet::default(), None, None);
let span = clean::Span::new(cx.tcx.def_span(did));
clean::Module { items, span }
@@ -559,6 +570,7 @@ fn build_module_items(
visited: &mut DefIdSet,
inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
allowed_def_ids: Option<&DefIdSet>,
+ attrs: Option<(&[ast::Attribute], Option<DefId>)>,
) -> Vec<clean::Item> {
let mut items = Vec::new();
@@ -613,7 +625,7 @@ fn build_module_items(
cfg: None,
inline_stmt_id: None,
});
- } else if let Some(i) = try_inline(cx, res, item.ident.name, None, visited) {
+ } else if let Some(i) = try_inline(cx, res, item.ident.name, attrs, visited) {
items.extend(i)
}
}
@@ -632,13 +644,18 @@ pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String {
}
fn build_const(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant {
+ let mut generics =
+ clean_ty_generics(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id));
+ clean::simplify::move_bounds_to_generic_parameters(&mut generics);
+
clean::Constant {
type_: clean_middle_ty(
- ty::Binder::dummy(cx.tcx.type_of(def_id).subst_identity()),
+ ty::Binder::dummy(cx.tcx.type_of(def_id).instantiate_identity()),
cx,
Some(def_id),
None,
),
+ generics: Box::new(generics),
kind: clean::ConstantKind::Extern { def_id },
}
}
@@ -646,7 +663,7 @@ fn build_const(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant {
fn build_static(cx: &mut DocContext<'_>, did: DefId, mutable: bool) -> clean::Static {
clean::Static {
type_: clean_middle_ty(
- ty::Binder::dummy(cx.tcx.type_of(did).subst_identity()),
+ ty::Binder::dummy(cx.tcx.type_of(did).instantiate_identity()),
cx,
Some(did),
None,
@@ -663,7 +680,7 @@ fn build_macro(
import_def_id: Option<DefId>,
macro_kind: MacroKind,
) -> clean::ItemKind {
- match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.sess()) {
+ match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.tcx) {
LoadedMacro::MacroDef(item_def, _) => match macro_kind {
MacroKind::Bang => {
if let ast::ItemKind::MacroDef(ref def) = item_def.kind {
@@ -764,7 +781,7 @@ pub(crate) fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) {
cx.active_extern_traits.insert(did);
}
- debug!("record_extern_trait: {:?}", did);
+ debug!("record_extern_trait: {did:?}");
let trait_ = build_external_trait(cx, did);
cx.external_traits.borrow_mut().insert(did, trait_);
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 8ad1ed095..c9a05460b 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -24,7 +24,6 @@ use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
use rustc_middle::metadata::Reexport;
use rustc_middle::middle::resolve_bound_vars as rbv;
use rustc_middle::ty::fold::TypeFolder;
-use rustc_middle::ty::InternalSubsts;
use rustc_middle::ty::TypeVisitableExt;
use rustc_middle::ty::{self, AdtKind, EarlyBinder, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
@@ -54,7 +53,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<
let mut inserted = FxHashSet::default();
items.extend(doc.foreigns.iter().map(|(item, renamed)| {
let item = clean_maybe_renamed_foreign_item(cx, item, *renamed);
- if let Some(name) = item.name && !item.is_doc_hidden() {
+ if let Some(name) = item.name && (cx.render_options.document_hidden || !item.is_doc_hidden()) {
inserted.insert((item.type_(), name));
}
item
@@ -64,7 +63,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<
return None;
}
let item = clean_doc_module(x, cx);
- if item.is_doc_hidden() {
+ if !cx.render_options.document_hidden && item.is_doc_hidden() {
// Hidden modules are stripped at a later stage.
// If a hidden module has the same name as a visible one, we want
// to keep both of them around.
@@ -85,12 +84,25 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<
}
let v = clean_maybe_renamed_item(cx, item, *renamed, *import_id);
for item in &v {
- if let Some(name) = item.name && !item.is_doc_hidden() {
+ if let Some(name) = item.name && (cx.render_options.document_hidden || !item.is_doc_hidden()) {
inserted.insert((item.type_(), name));
}
}
v
}));
+ items.extend(doc.inlined_foreigns.iter().flat_map(|((_, renamed), (res, local_import_id))| {
+ let Some(def_id) = res.opt_def_id() else { return Vec::new() };
+ let name = renamed.unwrap_or_else(|| cx.tcx.item_name(def_id));
+ let import = cx.tcx.hir().expect_item(*local_import_id);
+ match import.kind {
+ hir::ItemKind::Use(path, kind) => {
+ let hir::UsePath { segments, span, .. } = *path;
+ let path = hir::Path { segments, res: *res, span };
+ clean_use_statement_inner(import, name, &path, kind, cx, &mut Default::default())
+ }
+ _ => unreachable!(),
+ }
+ }));
items.extend(doc.items.values().flat_map(|(item, renamed, _)| {
// Now we actually lower the imports, skipping everything else.
if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind {
@@ -120,25 +132,31 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<
});
let kind = ModuleItem(Module { items, span });
- generate_item_with_correct_attrs(cx, kind, doc.def_id, doc.name, doc.import_id, doc.renamed)
+ generate_item_with_correct_attrs(
+ cx,
+ kind,
+ doc.def_id.to_def_id(),
+ doc.name,
+ doc.import_id,
+ doc.renamed,
+ )
}
fn generate_item_with_correct_attrs(
cx: &mut DocContext<'_>,
kind: ItemKind,
- local_def_id: LocalDefId,
+ def_id: DefId,
name: Symbol,
import_id: Option<LocalDefId>,
renamed: Option<Symbol>,
) -> Item {
- let def_id = local_def_id.to_def_id();
let target_attrs = inline::load_attrs(cx, def_id);
let attrs = if let Some(import_id) = import_id {
let is_inline = inline::load_attrs(cx, import_id.to_def_id())
.lists(sym::doc)
.get_word_attr(sym::inline)
.is_some();
- let mut attrs = get_all_import_attributes(cx, import_id, local_def_id, is_inline);
+ let mut attrs = get_all_import_attributes(cx, import_id, def_id, is_inline);
add_without_unwanted_attributes(&mut attrs, target_attrs, is_inline, None);
attrs
} else {
@@ -197,11 +215,11 @@ pub(crate) fn clean_trait_ref_with_bindings<'tcx>(
) -> Path {
let kind = cx.tcx.def_kind(trait_ref.def_id()).into();
if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) {
- span_bug!(cx.tcx.def_span(trait_ref.def_id()), "`TraitRef` had unexpected kind {:?}", kind);
+ span_bug!(cx.tcx.def_span(trait_ref.def_id()), "`TraitRef` had unexpected kind {kind:?}");
}
inline::record_extern_fqn(cx, trait_ref.def_id(), kind);
let path =
- external_path(cx, trait_ref.def_id(), true, bindings, trait_ref.map_bound(|tr| tr.substs));
+ external_path(cx, trait_ref.def_id(), true, bindings, trait_ref.map_bound(|tr| tr.args));
debug!(?trait_ref);
@@ -239,7 +257,7 @@ fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) ->
| rbv::ResolvedArg::Free(_, node_id),
) = def
{
- if let Some(lt) = cx.substs.get(&node_id).and_then(|p| p.as_lt()).cloned() {
+ if let Some(lt) = cx.args.get(&node_id).and_then(|p| p.as_lt()).cloned() {
return lt;
}
}
@@ -250,11 +268,12 @@ pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg, cx: &mut DocContext<'t
let def_id = cx.tcx.hir().body_owner_def_id(constant.value.body).to_def_id();
Constant {
type_: clean_middle_ty(
- ty::Binder::dummy(cx.tcx.type_of(def_id).subst_identity()),
+ ty::Binder::dummy(cx.tcx.type_of(def_id).instantiate_identity()),
cx,
Some(def_id),
None,
),
+ generics: Box::new(Generics::default()),
kind: ConstantKind::Anonymous { body: constant.value.body },
}
}
@@ -266,6 +285,7 @@ pub(crate) fn clean_middle_const<'tcx>(
// FIXME: instead of storing the stringified expression, store `self` directly instead.
Constant {
type_: clean_middle_ty(constant.map_bound(|c| c.ty()), cx, None, None),
+ generics: Box::new(Generics::default()),
kind: ConstantKind::TyConst { expr: constant.skip_binder().to_string().into() },
}
}
@@ -284,7 +304,7 @@ pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option<Life
| ty::ReError(_)
| ty::RePlaceholder(..)
| ty::ReErased => {
- debug!("cannot clean region {:?}", region);
+ debug!("cannot clean region {region:?}");
None
}
}
@@ -350,9 +370,8 @@ fn clean_poly_trait_predicate<'tcx>(
cx: &mut DocContext<'tcx>,
) -> Option<WherePredicate> {
// `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
- if pred.skip_binder().constness == ty::BoundConstness::ConstIfConst
- && Some(pred.skip_binder().def_id()) == cx.tcx.lang_items().destruct_trait()
- {
+ // FIXME(effects) check constness
+ if Some(pred.skip_binder().def_id()) == cx.tcx.lang_items().destruct_trait() {
return None;
}
@@ -442,7 +461,7 @@ fn clean_projection<'tcx>(
let bounds = cx
.tcx
.explicit_item_bounds(ty.skip_binder().def_id)
- .subst_iter_copied(cx.tcx, ty.skip_binder().substs)
+ .iter_instantiated_copied(cx.tcx, ty.skip_binder().args)
.map(|(pred, _)| pred)
.collect::<Vec<_>>();
return clean_middle_opaque_bounds(cx, bounds);
@@ -481,9 +500,9 @@ fn projection_to_path_segment<'tcx>(
PathSegment {
name: item.name,
args: GenericArgs::AngleBracketed {
- args: substs_to_args(
+ args: ty_args_to_args(
cx,
- ty.map_bound(|ty| &ty.substs[generics.parent_count..]),
+ ty.map_bound(|ty| &ty.args[generics.parent_count..]),
false,
None,
)
@@ -504,7 +523,7 @@ fn clean_generic_param_def<'tcx>(
ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
let default = if has_default {
Some(clean_middle_ty(
- ty::Binder::dummy(cx.tcx.type_of(def.def_id).subst_identity()),
+ ty::Binder::dummy(cx.tcx.type_of(def.def_id).instantiate_identity()),
cx,
Some(def.def_id),
None,
@@ -538,7 +557,7 @@ fn clean_generic_param_def<'tcx>(
)),
default: match has_default {
true => Some(Box::new(
- cx.tcx.const_param_default(def.def_id).subst_identity().to_string(),
+ cx.tcx.const_param_default(def.def_id).instantiate_identity().to_string(),
)),
false => None,
},
@@ -786,10 +805,10 @@ fn clean_ty_generics<'tcx>(
let where_predicates = preds
.predicates
.iter()
- .flat_map(|(p, _)| {
+ .flat_map(|(pred, _)| {
let mut projection = None;
let param_idx = (|| {
- let bound_p = p.kind();
+ let bound_p = pred.kind();
match bound_p.skip_binder() {
ty::ClauseKind::Trait(pred) => {
if let ty::Param(param) = pred.self_ty().kind() {
@@ -814,33 +833,26 @@ fn clean_ty_generics<'tcx>(
})();
if let Some(param_idx) = param_idx
- && let Some(b) = impl_trait.get_mut(&param_idx.into())
+ && let Some(bounds) = impl_trait.get_mut(&param_idx.into())
{
- let p: WherePredicate = clean_predicate(*p, cx)?;
+ let pred = clean_predicate(*pred, cx)?;
- b.extend(
- p.get_bounds()
+ bounds.extend(
+ pred.get_bounds()
.into_iter()
.flatten()
.cloned()
- .filter(|b| !b.is_sized_bound(cx)),
);
- let proj = projection.map(|p| {
- (
- clean_projection(p.map_bound(|p| p.projection_ty), cx, None),
- p.map_bound(|p| p.term),
- )
- });
- if let Some(((_, trait_did, name), rhs)) = proj
- .as_ref()
- .and_then(|(lhs, rhs): &(Type, _)| Some((lhs.projection()?, rhs)))
+ if let Some(proj) = projection
+ && let lhs = clean_projection(proj.map_bound(|p| p.projection_ty), cx, None)
+ && let Some((_, trait_did, name)) = lhs.projection()
{
impl_trait_proj.entry(param_idx).or_default().push((
trait_did,
name,
- *rhs,
- p.get_bound_params()
+ proj.map_bound(|p| p.term),
+ pred.get_bound_params()
.into_iter()
.flatten()
.cloned()
@@ -851,13 +863,32 @@ fn clean_ty_generics<'tcx>(
return None;
}
- Some(p)
+ Some(pred)
})
.collect::<Vec<_>>();
for (param, mut bounds) in impl_trait {
+ let mut has_sized = false;
+ bounds.retain(|b| {
+ if b.is_sized_bound(cx) {
+ has_sized = true;
+ false
+ } else {
+ true
+ }
+ });
+ if !has_sized {
+ bounds.push(GenericBound::maybe_sized(cx));
+ }
+
// Move trait bounds to the front.
- bounds.sort_by_key(|b| !matches!(b, GenericBound::TraitBound(..)));
+ bounds.sort_by_key(|b| !b.is_trait_bound());
+
+ // Add back a `Sized` bound if there are no *trait* bounds remaining (incl. `?Sized`).
+ // Since all potential trait bounds are at the front we can just check the first bound.
+ if bounds.first().map_or(true, |b| !b.is_trait_bound()) {
+ bounds.insert(0, GenericBound::sized(cx));
+ }
let crate::core::ImplTraitParam::ParamIndex(idx) = param else { unreachable!() };
if let Some(proj) = impl_trait_proj.remove(&idx) {
@@ -879,7 +910,7 @@ fn clean_ty_generics<'tcx>(
// implicit `Sized` bound unless removed with `?Sized`.
// However, in the list of where-predicates below, `Sized` appears like a
// normal bound: It's either present (the type is sized) or
- // absent (the type is unsized) but never *maybe* (i.e. `?Sized`).
+ // absent (the type might be unsized) but never *maybe* (i.e. `?Sized`).
//
// This is unsuitable for rendering.
// Thus, as a first step remove all `Sized` bounds that should be implicit.
@@ -890,8 +921,8 @@ fn clean_ty_generics<'tcx>(
let mut sized_params = FxHashSet::default();
where_predicates.retain(|pred| {
if let WherePredicate::BoundPredicate { ty: Generic(g), bounds, .. } = pred
- && *g != kw::SelfUpper
- && bounds.iter().any(|b| b.is_sized_bound(cx))
+ && *g != kw::SelfUpper
+ && bounds.iter().any(|b| b.is_sized_bound(cx))
{
sized_params.insert(*g);
false
@@ -1158,11 +1189,18 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
let local_did = trait_item.owner_id.to_def_id();
cx.with_param_env(local_did, |cx| {
let inner = match trait_item.kind {
- hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(
- clean_ty(ty, cx),
- ConstantKind::Local { def_id: local_did, body: default },
- ),
- hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)),
+ hir::TraitItemKind::Const(ty, Some(default)) => {
+ let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
+ AssocConstItem(
+ Box::new(generics),
+ clean_ty(ty, cx),
+ ConstantKind::Local { def_id: local_did, body: default },
+ )
+ }
+ hir::TraitItemKind::Const(ty, None) => {
+ let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
+ TyAssocConstItem(Box::new(generics), clean_ty(ty, cx))
+ }
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Body(body));
MethodItem(m, None)
@@ -1207,8 +1245,9 @@ pub(crate) fn clean_impl_item<'tcx>(
cx.with_param_env(local_did, |cx| {
let inner = match impl_.kind {
hir::ImplItemKind::Const(ty, expr) => {
+ let generics = clean_generics(impl_.generics, cx);
let default = ConstantKind::Local { def_id: local_did, body: expr };
- AssocConstItem(clean_ty(ty, cx), default)
+ AssocConstItem(Box::new(generics), clean_ty(ty, cx), default)
}
hir::ImplItemKind::Fn(ref sig, body) => {
let m = clean_function(cx, sig, impl_.generics, FunctionArgs::Body(body));
@@ -1243,24 +1282,31 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
let kind = match assoc_item.kind {
ty::AssocKind::Const => {
let ty = clean_middle_ty(
- ty::Binder::dummy(tcx.type_of(assoc_item.def_id).subst_identity()),
+ ty::Binder::dummy(tcx.type_of(assoc_item.def_id).instantiate_identity()),
cx,
Some(assoc_item.def_id),
None,
);
+ let mut generics = Box::new(clean_ty_generics(
+ cx,
+ tcx.generics_of(assoc_item.def_id),
+ tcx.explicit_predicates_of(assoc_item.def_id),
+ ));
+ simplify::move_bounds_to_generic_parameters(&mut generics);
+
let provided = match assoc_item.container {
ty::ImplContainer => true,
ty::TraitContainer => tcx.defaultness(assoc_item.def_id).has_value(),
};
if provided {
- AssocConstItem(ty, ConstantKind::Extern { def_id: assoc_item.def_id })
+ AssocConstItem(generics, ty, ConstantKind::Extern { def_id: assoc_item.def_id })
} else {
- TyAssocConstItem(ty)
+ TyAssocConstItem(generics, ty)
}
}
ty::AssocKind::Fn => {
- let sig = tcx.fn_sig(assoc_item.def_id).subst_identity();
+ let sig = tcx.fn_sig(assoc_item.def_id).instantiate_identity();
let late_bound_regions = sig.bound_vars().into_iter().filter_map(|var| match var {
ty::BoundVariableKind::Region(ty::BrNamed(_, name))
@@ -1283,7 +1329,9 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
if assoc_item.fn_has_self_parameter {
let self_ty = match assoc_item.container {
- ty::ImplContainer => tcx.type_of(assoc_item.container_id(tcx)).subst_identity(),
+ ty::ImplContainer => {
+ tcx.type_of(assoc_item.container_id(tcx)).instantiate_identity()
+ }
ty::TraitContainer => tcx.types.self_param,
};
let self_arg_ty = sig.input(0).skip_binder();
@@ -1339,7 +1387,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
let mut predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates;
if let ty::TraitContainer = assoc_item.container {
let bounds =
- tcx.explicit_item_bounds(assoc_item.def_id).subst_identity_iter_copied();
+ tcx.explicit_item_bounds(assoc_item.def_id).instantiate_identity_iter_copied();
predicates = tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied()));
}
let mut generics = clean_ty_generics(
@@ -1347,34 +1395,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
tcx.generics_of(assoc_item.def_id),
ty::GenericPredicates { parent: None, predicates },
);
- // Move bounds that are (likely) directly attached to the parameters of the
- // (generic) associated type from the where clause to the respective parameter.
- // There is no guarantee that this is what the user actually wrote but we have
- // no way of knowing.
- let mut where_predicates = ThinVec::new();
- for mut pred in generics.where_predicates {
- if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred
- && let Some(GenericParamDef {
- kind: GenericParamDefKind::Type { bounds: param_bounds, .. },
- ..
- }) = generics.params.iter_mut().find(|param| &param.name == arg)
- {
- param_bounds.append(bounds);
- } else if let WherePredicate::RegionPredicate { lifetime: Lifetime(arg), bounds } = &mut pred
- && let Some(GenericParamDef {
- kind: GenericParamDefKind::Lifetime { outlives: param_bounds },
- ..
- }) = generics.params.iter_mut().find(|param| &param.name == arg)
- {
- param_bounds.extend(bounds.drain(..).map(|bound| match bound {
- GenericBound::Outlives(lifetime) => lifetime,
- _ => unreachable!(),
- }));
- } else {
- where_predicates.push(pred);
- }
- }
- generics.where_predicates = where_predicates;
+ simplify::move_bounds_to_generic_parameters(&mut generics);
if let ty::TraitContainer = assoc_item.container {
// Move bounds that are (likely) directly attached to the associated type
@@ -1442,7 +1463,9 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
AssocTypeItem(
Box::new(Typedef {
type_: clean_middle_ty(
- ty::Binder::dummy(tcx.type_of(assoc_item.def_id).subst_identity()),
+ ty::Binder::dummy(
+ tcx.type_of(assoc_item.def_id).instantiate_identity(),
+ ),
cx,
Some(assoc_item.def_id),
None,
@@ -1459,7 +1482,9 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
AssocTypeItem(
Box::new(Typedef {
type_: clean_middle_ty(
- ty::Binder::dummy(tcx.type_of(assoc_item.def_id).subst_identity()),
+ ty::Binder::dummy(
+ tcx.type_of(assoc_item.def_id).instantiate_identity(),
+ ),
cx,
Some(assoc_item.def_id),
None,
@@ -1478,14 +1503,127 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx)
}
+fn first_non_private_clean_path<'tcx>(
+ cx: &mut DocContext<'tcx>,
+ path: &hir::Path<'tcx>,
+ new_path_segments: &'tcx [hir::PathSegment<'tcx>],
+ new_path_span: rustc_span::Span,
+) -> Path {
+ let new_hir_path =
+ hir::Path { segments: new_path_segments, res: path.res, span: new_path_span };
+ let mut new_clean_path = clean_path(&new_hir_path, cx);
+ // In here we need to play with the path data one last time to provide it the
+ // missing `args` and `res` of the final `Path` we get, which, since it comes
+ // from a re-export, doesn't have the generics that were originally there, so
+ // we add them by hand.
+ if let Some(path_last) = path.segments.last().as_ref()
+ && let Some(new_path_last) = new_clean_path.segments[..].last_mut()
+ && let Some(path_last_args) = path_last.args.as_ref()
+ && path_last.args.is_some()
+ {
+ assert!(new_path_last.args.is_empty());
+ new_path_last.args = clean_generic_args(path_last_args, cx);
+ }
+ new_clean_path
+}
+
+/// The goal of this function is to return the first `Path` which is not private (ie not private
+/// or `doc(hidden)`). If it's not possible, it'll return the "end type".
+///
+/// If the path is not a re-export or is public, it'll return `None`.
+fn first_non_private<'tcx>(
+ cx: &mut DocContext<'tcx>,
+ hir_id: hir::HirId,
+ path: &hir::Path<'tcx>,
+) -> Option<Path> {
+ let target_def_id = path.res.opt_def_id()?;
+ let (parent_def_id, ident) = match &path.segments[..] {
+ [] => return None,
+ // Relative paths are available in the same scope as the owner.
+ [leaf] => (cx.tcx.local_parent(hir_id.owner.def_id), leaf.ident),
+ // So are self paths.
+ [parent, leaf] if parent.ident.name == kw::SelfLower => {
+ (cx.tcx.local_parent(hir_id.owner.def_id), leaf.ident)
+ }
+ // Crate paths are not. We start from the crate root.
+ [parent, leaf] if matches!(parent.ident.name, kw::Crate | kw::PathRoot) => {
+ (LOCAL_CRATE.as_def_id().as_local()?, leaf.ident)
+ }
+ [parent, leaf] if parent.ident.name == kw::Super => {
+ let parent_mod = cx.tcx.parent_module(hir_id);
+ if let Some(super_parent) = cx.tcx.opt_local_parent(parent_mod.to_local_def_id()) {
+ (super_parent, leaf.ident)
+ } else {
+ // If we can't find the parent of the parent, then the parent is already the crate.
+ (LOCAL_CRATE.as_def_id().as_local()?, leaf.ident)
+ }
+ }
+ // Absolute paths are not. We start from the parent of the item.
+ [.., parent, leaf] => (parent.res.opt_def_id()?.as_local()?, leaf.ident),
+ };
+ let hir = cx.tcx.hir();
+ // First we try to get the `DefId` of the item.
+ for child in
+ cx.tcx.module_children_local(parent_def_id).iter().filter(move |c| c.ident == ident)
+ {
+ if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = child.res {
+ continue;
+ }
+
+ if let Some(def_id) = child.res.opt_def_id() && target_def_id == def_id {
+ let mut last_path_res = None;
+ 'reexps: for reexp in child.reexport_chain.iter() {
+ if let Some(use_def_id) = reexp.id() &&
+ let Some(local_use_def_id) = use_def_id.as_local() &&
+ let Some(hir::Node::Item(item)) = hir.find_by_def_id(local_use_def_id) &&
+ !item.ident.name.is_empty() &&
+ let hir::ItemKind::Use(path, _) = item.kind
+ {
+ for res in &path.res {
+ if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = res {
+ continue;
+ }
+ if (cx.render_options.document_hidden ||
+ !cx.tcx.is_doc_hidden(use_def_id)) &&
+ // We never check for "cx.render_options.document_private"
+ // because if a re-export is not fully public, it's never
+ // documented.
+ cx.tcx.local_visibility(local_use_def_id).is_public() {
+ break 'reexps;
+ }
+ last_path_res = Some((path, res));
+ continue 'reexps;
+ }
+ }
+ }
+ if !child.reexport_chain.is_empty() {
+ // So in here, we use the data we gathered from iterating the reexports. If
+ // `last_path_res` is set, it can mean two things:
+ //
+ // 1. We found a public reexport.
+ // 2. We didn't find a public reexport so it's the "end type" path.
+ if let Some((new_path, _)) = last_path_res {
+ return Some(first_non_private_clean_path(cx, path, new_path.segments, new_path.span));
+ }
+ // If `last_path_res` is `None`, it can mean two things:
+ //
+ // 1. The re-export is public, no need to change anything, just use the path as is.
+ // 2. Nothing was found, so let's just return the original path.
+ return None;
+ }
+ }
+ }
+ None
+}
+
fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {
- let hir::Ty { hir_id: _, span, ref kind } = *hir_ty;
+ let hir::Ty { hir_id, span, ref kind } = *hir_ty;
let hir::TyKind::Path(qpath) = kind else { unreachable!() };
match qpath {
hir::QPath::Resolved(None, path) => {
if let Res::Def(DefKind::TyParam, did) = path.res {
- if let Some(new_ty) = cx.substs.get(&did).and_then(|p| p.as_ty()).cloned() {
+ if let Some(new_ty) = cx.args.get(&did).and_then(|p| p.as_ty()).cloned() {
return new_ty;
}
if let Some(bounds) = cx.impl_trait_bounds.remove(&did.into()) {
@@ -1496,7 +1634,12 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
if let Some(expanded) = maybe_expand_private_type_alias(cx, path) {
expanded
} else {
- let path = clean_path(path, cx);
+ // First we check if it's a private re-export.
+ let path = if let Some(path) = first_non_private(cx, hir_id, &path) {
+ path
+ } else {
+ clean_path(path, cx)
+ };
resolve_type(cx, path)
}
}
@@ -1563,7 +1706,7 @@ fn maybe_expand_private_type_alias<'tcx>(
cx: &mut DocContext<'tcx>,
path: &hir::Path<'tcx>,
) -> Option<Type> {
- let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None };
+ let Res::Def(DefKind::TyAlias { .. }, def_id) = path.res else { return None };
// Substitute private type aliases
let def_id = def_id.as_local()?;
let alias = if !cx.cache.effective_visibilities.is_exported(cx.tcx, def_id.to_def_id())
@@ -1576,7 +1719,7 @@ fn maybe_expand_private_type_alias<'tcx>(
let hir::ItemKind::TyAlias(ty, generics) = alias else { return None };
let provided_params = &path.segments.last().expect("segments were empty");
- let mut substs = DefIdMap::default();
+ let mut args = DefIdMap::default();
let generic_args = provided_params.args();
let mut indices: hir::GenericParamCount = Default::default();
@@ -1600,7 +1743,7 @@ fn maybe_expand_private_type_alias<'tcx>(
} else {
Lifetime::elided()
};
- substs.insert(param.def_id.to_def_id(), SubstParam::Lifetime(cleaned));
+ args.insert(param.def_id.to_def_id(), SubstParam::Lifetime(cleaned));
}
indices.lifetimes += 1;
}
@@ -1617,10 +1760,9 @@ fn maybe_expand_private_type_alias<'tcx>(
_ => None,
});
if let Some(ty) = type_ {
- substs.insert(param.def_id.to_def_id(), SubstParam::Type(clean_ty(ty, cx)));
+ args.insert(param.def_id.to_def_id(), SubstParam::Type(clean_ty(ty, cx)));
} else if let Some(default) = *default {
- substs
- .insert(param.def_id.to_def_id(), SubstParam::Type(clean_ty(default, cx)));
+ args.insert(param.def_id.to_def_id(), SubstParam::Type(clean_ty(default, cx)));
}
indices.types += 1;
}
@@ -1637,7 +1779,7 @@ fn maybe_expand_private_type_alias<'tcx>(
_ => None,
});
if let Some(ct) = const_ {
- substs.insert(
+ args.insert(
param.def_id.to_def_id(),
SubstParam::Constant(clean_const(ct, cx)),
);
@@ -1648,7 +1790,7 @@ fn maybe_expand_private_type_alias<'tcx>(
}
}
- Some(cx.enter_alias(substs, def_id.to_def_id(), |cx| clean_ty(ty, cx)))
+ Some(cx.enter_alias(args, def_id.to_def_id(), |cx| clean_ty(&ty, cx)))
}
pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {
@@ -1725,11 +1867,11 @@ fn normalize<'tcx>(
.map(|resolved| infcx.resolve_vars_if_possible(resolved.value));
match normalized {
Ok(normalized_value) => {
- debug!("normalized {:?} to {:?}", ty, normalized_value);
+ debug!("normalized {ty:?} to {normalized_value:?}");
Some(normalized_value)
}
Err(err) => {
- debug!("failed to normalize {:?}: {:?}", ty, err);
+ debug!("failed to normalize {ty:?}: {err:?}");
None
}
}
@@ -1922,7 +2064,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
abi: sig.abi(),
}))
}
- ty::Adt(def, substs) => {
+ ty::Adt(def, args) => {
let did = def.did();
let kind = match def.adt_kind() {
AdtKind::Struct => ItemType::Struct,
@@ -1930,7 +2072,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
AdtKind::Enum => ItemType::Enum,
};
inline::record_extern_fqn(cx, did, kind);
- let path = external_path(cx, did, false, ThinVec::new(), bound_ty.rebind(substs));
+ let path = external_path(cx, did, false, ThinVec::new(), bound_ty.rebind(args));
Type::Path { path }
}
ty::Foreign(did) => {
@@ -1940,7 +2082,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
did,
false,
ThinVec::new(),
- ty::Binder::dummy(InternalSubsts::empty()),
+ ty::Binder::dummy(ty::GenericArgs::empty()),
);
Type::Path { path }
}
@@ -1953,10 +2095,10 @@ pub(crate) fn clean_middle_ty<'tcx>(
.principal_def_id()
.or_else(|| dids.next())
.unwrap_or_else(|| panic!("found trait object `{bound_ty:?}` with no traits?"));
- let substs = match obj.principal() {
- Some(principal) => principal.map_bound(|p| p.substs),
- // marker traits have no substs.
- _ => ty::Binder::dummy(InternalSubsts::empty()),
+ let args = match obj.principal() {
+ Some(principal) => principal.map_bound(|p| p.args),
+ // marker traits have no args.
+ _ => ty::Binder::dummy(ty::GenericArgs::empty()),
};
inline::record_extern_fqn(cx, did, ItemType::Trait);
@@ -1965,7 +2107,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
let mut bounds = dids
.map(|did| {
- let empty = ty::Binder::dummy(InternalSubsts::empty());
+ let empty = ty::Binder::dummy(ty::GenericArgs::empty());
let path = external_path(cx, did, false, ThinVec::new(), empty);
inline::record_extern_fqn(cx, did, ItemType::Trait);
PolyTrait { trait_: path, generic_params: Vec::new() }
@@ -1979,7 +2121,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
pb.map_bound(|pb| {
pb
// HACK(compiler-errors): Doesn't actually matter what self
- // type we put here, because we're only using the GAT's substs.
+ // type we put here, because we're only using the GAT's args.
.with_self_ty(cx.tcx, cx.tcx.types.self_param)
.projection_ty
}),
@@ -2005,7 +2147,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
.collect();
let late_bound_regions = late_bound_regions.into_iter().collect();
- let path = external_path(cx, did, false, bindings, substs);
+ let path = external_path(cx, did, false, bindings, args);
bounds.insert(0, PolyTrait { trait_: path, generic_params: late_bound_regions });
DynTrait(bounds, lifetime)
@@ -2026,9 +2168,9 @@ pub(crate) fn clean_middle_ty<'tcx>(
assoc: PathSegment {
name: cx.tcx.associated_item(alias_ty.skip_binder().def_id).name,
args: GenericArgs::AngleBracketed {
- args: substs_to_args(
+ args: ty_args_to_args(
cx,
- alias_ty.map_bound(|ty| ty.substs.as_slice()),
+ alias_ty.map_bound(|ty| ty.args.as_slice()),
true,
None,
)
@@ -2051,11 +2193,11 @@ pub(crate) fn clean_middle_ty<'tcx>(
data.def_id,
false,
ThinVec::new(),
- bound_ty.rebind(data.substs),
+ bound_ty.rebind(data.args),
);
Type::Path { path }
} else {
- let ty = cx.tcx.type_of(data.def_id).subst(cx.tcx, data.substs);
+ let ty = cx.tcx.type_of(data.def_id).instantiate(cx.tcx, data.args);
clean_middle_ty(bound_ty.rebind(ty), cx, None, None)
}
}
@@ -2068,11 +2210,10 @@ pub(crate) fn clean_middle_ty<'tcx>(
}
}
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
// If it's already in the same alias, don't get an infinite loop.
if cx.current_type_aliases.contains_key(&def_id) {
- let path =
- external_path(cx, def_id, false, ThinVec::new(), bound_ty.rebind(substs));
+ let path = external_path(cx, def_id, false, ThinVec::new(), bound_ty.rebind(args));
Type::Path { path }
} else {
*cx.current_type_aliases.entry(def_id).or_insert(0) += 1;
@@ -2081,7 +2222,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
let bounds = cx
.tcx
.explicit_item_bounds(def_id)
- .subst_iter_copied(cx.tcx, substs)
+ .iter_instantiated_copied(cx.tcx, args)
.map(|(bound, _)| bound)
.collect::<Vec<_>>();
let ty = clean_middle_opaque_bounds(cx, bounds);
@@ -2110,7 +2251,6 @@ fn clean_middle_opaque_bounds<'tcx>(
cx: &mut DocContext<'tcx>,
bounds: Vec<ty::Clause<'tcx>>,
) -> Type {
- let mut regions = vec![];
let mut has_sized = false;
let mut bounds = bounds
.iter()
@@ -2119,10 +2259,7 @@ fn clean_middle_opaque_bounds<'tcx>(
let trait_ref = match bound_predicate.skip_binder() {
ty::ClauseKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
- if let Some(r) = clean_middle_region(reg) {
- regions.push(GenericBound::Outlives(r));
- }
- return None;
+ return clean_middle_region(reg).map(GenericBound::Outlives);
}
_ => return None,
};
@@ -2158,10 +2295,20 @@ fn clean_middle_opaque_bounds<'tcx>(
Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, bindings))
})
.collect::<Vec<_>>();
- bounds.extend(regions);
- if !has_sized && !bounds.is_empty() {
- bounds.insert(0, GenericBound::maybe_sized(cx));
+
+ if !has_sized {
+ bounds.push(GenericBound::maybe_sized(cx));
+ }
+
+ // Move trait bounds to the front.
+ bounds.sort_by_key(|b| !b.is_trait_bound());
+
+ // Add back a `Sized` bound if there are no *trait* bounds remaining (incl. `?Sized`).
+ // Since all potential trait bounds are at the front we can just check the first bound.
+ if bounds.first().map_or(true, |b| !b.is_trait_bound()) {
+ bounds.insert(0, GenericBound::sized(cx));
}
+
ImplTrait(bounds)
}
@@ -2174,7 +2321,7 @@ pub(crate) fn clean_middle_field<'tcx>(field: &ty::FieldDef, cx: &mut DocContext
field.did,
field.name,
clean_middle_ty(
- ty::Binder::dummy(cx.tcx.type_of(field.did).subst_identity()),
+ ty::Binder::dummy(cx.tcx.type_of(field.did).instantiate_identity()),
cx,
Some(field.did),
None,
@@ -2305,10 +2452,10 @@ fn clean_bare_fn_ty<'tcx>(
pub(crate) fn reexport_chain<'tcx>(
tcx: TyCtxt<'tcx>,
import_def_id: LocalDefId,
- target_def_id: LocalDefId,
+ target_def_id: DefId,
) -> &'tcx [Reexport] {
for child in tcx.module_children_local(tcx.local_parent(import_def_id)) {
- if child.res.opt_def_id() == Some(target_def_id.to_def_id())
+ if child.res.opt_def_id() == Some(target_def_id)
&& child.reexport_chain.first().and_then(|r| r.id()) == Some(import_def_id.to_def_id())
{
return &child.reexport_chain;
@@ -2321,7 +2468,7 @@ pub(crate) fn reexport_chain<'tcx>(
fn get_all_import_attributes<'hir>(
cx: &mut DocContext<'hir>,
import_def_id: LocalDefId,
- target_def_id: LocalDefId,
+ target_def_id: DefId,
is_inline: bool,
) -> Vec<(Cow<'hir, ast::Attribute>, Option<DefId>)> {
let mut attrs = Vec::new();
@@ -2336,7 +2483,7 @@ fn get_all_import_attributes<'hir>(
attrs = import_attrs.iter().map(|attr| (Cow::Borrowed(attr), Some(def_id))).collect();
first = false;
// We don't add attributes of an intermediate re-export if it has `#[doc(hidden)]`.
- } else if !cx.tcx.is_doc_hidden(def_id) {
+ } else if cx.render_options.document_hidden || !cx.tcx.is_doc_hidden(def_id) {
add_without_unwanted_attributes(&mut attrs, import_attrs, is_inline, Some(def_id));
}
}
@@ -2344,19 +2491,19 @@ fn get_all_import_attributes<'hir>(
}
fn filter_tokens_from_list(
- args_tokens: TokenStream,
+ args_tokens: &TokenStream,
should_retain: impl Fn(&TokenTree) -> bool,
) -> Vec<TokenTree> {
let mut tokens = Vec::with_capacity(args_tokens.len());
let mut skip_next_comma = false;
- for token in args_tokens.into_trees() {
+ for token in args_tokens.trees() {
match token {
TokenTree::Token(Token { kind: TokenKind::Comma, .. }, _) if skip_next_comma => {
skip_next_comma = false;
}
- token if should_retain(&token) => {
+ token if should_retain(token) => {
skip_next_comma = false;
- tokens.push(token);
+ tokens.push(token.clone());
}
_ => {
skip_next_comma = true;
@@ -2414,7 +2561,7 @@ fn add_without_unwanted_attributes<'hir>(
match normal.item.args {
ast::AttrArgs::Delimited(ref mut args) => {
let tokens =
- filter_tokens_from_list(args.tokens.clone(), |token| {
+ filter_tokens_from_list(&args.tokens, |token| {
!matches!(
token,
TokenTree::Token(
@@ -2458,8 +2605,9 @@ fn clean_maybe_renamed_item<'tcx>(
ItemKind::Static(ty, mutability, body_id) => {
StaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: Some(body_id) })
}
- ItemKind::Const(ty, body_id) => ConstantItem(Constant {
+ ItemKind::Const(ty, generics, body_id) => ConstantItem(Constant {
type_: clean_ty(ty, cx),
+ generics: Box::new(clean_generics(generics, cx)),
kind: ConstantKind::Local { body: body_id, def_id },
}),
ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
@@ -2538,7 +2686,7 @@ fn clean_maybe_renamed_item<'tcx>(
vec![generate_item_with_correct_attrs(
cx,
kind,
- item.owner_id.def_id,
+ item.owner_id.def_id.to_def_id(),
name,
import_id,
renamed,
@@ -2574,8 +2722,8 @@ fn clean_impl<'tcx>(
let for_ = clean_ty(impl_.self_ty, cx);
let type_alias =
for_.def_id(&cx.cache).and_then(|alias_def_id: DefId| match tcx.def_kind(alias_def_id) {
- DefKind::TyAlias => Some(clean_middle_ty(
- ty::Binder::dummy(tcx.type_of(def_id).subst_identity()),
+ DefKind::TyAlias { .. } => Some(clean_middle_ty(
+ ty::Binder::dummy(tcx.type_of(def_id).instantiate_identity()),
cx,
Some(def_id.to_def_id()),
None,
@@ -2640,15 +2788,12 @@ fn clean_extern_crate<'tcx>(
}
}
- // FIXME: using `from_def_id_and_kind` breaks `rustdoc/masked` for some reason
- vec![Item {
- name: Some(name),
- attrs: Box::new(Attributes::from_ast(attrs)),
- item_id: crate_def_id.into(),
- kind: Box::new(ExternCrateItem { src: orig_name }),
- cfg: attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
- inline_stmt_id: Some(krate_owner_def_id),
- }]
+ vec![Item::from_def_id_and_parts(
+ krate_owner_def_id,
+ Some(name),
+ ExternCrateItem { src: orig_name },
+ cx,
+ )]
}
fn clean_use_statement<'tcx>(
@@ -2662,9 +2807,6 @@ fn clean_use_statement<'tcx>(
let mut items = Vec::new();
let hir::UsePath { segments, ref res, span } = *path;
for &res in res {
- if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = res {
- continue;
- }
let path = hir::Path { segments, res, span };
items.append(&mut clean_use_statement_inner(import, name, &path, kind, cx, inlined_names));
}
@@ -2679,6 +2821,9 @@ fn clean_use_statement_inner<'tcx>(
cx: &mut DocContext<'tcx>,
inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
) -> Vec<Item> {
+ if should_ignore_res(path.res) {
+ return Vec::new();
+ }
// We need this comparison because some imports (for std types for example)
// are "inserted" as well but directly by the compiler and they should not be
// taken into account.
@@ -2691,11 +2836,12 @@ fn clean_use_statement_inner<'tcx>(
let inline_attr = attrs.lists(sym::doc).get_word_attr(sym::inline);
let pub_underscore = visibility.is_public() && name == kw::Underscore;
let current_mod = cx.tcx.parent_module_from_def_id(import.owner_id.def_id);
+ let import_def_id = import.owner_id.def_id.to_def_id();
// The parent of the module in which this import resides. This
// is the same as `current_mod` if that's already the top
// level module.
- let parent_mod = cx.tcx.parent_module_from_def_id(current_mod);
+ let parent_mod = cx.tcx.parent_module_from_def_id(current_mod.to_local_def_id());
// This checks if the import can be seen from a higher level module.
// In other words, it checks if the visibility is the equivalent of
@@ -2741,9 +2887,14 @@ fn clean_use_statement_inner<'tcx>(
let inner = if kind == hir::UseKind::Glob {
if !denied {
let mut visited = DefIdSet::default();
- if let Some(items) =
- inline::try_inline_glob(cx, path.res, current_mod, &mut visited, inlined_names)
- {
+ if let Some(items) = inline::try_inline_glob(
+ cx,
+ path.res,
+ current_mod,
+ &mut visited,
+ inlined_names,
+ import,
+ ) {
return items;
}
}
@@ -2759,7 +2910,6 @@ fn clean_use_statement_inner<'tcx>(
denied = true;
}
if !denied {
- let import_def_id = import.owner_id.to_def_id();
if let Some(mut items) = inline::try_inline(
cx,
path.res,
@@ -2779,7 +2929,7 @@ fn clean_use_statement_inner<'tcx>(
Import::new_simple(name, resolve_use_source(cx, path), true)
};
- vec![Item::from_def_id_and_parts(import.owner_id.to_def_id(), None, ImportItem(inner), cx)]
+ vec![Item::from_def_id_and_parts(import_def_id, None, ImportItem(inner), cx)]
}
fn clean_maybe_renamed_foreign_item<'tcx>(
diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs
index ef38ca3c1..66d10f236 100644
--- a/src/librustdoc/clean/render_macro_matchers.rs
+++ b/src/librustdoc/clean/render_macro_matchers.rs
@@ -76,17 +76,13 @@ fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option<String
};
// Reparse a single token tree.
- let mut reparsed_trees = match parser.parse_all_token_trees() {
- Ok(reparsed_trees) => reparsed_trees,
- Err(diagnostic) => {
- diagnostic.cancel();
- return None;
- }
- };
- if reparsed_trees.len() != 1 {
+ if parser.token == token::Eof {
+ return None;
+ }
+ let reparsed_tree = parser.parse_token_tree();
+ if parser.token != token::Eof {
return None;
}
- let reparsed_tree = reparsed_trees.pop().unwrap();
// Compare against the original tree.
if reparsed_tree.eq_unspanned(matcher) { Some(snippet) } else { None }
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index 65b1b72ad..7b8f20326 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -47,7 +47,9 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> ThinVec<WP
// Look for equality predicates on associated types that can be merged into
// general bound predicates.
equalities.retain(|(lhs, rhs, bound_params)| {
- let Some((ty, trait_did, name)) = lhs.projection() else { return true; };
+ let Some((ty, trait_did, name)) = lhs.projection() else {
+ return true;
+ };
let Some((bounds, _)) = tybounds.get_mut(ty) else { return true };
merge_bounds(cx, bounds, bound_params.clone(), trait_did, name, rhs)
});
@@ -136,3 +138,38 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId)
})
.any(|did| trait_is_same_or_supertrait(cx, did, trait_))
}
+
+/// Move bounds that are (likely) directly attached to generic parameters from the where-clause to
+/// the respective parameter.
+///
+/// There is no guarantee that this is what the user actually wrote but we have no way of knowing.
+// FIXME(fmease): It'd make a lot of sense to just incorporate this logic into `clean_ty_generics`
+// making every of its users benefit from it.
+pub(crate) fn move_bounds_to_generic_parameters(generics: &mut clean::Generics) {
+ use clean::types::*;
+
+ let mut where_predicates = ThinVec::new();
+ for mut pred in generics.where_predicates.drain(..) {
+ if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred
+ && let Some(GenericParamDef {
+ kind: GenericParamDefKind::Type { bounds: param_bounds, .. },
+ ..
+ }) = generics.params.iter_mut().find(|param| &param.name == arg)
+ {
+ param_bounds.append(bounds);
+ } else if let WherePredicate::RegionPredicate { lifetime: Lifetime(arg), bounds } = &mut pred
+ && let Some(GenericParamDef {
+ kind: GenericParamDefKind::Lifetime { outlives: param_bounds },
+ ..
+ }) = generics.params.iter_mut().find(|param| &param.name == arg)
+ {
+ param_bounds.extend(bounds.drain(..).map(|bound| match bound {
+ GenericBound::Outlives(lifetime) => lifetime,
+ _ => unreachable!(),
+ }));
+ } else {
+ where_predicates.push(pred);
+ }
+ }
+ generics.where_predicates = where_predicates;
+}
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 26139d527..49bde1d31 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -78,7 +78,7 @@ impl ItemId {
#[track_caller]
pub(crate) fn expect_def_id(self) -> DefId {
self.as_def_id()
- .unwrap_or_else(|| panic!("ItemId::expect_def_id: `{:?}` isn't a DefId", self))
+ .unwrap_or_else(|| panic!("ItemId::expect_def_id: `{self:?}` isn't a DefId"))
}
#[inline]
@@ -352,7 +352,7 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
match tcx.def_kind(parent) {
DefKind::Struct | DefKind::Union => false,
DefKind::Variant => true,
- parent_kind => panic!("unexpected parent kind: {:?}", parent_kind),
+ parent_kind => panic!("unexpected parent kind: {parent_kind:?}"),
}
}
@@ -436,7 +436,7 @@ impl Item {
attrs: Box<Attributes>,
cfg: Option<Arc<Cfg>>,
) -> Item {
- trace!("name={:?}, def_id={:?} cfg={:?}", name, def_id, cfg);
+ trace!("name={name:?}, def_id={def_id:?} cfg={cfg:?}");
Item {
item_id: def_id.into(),
@@ -451,11 +451,7 @@ impl Item {
pub(crate) fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
use crate::html::format::{href, link_tooltip};
- let Some(links) = cx.cache()
- .intra_doc_links
- .get(&self.item_id) else {
- return vec![]
- };
+ let Some(links) = cx.cache().intra_doc_links.get(&self.item_id) else { return vec![] };
links
.iter()
.filter_map(|ItemLink { link: s, link_text, page_id: id, ref fragment }| {
@@ -484,11 +480,9 @@ impl Item {
/// the link text, but does need to know which `[]`-bracketed names
/// are actually links.
pub(crate) fn link_names(&self, cache: &Cache) -> Vec<RenderedLink> {
- let Some(links) = cache
- .intra_doc_links
- .get(&self.item_id) else {
- return vec![];
- };
+ let Some(links) = cache.intra_doc_links.get(&self.item_id) else {
+ return vec![];
+ };
links
.iter()
.map(|ItemLink { link: s, link_text, .. }| RenderedLink {
@@ -830,9 +824,9 @@ pub(crate) enum ItemKind {
ProcMacroItem(ProcMacro),
PrimitiveItem(PrimitiveType),
/// A required associated constant in a trait declaration.
- TyAssocConstItem(Type),
+ TyAssocConstItem(Box<Generics>, Type),
/// An associated constant in a trait impl or a provided one in a trait declaration.
- AssocConstItem(Type, ConstantKind),
+ AssocConstItem(Box<Generics>, Type, ConstantKind),
/// A required associated type in a trait declaration.
///
/// The bounds may be non-empty if there is a `where` clause.
@@ -877,8 +871,8 @@ impl ItemKind {
| MacroItem(_)
| ProcMacroItem(_)
| PrimitiveItem(_)
- | TyAssocConstItem(_)
- | AssocConstItem(_, _)
+ | TyAssocConstItem(..)
+ | AssocConstItem(..)
| TyAssocTypeItem(..)
| AssocTypeItem(..)
| StrippedItem(_)
@@ -1225,15 +1219,24 @@ pub(crate) enum GenericBound {
}
impl GenericBound {
+ pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
+ Self::sized_with(cx, hir::TraitBoundModifier::None)
+ }
+
pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
+ Self::sized_with(cx, hir::TraitBoundModifier::Maybe)
+ }
+
+ fn sized_with(cx: &mut DocContext<'_>, modifier: hir::TraitBoundModifier) -> GenericBound {
let did = cx.tcx.require_lang_item(LangItem::Sized, None);
- let empty = ty::Binder::dummy(ty::InternalSubsts::empty());
+ let empty = ty::Binder::dummy(ty::GenericArgs::empty());
let path = external_path(cx, did, false, ThinVec::new(), empty);
inline::record_extern_fqn(cx, did, ItemType::Trait);
- GenericBound::TraitBound(
- PolyTrait { trait_: path, generic_params: Vec::new() },
- hir::TraitBoundModifier::Maybe,
- )
+ GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifier)
+ }
+
+ pub(crate) fn is_trait_bound(&self) -> bool {
+ matches!(self, Self::TraitBound(..))
}
pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
@@ -1275,7 +1278,7 @@ impl Lifetime {
}
}
-#[derive(Clone, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub(crate) enum WherePredicate {
BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
@@ -1345,7 +1348,7 @@ impl GenericParamDef {
}
// maybe use a Generic enum and use Vec<Generic>?
-#[derive(Clone, Debug, Default)]
+#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
pub(crate) struct Generics {
pub(crate) params: ThinVec<GenericParamDef>,
pub(crate) where_predicates: ThinVec<WherePredicate>,
@@ -1782,7 +1785,6 @@ impl PrimitiveType {
}
pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
- use ty::fast_reject::SimplifiedType::*;
use ty::{FloatTy, IntTy, UintTy};
use PrimitiveType::*;
static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
@@ -1790,38 +1792,38 @@ impl PrimitiveType {
let single = |x| iter::once(x).collect();
CELL.get_or_init(move || {
map! {
- Isize => single(IntSimplifiedType(IntTy::Isize)),
- I8 => single(IntSimplifiedType(IntTy::I8)),
- I16 => single(IntSimplifiedType(IntTy::I16)),
- I32 => single(IntSimplifiedType(IntTy::I32)),
- I64 => single(IntSimplifiedType(IntTy::I64)),
- I128 => single(IntSimplifiedType(IntTy::I128)),
- Usize => single(UintSimplifiedType(UintTy::Usize)),
- U8 => single(UintSimplifiedType(UintTy::U8)),
- U16 => single(UintSimplifiedType(UintTy::U16)),
- U32 => single(UintSimplifiedType(UintTy::U32)),
- U64 => single(UintSimplifiedType(UintTy::U64)),
- U128 => single(UintSimplifiedType(UintTy::U128)),
- F32 => single(FloatSimplifiedType(FloatTy::F32)),
- F64 => single(FloatSimplifiedType(FloatTy::F64)),
- Str => single(StrSimplifiedType),
- Bool => single(BoolSimplifiedType),
- Char => single(CharSimplifiedType),
- Array => single(ArraySimplifiedType),
- Slice => single(SliceSimplifiedType),
+ Isize => single(SimplifiedType::Int(IntTy::Isize)),
+ I8 => single(SimplifiedType::Int(IntTy::I8)),
+ I16 => single(SimplifiedType::Int(IntTy::I16)),
+ I32 => single(SimplifiedType::Int(IntTy::I32)),
+ I64 => single(SimplifiedType::Int(IntTy::I64)),
+ I128 => single(SimplifiedType::Int(IntTy::I128)),
+ Usize => single(SimplifiedType::Uint(UintTy::Usize)),
+ U8 => single(SimplifiedType::Uint(UintTy::U8)),
+ U16 => single(SimplifiedType::Uint(UintTy::U16)),
+ U32 => single(SimplifiedType::Uint(UintTy::U32)),
+ U64 => single(SimplifiedType::Uint(UintTy::U64)),
+ U128 => single(SimplifiedType::Uint(UintTy::U128)),
+ F32 => single(SimplifiedType::Float(FloatTy::F32)),
+ F64 => single(SimplifiedType::Float(FloatTy::F64)),
+ Str => single(SimplifiedType::Str),
+ Bool => single(SimplifiedType::Bool),
+ Char => single(SimplifiedType::Char),
+ Array => single(SimplifiedType::Array),
+ Slice => single(SimplifiedType::Slice),
// FIXME: If we ever add an inherent impl for tuples
// with different lengths, they won't show in rustdoc.
//
// Either manually update this arrayvec at this point
// or start with a more complex refactoring.
- Tuple => [TupleSimplifiedType(1), TupleSimplifiedType(2), TupleSimplifiedType(3)].into(),
- Unit => single(TupleSimplifiedType(0)),
- RawPointer => [PtrSimplifiedType(Mutability::Not), PtrSimplifiedType(Mutability::Mut)].into_iter().collect(),
- Reference => [RefSimplifiedType(Mutability::Not), RefSimplifiedType(Mutability::Mut)].into_iter().collect(),
+ Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(),
+ Unit => single(SimplifiedType::Tuple(0)),
+ RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(),
+ Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(),
// FIXME: This will be wrong if we ever add inherent impls
// for function pointers.
- Fn => single(FunctionSimplifiedType(1)),
- Never => single(NeverSimplifiedType),
+ Fn => single(SimplifiedType::Function(1)),
+ Never => single(SimplifiedType::Never),
}
})
}
@@ -2210,6 +2212,17 @@ pub(crate) enum GenericArgs {
Parenthesized { inputs: Box<[Type]>, output: Option<Box<Type>> },
}
+impl GenericArgs {
+ pub(crate) fn is_empty(&self) -> bool {
+ match self {
+ GenericArgs::AngleBracketed { args, bindings } => {
+ args.is_empty() && bindings.is_empty()
+ }
+ GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
+ }
+ }
+}
+
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub(crate) struct PathSegment {
pub(crate) name: Symbol,
@@ -2253,6 +2266,7 @@ pub(crate) struct Static {
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub(crate) struct Constant {
pub(crate) type_: Type,
+ pub(crate) generics: Box<Generics>,
pub(crate) kind: ConstantKind,
}
@@ -2502,7 +2516,8 @@ mod size_asserts {
static_assert_size!(GenericParamDef, 56);
static_assert_size!(Generics, 16);
static_assert_size!(Item, 56);
- static_assert_size!(ItemKind, 64);
+ // FIXME(generic_const_items): Further reduce the size.
+ static_assert_size!(ItemKind, 72);
static_assert_size!(PathSegment, 40);
static_assert_size!(Type, 32);
// tidy-alphabetical-end
diff --git a/src/librustdoc/clean/types/tests.rs b/src/librustdoc/clean/types/tests.rs
index 394954208..4907a5527 100644
--- a/src/librustdoc/clean/types/tests.rs
+++ b/src/librustdoc/clean/types/tests.rs
@@ -73,7 +73,7 @@ fn should_not_trim() {
fn is_same_generic() {
use crate::clean::types::{PrimitiveType, Type};
use crate::formats::cache::Cache;
- let cache = Cache::new(false);
+ let cache = Cache::new(false, false);
let generic = Type::Generic(rustc_span::symbol::sym::Any);
let unit = Type::Primitive(PrimitiveType::Unit);
assert!(!generic.is_doc_subtype_of(&unit, &cache));
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index b786ecbe3..a86bbcc76 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -13,11 +13,10 @@ use rustc_ast as ast;
use rustc_ast::tokenstream::TokenTree;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
use rustc_middle::mir;
use rustc_middle::mir::interpret::ConstValue;
-use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, TyCtxt};
use rustc_span::symbol::{kw, sym, Symbol};
use std::fmt::Write as _;
use std::mem;
@@ -39,11 +38,15 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
for it in &module.items {
// `compiler_builtins` should be masked too, but we can't apply
// `#[doc(masked)]` to the injected `extern crate` because it's unstable.
- if it.is_extern_crate()
- && (it.attrs.has_doc_flag(sym::masked)
- || cx.tcx.is_compiler_builtins(it.item_id.krate()))
- {
+ if cx.tcx.is_compiler_builtins(it.item_id.krate()) {
cx.cache.masked_crates.insert(it.item_id.krate());
+ } else if it.is_extern_crate()
+ && it.attrs.has_doc_flag(sym::masked)
+ && let Some(def_id) = it.item_id.as_def_id()
+ && let Some(local_def_id) = def_id.as_local()
+ && let Some(cnum) = cx.tcx.extern_mod_stmt_cnum(local_def_id)
+ {
+ cx.cache.masked_crates.insert(cnum);
}
}
}
@@ -71,7 +74,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
Crate { module, external_traits: cx.external_traits.clone() }
}
-pub(crate) fn substs_to_args<'tcx>(
+pub(crate) fn ty_args_to_args<'tcx>(
cx: &mut DocContext<'tcx>,
args: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>,
has_self: bool,
@@ -114,12 +117,12 @@ fn external_generic_args<'tcx>(
did: DefId,
has_self: bool,
bindings: ThinVec<TypeBinding>,
- substs: ty::Binder<'tcx, SubstsRef<'tcx>>,
+ ty_args: ty::Binder<'tcx, GenericArgsRef<'tcx>>,
) -> GenericArgs {
- let args = substs_to_args(cx, substs.map_bound(|substs| &substs[..]), has_self, Some(did));
+ let args = ty_args_to_args(cx, ty_args.map_bound(|args| &args[..]), has_self, Some(did));
if cx.tcx.fn_trait_kind_from_def_id(did).is_some() {
- let ty = substs
+ let ty = ty_args
.iter()
.nth(if has_self { 1 } else { 0 })
.unwrap()
@@ -147,7 +150,7 @@ pub(super) fn external_path<'tcx>(
did: DefId,
has_self: bool,
bindings: ThinVec<TypeBinding>,
- substs: ty::Binder<'tcx, SubstsRef<'tcx>>,
+ args: ty::Binder<'tcx, GenericArgsRef<'tcx>>,
) -> Path {
let def_kind = cx.tcx.def_kind(did);
let name = cx.tcx.item_name(did);
@@ -155,7 +158,7 @@ pub(super) fn external_path<'tcx>(
res: Res::Def(def_kind, did),
segments: thin_vec![PathSegment {
name,
- args: external_generic_args(cx, did, has_self, bindings, substs),
+ args: external_generic_args(cx, did, has_self, bindings, args),
}],
}
}
@@ -217,7 +220,7 @@ pub(crate) fn build_deref_target_impls(
pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
use rustc_hir::*;
- debug!("trying to get a name from pattern: {:?}", p);
+ debug!("trying to get a name from pattern: {p:?}");
Symbol::intern(&match p.kind {
PatKind::Wild | PatKind::Struct(..) => return kw::Underscore,
@@ -250,7 +253,7 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
match n.kind() {
- ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs: _ }) => {
+ ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args: _ }) => {
let s = if let Some(def) = def.as_local() {
print_const_expr(cx.tcx, cx.tcx.hir().body_owned_by(def))
} else {
@@ -275,7 +278,7 @@ pub(crate) fn print_evaluated_const(
underscores_and_type: bool,
) -> Option<String> {
tcx.const_eval_poly(def_id).ok().and_then(|val| {
- let ty = tcx.type_of(def_id).subst_identity();
+ let ty = tcx.type_of(def_id).instantiate_identity();
match (val, ty.kind()) {
(_, &ty::Ref(..)) => None,
(ConstValue::Scalar(_), &ty::Adt(_, _)) => None,
@@ -460,7 +463,7 @@ pub(crate) fn print_const_expr(tcx: TyCtxt<'_>, body: hir::BodyId) -> String {
/// Given a type Path, resolve it to a Type using the TyCtxt
pub(crate) fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type {
- debug!("resolve_type({:?})", path);
+ debug!("resolve_type({path:?})");
match path.res {
Res::PrimTy(p) => Primitive(PrimitiveType::from(p)),
@@ -479,12 +482,6 @@ pub(crate) fn get_auto_trait_and_blanket_impls(
cx: &mut DocContext<'_>,
item_def_id: DefId,
) -> impl Iterator<Item = Item> {
- // FIXME: To be removed once `parallel_compiler` bugs are fixed!
- // More information in <https://github.com/rust-lang/rust/pull/106930>.
- if cfg!(parallel_compiler) {
- return vec![].into_iter().chain(vec![].into_iter());
- }
-
let auto_impls = cx
.sess()
.prof
@@ -505,16 +502,30 @@ pub(crate) fn get_auto_trait_and_blanket_impls(
/// [`href()`]: crate::html::format::href
pub(crate) fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId {
use DefKind::*;
- debug!("register_res({:?})", res);
+ debug!("register_res({res:?})");
let (kind, did) = match res {
Res::Def(
- kind @ (AssocTy | AssocFn | AssocConst | Variant | Fn | TyAlias | Enum | Trait | Struct
- | Union | Mod | ForeignTy | Const | Static(_) | Macro(..) | TraitAlias),
+ kind @ (AssocTy
+ | AssocFn
+ | AssocConst
+ | Variant
+ | Fn
+ | TyAlias { .. }
+ | Enum
+ | Trait
+ | Struct
+ | Union
+ | Mod
+ | ForeignTy
+ | Const
+ | Static(_)
+ | Macro(..)
+ | TraitAlias),
did,
) => (kind.into(), did),
- _ => panic!("register_res: unexpected {:?}", res),
+ _ => panic!("register_res: unexpected {res:?}"),
};
if did.is_local() {
return did;
@@ -592,8 +603,12 @@ pub(super) fn render_macro_arms<'a>(
) -> String {
let mut out = String::new();
for matcher in matchers {
- writeln!(out, " {} => {{ ... }}{}", render_macro_matcher(tcx, matcher), arm_delim)
- .unwrap();
+ writeln!(
+ out,
+ " {matcher} => {{ ... }}{arm_delim}",
+ matcher = render_macro_matcher(tcx, matcher),
+ )
+ .unwrap();
}
out
}
@@ -609,22 +624,54 @@ pub(super) fn display_macro_source(
let matchers = def.body.tokens.chunks(4).map(|arm| &arm[0]);
if def.macro_rules {
- format!("macro_rules! {} {{\n{}}}", name, render_macro_arms(cx.tcx, matchers, ";"))
+ format!("macro_rules! {name} {{\n{arms}}}", arms = render_macro_arms(cx.tcx, matchers, ";"))
} else {
if matchers.len() <= 1 {
format!(
- "{}macro {}{} {{\n ...\n}}",
- visibility_to_src_with_space(Some(vis), cx.tcx, def_id),
- name,
- matchers.map(|matcher| render_macro_matcher(cx.tcx, matcher)).collect::<String>(),
+ "{vis}macro {name}{matchers} {{\n ...\n}}",
+ vis = visibility_to_src_with_space(Some(vis), cx.tcx, def_id),
+ matchers = matchers
+ .map(|matcher| render_macro_matcher(cx.tcx, matcher))
+ .collect::<String>(),
)
} else {
format!(
- "{}macro {} {{\n{}}}",
- visibility_to_src_with_space(Some(vis), cx.tcx, def_id),
- name,
- render_macro_arms(cx.tcx, matchers, ","),
+ "{vis}macro {name} {{\n{arms}}}",
+ vis = visibility_to_src_with_space(Some(vis), cx.tcx, def_id),
+ arms = render_macro_arms(cx.tcx, matchers, ","),
)
}
}
}
+
+pub(crate) fn inherits_doc_hidden(
+ tcx: TyCtxt<'_>,
+ mut def_id: LocalDefId,
+ stop_at: Option<LocalDefId>,
+) -> bool {
+ let hir = tcx.hir();
+ while let Some(id) = tcx.opt_local_parent(def_id) {
+ if let Some(stop_at) = stop_at && id == stop_at {
+ return false;
+ }
+ def_id = id;
+ if tcx.is_doc_hidden(def_id.to_def_id()) {
+ return true;
+ } else if let Some(node) = hir.find_by_def_id(def_id) &&
+ matches!(
+ node,
+ hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }),
+ )
+ {
+ // `impl` blocks stand a bit on their own: unless they have `#[doc(hidden)]` directly
+ // on them, they don't inherit it from the parent context.
+ return false;
+ }
+ }
+ false
+}
+
+#[inline]
+pub(crate) fn should_ignore_res(res: Res) -> bool {
+ matches!(res, Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..))
+}
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 217f1a6ee..81fb13f41 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -50,7 +50,7 @@ impl TryFrom<&str> for OutputFormat {
match value {
"json" => Ok(OutputFormat::Json),
"html" => Ok(OutputFormat::Html),
- _ => Err(format!("unknown output format `{}`", value)),
+ _ => Err(format!("unknown output format `{value}`")),
}
}
}
@@ -383,7 +383,7 @@ impl Options {
match kind.parse() {
Ok(kind) => emit.push(kind),
Err(()) => {
- diag.err(format!("unrecognized emission type: {}", kind));
+ diag.err(format!("unrecognized emission type: {kind}"));
return Err(1);
}
}
@@ -415,7 +415,7 @@ impl Options {
println!("rustdoc: [check-theme] Starting tests! (Ignoring all other arguments)");
for theme_file in to_check.iter() {
- print!(" - Checking \"{}\"...", theme_file);
+ print!(" - Checking \"{theme_file}\"...");
let (success, differences) = theme::test_theme_against(theme_file, &paths, &diag);
if !differences.is_empty() || !success {
println!(" FAILED");
@@ -556,30 +556,28 @@ impl Options {
matches.opt_strs("theme").iter().map(|s| (PathBuf::from(&s), s.to_owned()))
{
if !theme_file.is_file() {
- diag.struct_err(format!("invalid argument: \"{}\"", theme_s))
+ diag.struct_err(format!("invalid argument: \"{theme_s}\""))
.help("arguments to --theme must be files")
.emit();
return Err(1);
}
if theme_file.extension() != Some(OsStr::new("css")) {
- diag.struct_err(format!("invalid argument: \"{}\"", theme_s))
+ diag.struct_err(format!("invalid argument: \"{theme_s}\""))
.help("arguments to --theme must have a .css extension")
.emit();
return Err(1);
}
let (success, ret) = theme::test_theme_against(&theme_file, &paths, &diag);
if !success {
- diag.struct_err(format!("error loading theme file: \"{}\"", theme_s)).emit();
+ diag.struct_err(format!("error loading theme file: \"{theme_s}\"")).emit();
return Err(1);
} else if !ret.is_empty() {
diag.struct_warn(format!(
- "theme file \"{}\" is missing CSS rules from the default theme",
- theme_s
+ "theme file \"{theme_s}\" is missing CSS rules from the default theme",
))
.warn("the theme may appear incorrect when loaded")
.help(format!(
- "to see what rules are missing, call `rustdoc --check-theme \"{}\"`",
- theme_s
+ "to see what rules are missing, call `rustdoc --check-theme \"{theme_s}\"`",
))
.emit();
}
@@ -608,7 +606,7 @@ impl Options {
match matches.opt_str("r").as_deref() {
Some("rust") | None => {}
Some(s) => {
- diag.struct_err(format!("unknown input format: {}", s)).emit();
+ diag.struct_err(format!("unknown input format: {s}")).emit();
return Err(1);
}
}
@@ -628,7 +626,7 @@ impl Options {
let crate_types = match parse_crate_types_from_list(matches.opt_strs("crate-type")) {
Ok(types) => types,
Err(e) => {
- diag.struct_err(format!("unknown crate type: {}", e)).emit();
+ diag.struct_err(format!("unknown crate type: {e}")).emit();
return Err(1);
}
};
@@ -787,7 +785,7 @@ fn check_deprecated_options(matches: &getopts::Matches, diag: &rustc_errors::Han
for &flag in deprecated_flags.iter() {
if matches.opt_present(flag) {
- diag.struct_warn(format!("the `{}` flag is deprecated", flag))
+ diag.struct_warn(format!("the `{flag}` flag is deprecated"))
.note(
"see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
for more information",
@@ -800,7 +798,7 @@ fn check_deprecated_options(matches: &getopts::Matches, diag: &rustc_errors::Han
for &flag in removed_flags.iter() {
if matches.opt_present(flag) {
- let mut err = diag.struct_warn(format!("the `{}` flag no longer functions", flag));
+ let mut err = diag.struct_warn(format!("the `{flag}` flag no longer functions"));
err.note(
"see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
for more information",
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 9687b8b18..4c8dab61f 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -10,6 +10,7 @@ use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{HirId, Path};
use rustc_interface::interface;
+use rustc_lint::{late_lint_mod, MissingDoc};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
use rustc_session::config::{self, CrateType, ErrorOutputType, ResolveDocLinks};
@@ -45,7 +46,7 @@ pub(crate) struct DocContext<'tcx> {
// The current set of parameter substitutions,
// for expanding type aliases at the HIR level:
/// Table `DefId` of type, lifetime, or const parameter -> substituted type, lifetime, or const
- pub(crate) substs: DefIdMap<clean::SubstParam>,
+ pub(crate) args: DefIdMap<clean::SubstParam>,
pub(crate) current_type_aliases: DefIdMap<usize>,
/// Table synthetic type parameter for `impl Trait` in argument position -> bounds
pub(crate) impl_trait_bounds: FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>,
@@ -85,17 +86,17 @@ impl<'tcx> DocContext<'tcx> {
/// the substitutions for a type alias' RHS.
pub(crate) fn enter_alias<F, R>(
&mut self,
- substs: DefIdMap<clean::SubstParam>,
+ args: DefIdMap<clean::SubstParam>,
def_id: DefId,
f: F,
) -> R
where
F: FnOnce(&mut Self) -> R,
{
- let old_substs = mem::replace(&mut self.substs, substs);
+ let old_args = mem::replace(&mut self.args, args);
*self.current_type_aliases.entry(def_id).or_insert(0) += 1;
let r = f(self);
- self.substs = old_substs;
+ self.args = old_args;
if let Some(count) = self.current_type_aliases.get_mut(&def_id) {
*count -= 1;
if *count == 0 {
@@ -136,19 +137,13 @@ pub(crate) fn new_handler(
ErrorOutputType::HumanReadable(kind) => {
let (short, color_config) = kind.unzip();
Box::new(
- EmitterWriter::stderr(
- color_config,
- source_map.map(|sm| sm as _),
- None,
- fallback_bundle,
- short,
- unstable_opts.teach,
- diagnostic_width,
- false,
- unstable_opts.track_diagnostics,
- TerminalUrl::No,
- )
- .ui_testing(unstable_opts.ui_testing),
+ EmitterWriter::stderr(color_config, fallback_bundle)
+ .sm(source_map.map(|sm| sm as _))
+ .short_message(short)
+ .teach(unstable_opts.teach)
+ .diagnostic_width(diagnostic_width)
+ .track_diagnostics(unstable_opts.track_diagnostics)
+ .ui_testing(unstable_opts.ui_testing),
)
}
ErrorOutputType::Json { pretty, json_rendered } => {
@@ -173,10 +168,8 @@ pub(crate) fn new_handler(
}
};
- rustc_errors::Handler::with_emitter_and_flags(
- emitter,
- unstable_opts.diagnostic_handler_flags(true),
- )
+ rustc_errors::Handler::with_emitter(emitter)
+ .with_flags(unstable_opts.diagnostic_handler_flags(true))
}
/// Parse, resolve, and typecheck the given crate.
@@ -270,8 +263,9 @@ pub(crate) fn create_config(
parse_sess_created: None,
register_lints: Some(Box::new(crate::lint::register_lints)),
override_queries: Some(|_sess, providers, _external_providers| {
+ // We do not register late module lints, so this only runs `MissingDoc`.
// Most lints will require typechecking, so just don't run them.
- providers.lint_mod = |_, _| {};
+ providers.lint_mod = |tcx, module_def_id| late_lint_mod(tcx, module_def_id, MissingDoc);
// hack so that `used_trait_imports` won't try to call typeck
providers.used_trait_imports = |_, _| {
static EMPTY_SET: LazyLock<UnordSet<LocalDefId>> = LazyLock::new(UnordSet::default);
@@ -289,13 +283,14 @@ pub(crate) fn create_config(
let hir = tcx.hir();
let body = hir.body(hir.body_owned_by(def_id));
- debug!("visiting body for {:?}", def_id);
+ debug!("visiting body for {def_id:?}");
EmitIgnoredResolutionErrors::new(tcx).visit_body(body);
(rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck)(tcx, def_id)
};
}),
make_codegen_backend: None,
registry: rustc_driver::diagnostics_registry(),
+ ice_file: None,
}
}
@@ -324,9 +319,7 @@ pub(crate) fn run_global_ctxt(
tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module))
});
tcx.sess.abort_if_errors();
- tcx.sess.time("missing_docs", || {
- rustc_lint::check_crate(tcx, rustc_lint::builtin::MissingDoc::new);
- });
+ tcx.sess.time("missing_docs", || rustc_lint::check_crate(tcx));
tcx.sess.time("check_mod_attrs", || {
tcx.hir().for_each_module(|module| tcx.ensure().check_mod_attrs(module))
});
@@ -340,12 +333,12 @@ pub(crate) fn run_global_ctxt(
param_env: ParamEnv::empty(),
external_traits: Default::default(),
active_extern_traits: Default::default(),
- substs: Default::default(),
+ args: Default::default(),
current_type_aliases: Default::default(),
impl_trait_bounds: Default::default(),
generated_synthetics: Default::default(),
auto_traits,
- cache: Cache::new(render_options.document_private),
+ cache: Cache::new(render_options.document_private, render_options.document_hidden),
inlined: FxHashSet::default(),
output_format,
render_options,
@@ -384,7 +377,7 @@ pub(crate) fn run_global_ctxt(
fn report_deprecated_attr(name: &str, diag: &rustc_errors::Handler, sp: Span) {
let mut msg =
- diag.struct_span_warn(sp, format!("the `#![doc({})]` attribute is deprecated", name));
+ diag.struct_span_warn(sp, format!("the `#![doc({name})]` attribute is deprecated"));
msg.note(
"see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
for more information",
@@ -477,7 +470,7 @@ impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> {
}
fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) {
- debug!("visiting path {:?}", path);
+ debug!("visiting path {path:?}");
if path.res == Res::Err {
// We have less context here than in rustc_resolve,
// so we can only emit the name and span.
@@ -494,8 +487,7 @@ impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> {
self.tcx.sess,
path.span,
E0433,
- "failed to resolve: {}",
- label
+ "failed to resolve: {label}",
);
err.span_label(path.span, label);
err.note("this error was originally ignored because you are running `rustdoc`");
diff --git a/src/librustdoc/docfs.rs b/src/librustdoc/docfs.rs
index d58b8dc6a..82c1a5039 100644
--- a/src/librustdoc/docfs.rs
+++ b/src/librustdoc/docfs.rs
@@ -72,9 +72,9 @@ impl DocFS {
let sender = self.errors.clone().expect("can't write after closing");
self.pool.execute(move || {
fs::write(&path, contents).unwrap_or_else(|e| {
- sender.send(format!("\"{}\": {}", path.display(), e)).unwrap_or_else(|_| {
- panic!("failed to send error on \"{}\"", path.display())
- })
+ sender.send(format!("\"{path}\": {e}", path = path.display())).unwrap_or_else(
+ |_| panic!("failed to send error on \"{}\"", path.display()),
+ )
});
});
} else {
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 217257316..36d5adb63 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -1,7 +1,7 @@
use rustc_ast as ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
-use rustc_errors::{ColorConfig, ErrorGuaranteed, FatalError, TerminalUrl};
+use rustc_errors::{ColorConfig, ErrorGuaranteed, FatalError};
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::{self as hir, intravisit, CRATE_HIR_ID};
use rustc_interface::interface;
@@ -108,6 +108,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
override_queries: None,
make_codegen_backend: None,
registry: rustc_driver::diagnostics_registry(),
+ ice_file: None,
};
let test_args = options.test_args.clone();
@@ -191,7 +192,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
// The allow lint level is not expected,
// as if allow is specified, no message
// is to be emitted.
- v => unreachable!("Invalid lint level '{}'", v),
+ v => unreachable!("Invalid lint level '{v}'"),
})
.unwrap_or("warn")
.to_string();
@@ -403,7 +404,7 @@ fn run_test(
compiler.stdin(Stdio::piped());
compiler.stderr(Stdio::piped());
- debug!("compiler invocation for doctest: {:?}", compiler);
+ debug!("compiler invocation for doctest: {compiler:?}");
let mut child = compiler.spawn().expect("Failed to spawn rustc process");
{
@@ -468,7 +469,9 @@ fn run_test(
// Run the code!
let mut cmd;
+ let output_file = make_maybe_absolute_path(output_file);
if let Some(tool) = runtool {
+ let tool = make_maybe_absolute_path(tool.into());
cmd = Command::new(tool);
cmd.args(runtool_args);
cmd.arg(output_file);
@@ -502,6 +505,20 @@ fn run_test(
Ok(())
}
+/// Converts a path intended to use as a command to absolute if it is
+/// relative, and not a single component.
+///
+/// This is needed to deal with relative paths interacting with
+/// `Command::current_dir` in a platform-specific way.
+fn make_maybe_absolute_path(path: PathBuf) -> PathBuf {
+ if path.components().count() == 1 {
+ // Look up process via PATH.
+ path
+ } else {
+ std::env::current_dir().map(|c| c.join(&path)).unwrap_or_else(|_| path)
+ }
+}
+
/// Transforms a test into code that can be compiled into a Rust binary, and returns the number of
/// lines before the test code begins as well as if the output stream supports colors or not.
pub(crate) fn make_test(
@@ -557,36 +574,14 @@ pub(crate) fn make_test(
rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
false,
);
- supports_color = EmitterWriter::stderr(
- ColorConfig::Auto,
- None,
- None,
- fallback_bundle.clone(),
- false,
- false,
- Some(80),
- false,
- false,
- TerminalUrl::No,
- )
- .supports_color();
+ supports_color = EmitterWriter::stderr(ColorConfig::Auto, fallback_bundle.clone())
+ .diagnostic_width(Some(80))
+ .supports_color();
- let emitter = EmitterWriter::new(
- Box::new(io::sink()),
- None,
- None,
- fallback_bundle,
- false,
- false,
- false,
- None,
- false,
- false,
- TerminalUrl::No,
- );
+ let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle);
// FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
- let handler = Handler::with_emitter(false, None, Box::new(emitter));
+ let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings();
let sess = ParseSess::with_span_handler(handler, sm);
let mut found_main = false;
@@ -653,8 +648,7 @@ pub(crate) fn make_test(
(found_main, found_extern_crate, found_macro)
})
});
- let Ok((already_has_main, already_has_extern_crate, found_macro)) = result
- else {
+ let Ok((already_has_main, already_has_extern_crate, found_macro)) = result else {
// If the parser panicked due to a fatal error, pass the test code through unchanged.
// The error will be reported during compilation.
return (s.to_owned(), 0, false);
@@ -760,21 +754,9 @@ fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool {
false,
);
- let emitter = EmitterWriter::new(
- Box::new(io::sink()),
- None,
- None,
- fallback_bundle,
- false,
- false,
- false,
- None,
- false,
- false,
- TerminalUrl::No,
- );
+ let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle);
- let handler = Handler::with_emitter(false, None, Box::new(emitter));
+ let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings();
let sess = ParseSess::with_span_handler(handler, sm);
let mut parser =
match maybe_new_parser_from_source_str(&sess, filename, source.to_owned()) {
@@ -967,7 +949,7 @@ impl Collector {
if !item_path.is_empty() {
item_path.push(' ');
}
- format!("{} - {}(line {})", filename.prefer_local(), item_path, line)
+ format!("{} - {item_path}(line {line})", filename.prefer_local())
}
pub(crate) fn set_position(&mut self, position: Span) {
@@ -1044,7 +1026,7 @@ impl Tester for Collector {
path.push(&test_id);
if let Err(err) = std::fs::create_dir_all(&path) {
- eprintln!("Couldn't create directory for doctest executables: {}", err);
+ eprintln!("Couldn't create directory for doctest executables: {err}");
panic::resume_unwind(Box::new(()));
}
@@ -1113,7 +1095,7 @@ impl Tester for Collector {
eprint!("Test executable succeeded, but it's marked `should_panic`.");
}
TestFailure::MissingErrorCodes(codes) => {
- eprint!("Some expected error codes were not found: {:?}", codes);
+ eprint!("Some expected error codes were not found: {codes:?}");
}
TestFailure::ExecutionError(err) => {
eprint!("Couldn't run the test: {err}");
diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs
index 88049c4ca..f0ebb8e5a 100644
--- a/src/librustdoc/externalfiles.rs
+++ b/src/librustdoc/externalfiles.rs
@@ -37,8 +37,7 @@ impl ExternalHtml {
let bc = load_external_files(before_content, diag)?;
let m_bc = load_external_files(md_before_content, diag)?;
let bc = format!(
- "{}{}",
- bc,
+ "{bc}{}",
Markdown {
content: &m_bc,
links: &[],
@@ -53,8 +52,7 @@ impl ExternalHtml {
let ac = load_external_files(after_content, diag)?;
let m_ac = load_external_files(md_after_content, diag)?;
let ac = format!(
- "{}{}",
- ac,
+ "{ac}{}",
Markdown {
content: &m_ac,
links: &[],
@@ -83,7 +81,11 @@ pub(crate) fn load_string<P: AsRef<Path>>(
let contents = match fs::read(file_path) {
Ok(bytes) => bytes,
Err(e) => {
- diag.struct_err(format!("error reading `{}`: {}", file_path.display(), e)).emit();
+ diag.struct_err(format!(
+ "error reading `{file_path}`: {e}",
+ file_path = file_path.display()
+ ))
+ .emit();
return Err(LoadStringError::ReadFail);
}
};
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index dac762e9f..d1deda0c7 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -86,6 +86,9 @@ pub(crate) struct Cache {
/// Whether to document private items.
/// This is stored in `Cache` so it doesn't need to be passed through all rustdoc functions.
pub(crate) document_private: bool,
+ /// Whether to document hidden items.
+ /// This is stored in `Cache` so it doesn't need to be passed through all rustdoc functions.
+ pub(crate) document_hidden: bool,
/// Crates marked with [`#[doc(masked)]`][doc_masked].
///
@@ -137,8 +140,8 @@ struct CacheBuilder<'a, 'tcx> {
}
impl Cache {
- pub(crate) fn new(document_private: bool) -> Self {
- Cache { document_private, ..Cache::default() }
+ pub(crate) fn new(document_private: bool, document_hidden: bool) -> Self {
+ Cache { document_private, document_hidden, ..Cache::default() }
}
/// Populates the `Cache` with more data. The returned `Crate` will be missing some data that was
@@ -473,7 +476,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
| clean::BorrowedRef { type_: box clean::Type::Path { ref path }, .. } => {
dids.insert(path.def_id());
if let Some(generics) = path.generics() &&
- let ty::Adt(adt, _) = self.tcx.type_of(path.def_id()).subst_identity().kind() &&
+ let ty::Adt(adt, _) = self.tcx.type_of(path.def_id()).instantiate_identity().kind() &&
adt.is_fundamental() {
for ty in generics {
if let Some(did) = ty.def_id(self.cache) {
diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs
index 452e14918..a78893558 100644
--- a/src/librustdoc/formats/item_type.rs
+++ b/src/librustdoc/formats/item_type.rs
@@ -115,7 +115,7 @@ impl From<DefKind> for ItemType {
DefKind::Struct => Self::Struct,
DefKind::Union => Self::Union,
DefKind::Trait => Self::Trait,
- DefKind::TyAlias => Self::Typedef,
+ DefKind::TyAlias { .. } => Self::Typedef,
DefKind::TraitAlias => Self::TraitAlias,
DefKind::Macro(kind) => match kind {
MacroKind::Bang => ItemType::Macro,
@@ -136,7 +136,6 @@ impl From<DefKind> for ItemType {
| DefKind::AnonConst
| DefKind::InlineConst
| DefKind::OpaqueTy
- | DefKind::ImplTraitPlaceholder
| DefKind::Field
| DefKind::LifetimeParam
| DefKind::GlobalAsm
diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs
index 6f9cc0266..c49f1a4d3 100644
--- a/src/librustdoc/formats/renderer.rs
+++ b/src/librustdoc/formats/renderer.rs
@@ -77,8 +77,11 @@ pub(crate) fn run_format<'tcx, T: FormatRenderer<'tcx>>(
prof.generic_activity_with_arg("render_mod_item", item.name.unwrap().to_string());
cx.mod_item_in(&item)?;
- let (clean::StrippedItem(box clean::ModuleItem(module)) | clean::ModuleItem(module)) = *item.kind
- else { unreachable!() };
+ let (clean::StrippedItem(box clean::ModuleItem(module)) | clean::ModuleItem(module)) =
+ *item.kind
+ else {
+ unreachable!()
+ };
for it in module.items {
debug!("Adding {:?} to worklist", it.name);
work.push((cx.make_child_renderer(), it));
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 54c0cd2ef..2f611c31a 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -18,7 +18,7 @@ use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_metadata::creader::{CStore, LoadedMacro};
use rustc_middle::ty;
use rustc_middle::ty::TyCtxt;
@@ -109,6 +109,10 @@ impl Buffer {
self.buffer
}
+ pub(crate) fn push(&mut self, c: char) {
+ self.buffer.push(c);
+ }
+
pub(crate) fn push_str(&mut self, s: &str) {
self.buffer.push_str(s);
}
@@ -228,9 +232,9 @@ impl clean::GenericParamDef {
if let Some(default) = default {
if f.alternate() {
- write!(f, " = {:#}", default)?;
+ write!(f, " = {default:#}")?;
} else {
- write!(f, " = {}", default)?;
+ write!(f, " = {default}")?;
}
}
@@ -451,9 +455,9 @@ impl clean::GenericBound {
hir::TraitBoundModifier::MaybeConst => "",
};
if f.alternate() {
- write!(f, "{}{:#}", modifier_str, ty.print(cx))
+ write!(f, "{modifier_str}{ty:#}", ty = ty.print(cx))
} else {
- write!(f, "{}{}", modifier_str, ty.print(cx))
+ write!(f, "{modifier_str}{ty}", ty = ty.print(cx))
}
}
})
@@ -599,12 +603,12 @@ fn generate_macro_def_id_path(
let cstore = CStore::from_tcx(tcx);
// We need this to prevent a `panic` when this function is used from intra doc links...
if !cstore.has_crate_data(def_id.krate) {
- debug!("No data for crate {}", crate_name);
+ debug!("No data for crate {crate_name}");
return Err(HrefError::NotInExternalCache);
}
// Check to see if it is a macro 2.0 or built-in macro.
// More information in <https://rust-lang.github.io/rfcs/1584-macros.html>.
- let is_macro_2 = match cstore.load_macro_untracked(def_id, tcx.sess) {
+ let is_macro_2 = match cstore.load_macro_untracked(def_id, tcx) {
LoadedMacro::MacroDef(def, _) => {
// If `ast_def.macro_rules` is `true`, then it's not a macro 2.0.
matches!(&def.kind, ast::ItemKind::MacroDef(ast_def) if !ast_def.macro_rules)
@@ -631,19 +635,18 @@ fn generate_macro_def_id_path(
let url = match cache.extern_locations[&def_id.krate] {
ExternalLocation::Remote(ref s) => {
// `ExternalLocation::Remote` always end with a `/`.
- format!("{}{}", s, path.iter().map(|p| p.as_str()).join("/"))
+ format!("{s}{path}", path = path.iter().map(|p| p.as_str()).join("/"))
}
ExternalLocation::Local => {
// `root_path` always end with a `/`.
format!(
- "{}{}/{}",
- root_path.unwrap_or(""),
- crate_name,
- path.iter().map(|p| p.as_str()).join("/")
+ "{root_path}{crate_name}/{path}",
+ root_path = root_path.unwrap_or(""),
+ path = path.iter().map(|p| p.as_str()).join("/")
)
}
ExternalLocation::Unknown => {
- debug!("crate {} not in cache when linkifying macros", crate_name);
+ debug!("crate {crate_name} not in cache when linkifying macros");
return Err(HrefError::NotInExternalCache);
}
};
@@ -662,6 +665,14 @@ pub(crate) fn href_with_root_path(
// documented on their parent's page
tcx.parent(did)
}
+ DefKind::ExternCrate => {
+ // Link to the crate itself, not the `extern crate` item.
+ if let Some(local_did) = did.as_local() {
+ tcx.extern_mod_stmt_cnum(local_did).unwrap_or(LOCAL_CRATE).as_def_id()
+ } else {
+ did
+ }
+ }
_ => did,
};
let cache = cx.cache();
@@ -724,7 +735,7 @@ pub(crate) fn href_with_root_path(
_ => {
let prefix = shortty.as_str();
let last = fqp.last().unwrap();
- url_parts.push_fmt(format_args!("{}.{}.html", prefix, last));
+ url_parts.push_fmt(format_args!("{prefix}.{last}.html"));
}
}
Ok((url_parts.finish(), shortty, fqp.to_vec()))
@@ -771,9 +782,10 @@ pub(crate) fn href_relative_parts<'fqp>(
pub(crate) fn link_tooltip(did: DefId, fragment: &Option<UrlFragment>, cx: &Context<'_>) -> String {
let cache = cx.cache();
- let Some((fqp, shortty)) = cache.paths.get(&did)
- .or_else(|| cache.external_paths.get(&did))
- else { return String::new() };
+ let Some((fqp, shortty)) = cache.paths.get(&did).or_else(|| cache.external_paths.get(&did))
+ else {
+ return String::new();
+ };
let mut buf = Buffer::new();
let fqp = if *shortty == ItemType::Primitive {
// primitives are documented in a crate, but not actually part of it
@@ -819,9 +831,9 @@ fn resolved_path<'cx>(
let path = if use_absolute {
if let Ok((_, _, fqp)) = href(did, cx) {
format!(
- "{}::{}",
- join_with_double_colon(&fqp[..fqp.len() - 1]),
- anchor(did, *fqp.last().unwrap(), cx)
+ "{path}::{anchor}",
+ path = join_with_double_colon(&fqp[..fqp.len() - 1]),
+ anchor = anchor(did, *fqp.last().unwrap(), cx)
)
} else {
last.name.to_string()
@@ -829,7 +841,7 @@ fn resolved_path<'cx>(
} else {
anchor(did, last.name, cx).to_string()
};
- write!(w, "{}{}", path, last.args.print(cx))?;
+ write!(w, "{path}{args}", args = last.args.print(cx))?;
}
Ok(())
}
@@ -897,7 +909,7 @@ fn primitive_link_fragment(
None => {}
}
}
- write!(f, "{}", name)?;
+ f.write_str(name)?;
if needs_termination {
write!(f, "</a>")?;
}
@@ -937,15 +949,11 @@ pub(crate) fn anchor<'a, 'cx: 'a>(
if let Ok((url, short_ty, fqp)) = parts {
write!(
f,
- r#"<a class="{}" href="{}" title="{} {}">{}</a>"#,
- short_ty,
- url,
- short_ty,
- join_with_double_colon(&fqp),
- text.as_str()
+ r#"<a class="{short_ty}" href="{url}" title="{short_ty} {path}">{text}</a>"#,
+ path = join_with_double_colon(&fqp),
)
} else {
- write!(f, "{}", text)
+ f.write_str(text.as_str())
}
})
}
@@ -956,10 +964,10 @@ fn fmt_type<'cx>(
use_absolute: bool,
cx: &'cx Context<'_>,
) -> fmt::Result {
- trace!("fmt_type(t = {:?})", t);
+ trace!("fmt_type(t = {t:?})");
match *t {
- clean::Generic(name) => write!(f, "{}", name),
+ clean::Generic(name) => f.write_str(name.as_str()),
clean::Type::Path { ref path } => {
// Paths like `T::Output` and `Self::Output` should be rendered with all segments.
let did = path.def_id();
@@ -1076,13 +1084,13 @@ fn fmt_type<'cx>(
if matches!(**t, clean::Generic(_)) || t.is_assoc_ty() {
let text = if f.alternate() {
- format!("*{} {:#}", m, t.print(cx))
+ format!("*{m} {ty:#}", ty = t.print(cx))
} else {
- format!("*{} {}", m, t.print(cx))
+ format!("*{m} {ty}", ty = t.print(cx))
};
primitive_link(f, clean::PrimitiveType::RawPointer, &text, cx)
} else {
- primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{} ", m), cx)?;
+ primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{m} "), cx)?;
fmt::Display::fmt(&t.print(cx), f)
}
}
@@ -1093,22 +1101,35 @@ fn fmt_type<'cx>(
};
let m = mutability.print_with_space();
let amp = if f.alternate() { "&" } else { "&amp;" };
- match **ty {
+
+ if let clean::Generic(name) = **ty {
+ return primitive_link(
+ f,
+ PrimitiveType::Reference,
+ &format!("{amp}{lt}{m}{name}"),
+ cx,
+ );
+ }
+
+ write!(f, "{amp}{lt}{m}")?;
+
+ let needs_parens = match **ty {
clean::DynTrait(ref bounds, ref trait_lt)
if bounds.len() > 1 || trait_lt.is_some() =>
{
- write!(f, "{}{}{}(", amp, lt, m)?;
- fmt_type(ty, f, use_absolute, cx)?;
- write!(f, ")")
- }
- clean::Generic(name) => {
- primitive_link(f, PrimitiveType::Reference, &format!("{amp}{lt}{m}{name}"), cx)
- }
- _ => {
- write!(f, "{}{}{}", amp, lt, m)?;
- fmt_type(ty, f, use_absolute, cx)
+ true
}
+ clean::ImplTrait(ref bounds) if bounds.len() > 1 => true,
+ _ => false,
+ };
+ if needs_parens {
+ f.write_str("(")?;
+ }
+ fmt_type(ty, f, use_absolute, cx)?;
+ if needs_parens {
+ f.write_str(")")?;
}
+ Ok(())
}
clean::ImplTrait(ref bounds) => {
if f.alternate() {
@@ -1423,11 +1444,20 @@ impl clean::FnDecl {
clean::SelfValue => {
write!(f, "self")?;
}
- clean::SelfBorrowed(Some(ref lt), mtbl) => {
- write!(f, "{}{} {}self", amp, lt.print(), mtbl.print_with_space())?;
+ clean::SelfBorrowed(Some(ref lt), mutability) => {
+ write!(
+ f,
+ "{amp}{lifetime} {mutability}self",
+ lifetime = lt.print(),
+ mutability = mutability.print_with_space(),
+ )?;
}
- clean::SelfBorrowed(None, mtbl) => {
- write!(f, "{}{}self", amp, mtbl.print_with_space())?;
+ clean::SelfBorrowed(None, mutability) => {
+ write!(
+ f,
+ "{amp}{mutability}self",
+ mutability = mutability.print_with_space(),
+ )?;
}
clean::SelfExplicit(ref typ) => {
write!(f, "self: ")?;
@@ -1501,7 +1531,7 @@ pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>(
"pub(super) ".into()
} else {
let path = cx.tcx().def_path(vis_did);
- debug!("path={:?}", path);
+ debug!("path={path:?}");
// modified from `resolved_path()` to work with `DefPathData`
let last_name = path.data.last().unwrap().data.get_opt_name().unwrap();
let anchor = anchor(vis_did, last_name, cx);
@@ -1510,12 +1540,12 @@ pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>(
for seg in &path.data[..path.data.len() - 1] {
let _ = write!(s, "{}::", seg.data.get_opt_name().unwrap());
}
- let _ = write!(s, "{}) ", anchor);
+ let _ = write!(s, "{anchor}) ");
s.into()
}
}
};
- display_fn(move |f| write!(f, "{}", to_print))
+ display_fn(move |f| f.write_str(&to_print))
}
/// This function is the same as print_with_space, except that it renders no links.
@@ -1610,7 +1640,7 @@ impl clean::Import {
if name == self.source.path.last() {
write!(f, "use {};", self.source.print(cx))
} else {
- write!(f, "use {} as {};", self.source.print(cx), name)
+ write!(f, "use {source} as {name};", source = self.source.print(cx))
}
}
clean::ImportKind::Glob => {
@@ -1639,7 +1669,7 @@ impl clean::ImportSource {
if let hir::def::Res::PrimTy(p) = self.path.res {
primitive_link(f, PrimitiveType::from(p), name.as_str(), cx)?;
} else {
- write!(f, "{}", name)?;
+ f.write_str(name.as_str())?;
}
Ok(())
}
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index c94968b48..039e8cdb9 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -928,18 +928,16 @@ fn string_without_closing_tag<T: Display>(
href_context: &Option<HrefContext<'_, '_>>,
open_tag: bool,
) -> Option<&'static str> {
- let Some(klass) = klass
- else {
- write!(out, "{}", text).unwrap();
+ let Some(klass) = klass else {
+ write!(out, "{text}").unwrap();
return None;
};
- let Some(def_span) = klass.get_span()
- else {
+ let Some(def_span) = klass.get_span() else {
if !open_tag {
- write!(out, "{}", text).unwrap();
+ write!(out, "{text}").unwrap();
return None;
}
- write!(out, "<span class=\"{}\">{}", klass.as_html(), text).unwrap();
+ write!(out, "<span class=\"{klass}\">{text}", klass = klass.as_html()).unwrap();
return Some("</span>");
};
@@ -949,14 +947,17 @@ fn string_without_closing_tag<T: Display>(
match t {
"self" | "Self" => write!(
&mut path,
- "<span class=\"{}\">{}</span>",
- Class::Self_(DUMMY_SP).as_html(),
- t
+ "<span class=\"{klass}\">{t}</span>",
+ klass = Class::Self_(DUMMY_SP).as_html(),
),
"crate" | "super" => {
- write!(&mut path, "<span class=\"{}\">{}</span>", Class::KeyWord.as_html(), t)
+ write!(
+ &mut path,
+ "<span class=\"{klass}\">{t}</span>",
+ klass = Class::KeyWord.as_html(),
+ )
}
- t => write!(&mut path, "{}", t),
+ t => write!(&mut path, "{t}"),
}
.expect("Failed to build source HTML path");
path
@@ -988,19 +989,24 @@ fn string_without_closing_tag<T: Display>(
)
.ok()
.map(|(url, _, _)| url),
+ LinkFromSrc::Doc(def_id) => {
+ format::href_with_root_path(*def_id, context, Some(&href_context.root_path))
+ .ok()
+ .map(|(doc_link, _, _)| doc_link)
+ }
}
})
{
if !open_tag {
// We're already inside an element which has the same klass, no need to give it
// again.
- write!(out, "<a href=\"{}\">{}", href, text_s).unwrap();
+ write!(out, "<a href=\"{href}\">{text_s}").unwrap();
} else {
let klass_s = klass.as_html();
if klass_s.is_empty() {
- write!(out, "<a href=\"{}\">{}", href, text_s).unwrap();
+ write!(out, "<a href=\"{href}\">{text_s}").unwrap();
} else {
- write!(out, "<a class=\"{}\" href=\"{}\">{}", klass_s, href, text_s).unwrap();
+ write!(out, "<a class=\"{klass_s}\" href=\"{href}\">{text_s}").unwrap();
}
}
return Some("</a>");
@@ -1015,7 +1021,7 @@ fn string_without_closing_tag<T: Display>(
out.write_str(&text_s).unwrap();
Some("")
} else {
- write!(out, "<span class=\"{}\">{}", klass_s, text_s).unwrap();
+ write!(out, "<span class=\"{klass_s}\">{text_s}").unwrap();
Some("</span>")
}
}
diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs
index 2c93b9a09..4c0874a68 100644
--- a/src/librustdoc/html/highlight/tests.rs
+++ b/src/librustdoc/html/highlight/tests.rs
@@ -23,7 +23,7 @@ fn test_html_highlighting() {
let html = {
let mut out = Buffer::new();
write_code(&mut out, src, None, None);
- format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner())
+ format!("{STYLE}<pre><code>{}</code></pre>\n", out.into_inner())
};
expect_file!["fixtures/sample.html"].assert_eq(&html);
});
diff --git a/src/librustdoc/html/length_limit.rs b/src/librustdoc/html/length_limit.rs
index 4c8db2c67..8562e103d 100644
--- a/src/librustdoc/html/length_limit.rs
+++ b/src/librustdoc/html/length_limit.rs
@@ -78,8 +78,7 @@ impl HtmlWithLimit {
pub(super) fn open_tag(&mut self, tag_name: &'static str) {
assert!(
tag_name.chars().all(|c| ('a'..='z').contains(&c)),
- "tag_name contained non-alphabetic chars: {:?}",
- tag_name
+ "tag_name contained non-alphabetic chars: {tag_name:?}",
);
self.queued_tags.push(tag_name);
}
@@ -88,7 +87,7 @@ impl HtmlWithLimit {
pub(super) fn close_tag(&mut self) {
match self.unclosed_tags.pop() {
// Close the most recently opened tag.
- Some(tag_name) => write!(self.buf, "</{}>", tag_name).unwrap(),
+ Some(tag_name) => write!(self.buf, "</{tag_name}>").unwrap(),
// There are valid cases where `close_tag()` is called without
// there being any tags to close. For example, this occurs when
// a tag is opened after the length limit is exceeded;
@@ -101,7 +100,7 @@ impl HtmlWithLimit {
/// Write all queued tags and add them to the `unclosed_tags` list.
fn flush_queue(&mut self) {
for tag_name in self.queued_tags.drain(..) {
- write!(self.buf, "<{}>", tag_name).unwrap();
+ write!(self.buf, "<{tag_name}>").unwrap();
self.unclosed_tags.push(tag_name);
}
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index fd00277e2..98cc38a10 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -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)]
@@ -246,10 +246,9 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
return Some(Event::Html(
format!(
"<div class=\"example-wrap\">\
- <pre class=\"language-{}\"><code>{}</code></pre>\
+ <pre class=\"language-{lang}\"><code>{text}</code></pre>\
</div>",
- lang,
- Escape(&original_text),
+ text = Escape(&original_text),
)
.into(),
));
@@ -288,8 +287,9 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
let test_escaped = small_url_encode(test);
Some(format!(
- r#"<a class="test-arrow" target="_blank" href="{}?code={}{}&amp;edition={}">Run</a>"#,
- url, test_escaped, channel, edition,
+ "<a class=\"test-arrow\" \
+ target=\"_blank\" \
+ href=\"{url}?code={test_escaped}{channel}&amp;edition={edition}\">Run</a>",
))
});
@@ -308,7 +308,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
// insert newline to clearly separate it from the
// previous block so we can shorten the html output
let mut s = Buffer::new();
- s.push_str("\n");
+ s.push('\n');
highlight::render_example_with_highlighting(
&text,
@@ -349,7 +349,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> {
dest,
title,
))) => {
- debug!("saw start of shortcut link to {} with title {}", dest, title);
+ debug!("saw start of shortcut link to {dest} with title {title}");
// If this is a shortcut link, it was resolved by the broken_link_callback.
// So the URL will already be updated properly.
let link = self.links.iter().find(|&link| *link.href == **dest);
@@ -370,7 +370,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> {
dest,
_,
))) => {
- debug!("saw end of shortcut link to {}", dest);
+ debug!("saw end of shortcut link to {dest}");
if self.links.iter().any(|link| *link.href == **dest) {
assert!(self.shortcut_link.is_some(), "saw closing link without opening tag");
self.shortcut_link = None;
@@ -379,7 +379,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> {
// Handle backticks in inline code blocks, but only if we're in the middle of a shortcut link.
// [`fn@f`]
Some(Event::Code(text)) => {
- trace!("saw code {}", text);
+ trace!("saw code {text}");
if let Some(link) = self.shortcut_link {
// NOTE: this only replaces if the code block is the *entire* text.
// If only part of the link has code highlighting, the disambiguator will not be removed.
@@ -394,7 +394,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> {
l.href == link.href
&& Some(&**text) == l.original_text.get(1..l.original_text.len() - 1)
}) {
- debug!("replacing {} with {}", text, link.new_text);
+ debug!("replacing {text} with {new_text}", new_text = link.new_text);
*text = CowStr::Borrowed(&link.new_text);
}
}
@@ -402,7 +402,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> {
// Replace plain text in links, but only in the middle of a shortcut link.
// [fn@f]
Some(Event::Text(text)) => {
- trace!("saw text {}", text);
+ trace!("saw text {text}");
if let Some(link) = self.shortcut_link {
// NOTE: same limitations as `Event::Code`
if let Some(link) = self
@@ -410,7 +410,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> {
.iter()
.find(|l| l.href == link.href && **text == *l.original_text)
{
- debug!("replacing {} with {}", text, link.new_text);
+ debug!("replacing {text} with {new_text}", new_text = link.new_text);
*text = CowStr::Borrowed(&link.new_text);
}
}
@@ -522,18 +522,16 @@ impl<'a, 'b, 'ids, I: Iterator<Item = SpannedEvent<'a>>> Iterator
let mut html_header = String::new();
html::push_html(&mut html_header, self.buf.iter().map(|(ev, _)| ev.clone()));
let sec = builder.push(level as u32, html_header, id.clone());
- self.buf.push_front((Event::Html(format!("{} ", sec).into()), 0..0));
+ self.buf.push_front((Event::Html(format!("{sec} ").into()), 0..0));
}
let level =
std::cmp::min(level as u32 + (self.heading_offset as u32), MAX_HEADER_LEVEL);
- self.buf.push_back((Event::Html(format!("</a></h{}>", level).into()), 0..0));
+ self.buf.push_back((Event::Html(format!("</a></h{level}>").into()), 0..0));
let start_tags = format!(
"<h{level} id=\"{id}\">\
<a href=\"#{id}\">",
- id = id,
- level = level
);
return Some((Event::Html(start_tags.into()), 0..0));
}
@@ -683,14 +681,14 @@ impl<'a, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, I> {
v.sort_by(|a, b| a.1.cmp(&b.1));
let mut ret = String::from("<div class=\"footnotes\"><hr><ol>");
for (mut content, id) in v {
- write!(ret, "<li id=\"fn{}\">", id).unwrap();
+ write!(ret, "<li id=\"fn{id}\">").unwrap();
let mut is_paragraph = false;
if let Some(&Event::End(Tag::Paragraph)) = content.last() {
content.pop();
is_paragraph = true;
}
html::push_html(&mut ret, content.into_iter());
- write!(ret, "&nbsp;<a href=\"#fnref{}\">↩</a>", id).unwrap();
+ write!(ret, "&nbsp;<a href=\"#fnref{id}\">↩</a>").unwrap();
if is_paragraph {
ret.push_str("</p>");
}
@@ -961,7 +959,7 @@ impl LangString {
} {
if let Some(extra) = extra {
extra.error_invalid_codeblock_attr(
- format!("unknown attribute `{}`. Did you mean `{}`?", x, flag),
+ format!("unknown attribute `{x}`. Did you mean `{flag}`?"),
help,
);
}
@@ -1040,7 +1038,7 @@ impl MarkdownWithToc<'_> {
html::push_html(&mut s, p);
}
- format!("<nav id=\"TOC\">{}</nav>{}", toc.into_toc().print(), s)
+ format!("<nav id=\"TOC\">{toc}</nav>{s}", toc = toc.into_toc().print())
}
}
@@ -1242,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,
}
@@ -1265,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() {
@@ -1377,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']')
- }
- 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)
+ .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::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)]
diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs
index e05635a02..db8504d15 100644
--- a/src/librustdoc/html/markdown/tests.rs
+++ b/src/librustdoc/html/markdown/tests.rs
@@ -38,7 +38,7 @@ fn test_unique_id() {
];
let mut map = IdMap::new();
- let actual: Vec<String> = input.iter().map(|s| map.derive(s.to_string())).collect();
+ let actual: Vec<String> = input.iter().map(|s| map.derive(s)).collect();
assert_eq!(&actual[..], expected);
}
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 4c4762636..d7ff248a9 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -162,7 +162,7 @@ impl<'tcx> Context<'tcx> {
self.shared.tcx.sess
}
- pub(super) fn derive_id(&mut self, id: String) -> String {
+ pub(super) fn derive_id<S: AsRef<str> + ToString>(&mut self, id: S) -> String {
self.id_map.derive(id)
}
@@ -206,15 +206,14 @@ impl<'tcx> Context<'tcx> {
format!("API documentation for the Rust `{}` crate.", self.shared.layout.krate)
} else {
format!(
- "API documentation for the Rust `{}` {} in crate `{}`.",
- it.name.as_ref().unwrap(),
- tyname,
- self.shared.layout.krate
+ "API documentation for the Rust `{name}` {tyname} in crate `{krate}`.",
+ name = it.name.as_ref().unwrap(),
+ krate = self.shared.layout.krate,
)
};
let name;
let tyname_s = if it.is_crate() {
- name = format!("{} crate", tyname);
+ name = format!("{tyname} crate");
name.as_str()
} else {
tyname.as_str()
@@ -264,7 +263,12 @@ impl<'tcx> Context<'tcx> {
current_path.push_str(&item_path(ty, names.last().unwrap().as_str()));
redirections.borrow_mut().insert(current_path, path);
}
- None => return layout::redirect(&format!("{}{}", self.root_path(), path)),
+ None => {
+ return layout::redirect(&format!(
+ "{root}{path}",
+ root = self.root_path()
+ ));
+ }
}
}
}
@@ -382,11 +386,7 @@ impl<'tcx> Context<'tcx> {
let hiline = span.hi(self.sess()).line;
format!(
"#{}",
- if loline == hiline {
- loline.to_string()
- } else {
- format!("{}-{}", loline, hiline)
- }
+ if loline == hiline { loline.to_string() } else { format!("{loline}-{hiline}") }
)
} else {
"".to_string()
@@ -798,15 +798,18 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
if let Some(def_id) = item.def_id() && self.cache().inlined_items.contains(&def_id) {
self.is_inside_inlined_module = true;
}
- } else if item.is_doc_hidden() {
+ } else if !self.cache().document_hidden && item.is_doc_hidden() {
// We're not inside an inlined module anymore since this one cannot be re-exported.
self.is_inside_inlined_module = false;
}
// Render sidebar-items.js used throughout this module.
if !self.render_redirect_pages {
- let (clean::StrippedItem(box clean::ModuleItem(ref module)) | clean::ModuleItem(ref module)) = *item.kind
- else { unreachable!() };
+ let (clean::StrippedItem(box clean::ModuleItem(ref module))
+ | clean::ModuleItem(ref module)) = *item.kind
+ else {
+ unreachable!()
+ };
let items = self.build_sidebar_items(module);
let js_dst = self.dst.join(&format!("sidebar-items{}.js", self.shared.resource_suffix));
let v = format!("window.SIDEBAR_ITEMS = {};", serde_json::to_string(&items).unwrap());
@@ -852,12 +855,12 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
// If the item is a macro, redirect from the old macro URL (with !)
// to the new one (without).
if item_type == ItemType::Macro {
- let redir_name = format!("{}.{}!.html", item_type, name);
+ let redir_name = format!("{item_type}.{name}!.html");
if let Some(ref redirections) = self.shared.redirections {
let crate_name = &self.shared.layout.krate;
redirections.borrow_mut().insert(
- format!("{}/{}", crate_name, redir_name),
- format!("{}/{}", crate_name, file_name),
+ format!("{crate_name}/{redir_name}"),
+ format!("{crate_name}/{file_name}"),
);
} else {
let v = layout::redirect(file_name);
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index f923f9054..ac9c180a6 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -85,7 +85,7 @@ use crate::DOC_RUST_LANG_ORG_CHANNEL;
pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ {
crate::html::format::display_fn(move |f| {
- if !v.ends_with('/') && !v.is_empty() { write!(f, "{}/", v) } else { f.write_str(v) }
+ if !v.ends_with('/') && !v.is_empty() { write!(f, "{v}/") } else { f.write_str(v) }
})
}
@@ -268,7 +268,7 @@ impl AllTypes {
fn append(&mut self, item_name: String, item_type: &ItemType) {
let mut url: Vec<_> = item_name.split("::").skip(1).collect();
if let Some(name) = url.pop() {
- let new_url = format!("{}/{}.{}.html", url.join("/"), item_type, name);
+ let new_url = format!("{}/{item_type}.{name}.html", url.join("/"));
url.push(name);
let name = url.join("::");
match *item_type {
@@ -385,16 +385,17 @@ impl AllTypes {
fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
let mut content = SCRAPE_EXAMPLES_HELP_MD.to_owned();
content.push_str(&format!(
- "## More information\n\n\
- If you want more information about this feature, please read the [corresponding chapter in the Rustdoc book]({}/rustdoc/scraped-examples.html).",
- DOC_RUST_LANG_ORG_CHANNEL));
+ "## More information\n\n\
+ If you want more information about this feature, please read the [corresponding chapter in \
+ the Rustdoc book]({DOC_RUST_LANG_ORG_CHANNEL}/rustdoc/scraped-examples.html)."
+ ));
let mut ids = IdMap::default();
format!(
"<div class=\"main-heading\">\
- <h1>About scraped examples</h1>\
- </div>\
- <div>{}</div>",
+ <h1>About scraped examples</h1>\
+ </div>\
+ <div>{}</div>",
Markdown {
content: &content,
links: &[],
@@ -415,7 +416,7 @@ fn document<'a, 'cx: 'a>(
heading_offset: HeadingOffset,
) -> impl fmt::Display + 'a + Captures<'cx> {
if let Some(ref name) = item.name {
- info!("Documenting {}", name);
+ info!("Documenting {name}");
}
display_fn(move |f| {
@@ -473,7 +474,7 @@ fn document_short<'a, 'cx: 'a>(
MarkdownSummaryLine(&s, &item.links(cx)).into_string_with_has_more_content();
if has_more_content {
- let link = format!(r#" <a{}>Read more</a>"#, assoc_href_attr(item, link, cx));
+ let link = format!(" <a{}>Read more</a>", assoc_href_attr(item, link, cx));
if let Some(idx) = summary_html.rfind("</p>") {
summary_html.insert_str(idx, &link);
@@ -482,7 +483,7 @@ fn document_short<'a, 'cx: 'a>(
}
}
- write!(f, "<div class='docblock'>{}</div>", summary_html)?;
+ write!(f, "<div class='docblock'>{summary_html}</div>")?;
}
Ok(())
})
@@ -512,14 +513,14 @@ fn document_full_inner<'a, 'cx: 'a>(
) -> impl fmt::Display + 'a + Captures<'cx> {
display_fn(move |f| {
if let Some(s) = item.opt_doc_value() {
- debug!("Doc block: =====\n{}\n=====", s);
+ debug!("Doc block: =====\n{s}\n=====");
if is_collapsible {
write!(
f,
"<details class=\"toggle top-doc\" open>\
- <summary class=\"hideme\">\
+ <summary class=\"hideme\">\
<span>Expand description</span>\
- </summary>{}</details>",
+ </summary>{}</details>",
render_markdown(cx, &s, item.links(cx), heading_offset)
)?;
} else {
@@ -564,12 +565,10 @@ fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option<Strin
};
debug!(
- "Portability {:?} {:?} (parent: {:?}) - {:?} = {:?}",
- item.name,
- item.cfg,
- parent,
- parent.and_then(|p| p.cfg.as_ref()),
- cfg
+ "Portability {name:?} {item_cfg:?} (parent: {parent:?}) - {parent_cfg:?} = {cfg:?}",
+ name = item.name,
+ item_cfg = item.cfg,
+ parent_cfg = parent.and_then(|p| p.cfg.as_ref()),
);
Some(cfg?.render_long_html())
@@ -701,8 +700,8 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
let item_type = it.type_();
let href = match link {
- AssocItemLink::Anchor(Some(ref id)) => Some(format!("#{}", id)),
- AssocItemLink::Anchor(None) => Some(format!("#{}.{}", item_type, name)),
+ AssocItemLink::Anchor(Some(ref id)) => Some(format!("#{id}")),
+ AssocItemLink::Anchor(None) => Some(format!("#{item_type}.{name}")),
AssocItemLink::GotoSource(did, provided_methods) => {
// We're creating a link from the implementation of an associated item to its
// declaration in the trait declaration.
@@ -722,7 +721,7 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
};
match href(did.expect_def_id(), cx) {
- Ok((url, ..)) => Some(format!("{}#{}.{}", url, item_type, name)),
+ Ok((url, ..)) => Some(format!("{url}#{item_type}.{name}")),
// The link is broken since it points to an external crate that wasn't documented.
// Do not create any link in such case. This is better than falling back to a
// dummy anchor like `#{item_type}.{name}` representing the `id` of *this* impl item
@@ -735,37 +734,39 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
// In this scenario, the actual `id` of this impl item would be
// `#{item_type}.{name}-{n}` for some number `n` (a disambiguator).
Err(HrefError::DocumentationNotBuilt) => None,
- Err(_) => Some(format!("#{}.{}", item_type, name)),
+ Err(_) => Some(format!("#{item_type}.{name}")),
}
}
};
// If there is no `href` for the reason explained above, simply do not render it which is valid:
// https://html.spec.whatwg.org/multipage/links.html#links-created-by-a-and-area-elements
- href.map(|href| format!(" href=\"{}\"", href)).unwrap_or_default()
+ href.map(|href| format!(" href=\"{href}\"")).unwrap_or_default()
}
fn assoc_const(
w: &mut Buffer,
it: &clean::Item,
+ generics: &clean::Generics,
ty: &clean::Type,
default: Option<&clean::ConstantKind>,
link: AssocItemLink<'_>,
- extra: &str,
+ indent: usize,
cx: &Context<'_>,
) {
let tcx = cx.tcx();
write!(
w,
- "{extra}{vis}const <a{href} class=\"constant\">{name}</a>: {ty}",
- extra = extra,
+ "{indent}{vis}const <a{href} class=\"constant\">{name}</a>{generics}: {ty}",
+ indent = " ".repeat(indent),
vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
href = assoc_href_attr(it, link, cx),
name = it.name.as_ref().unwrap(),
+ generics = generics.print(cx),
ty = ty.print(cx),
);
if let Some(default) = default {
- write!(w, " = ");
+ w.write_str(" = ");
// FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the
// hood which adds noisy underscores and a type suffix to number literals.
@@ -774,6 +775,7 @@ fn assoc_const(
// Find a way to print constants here without all that jazz.
write!(w, "{}", Escape(&default.value(tcx).unwrap_or_else(|| default.expr(tcx))));
}
+ write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline));
}
fn assoc_type(
@@ -820,6 +822,7 @@ fn assoc_method(
let header = meth.fn_header(tcx).expect("Trying to get header from a non-function item");
let name = meth.name.as_ref().unwrap();
let vis = visibility_print_with_space(meth.visibility(tcx), meth.item_id, cx).to_string();
+ let defaultness = print_default_space(meth.is_default());
// FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
// this condition.
let constness = match render_mode {
@@ -830,7 +833,6 @@ fn assoc_method(
};
let asyncness = header.asyncness.print_with_space();
let unsafety = header.unsafety.print_with_space();
- let defaultness = print_default_space(meth.is_default());
let abi = print_abi_with_space(header.abi).to_string();
let href = assoc_href_attr(meth, link, cx);
@@ -838,10 +840,10 @@ fn assoc_method(
let generics_len = format!("{:#}", g.print(cx)).len();
let mut header_len = "fn ".len()
+ vis.len()
+ + defaultness.len()
+ constness.len()
+ asyncness.len()
+ unsafety.len()
- + defaultness.len()
+ abi.len()
+ name.as_str().len()
+ generics_len;
@@ -860,14 +862,14 @@ fn assoc_method(
w.reserve(header_len + "<a href=\"\" class=\"fn\">{".len() + "</a>".len());
write!(
w,
- "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn \
+ "{indent}{vis}{defaultness}{constness}{asyncness}{unsafety}{abi}fn \
<a{href} class=\"fn\">{name}</a>{generics}{decl}{notable_traits}{where_clause}",
indent = indent_str,
vis = vis,
+ defaultness = defaultness,
constness = constness,
asyncness = asyncness,
unsafety = unsafety,
- defaultness = defaultness,
abi = abi,
href = href,
name = name,
@@ -907,39 +909,41 @@ fn render_stability_since_raw_with_extra(
if let Some(ver) = stable_version {
stability.push_str(ver.as_str());
- title.push_str(&format!("Stable since Rust version {}", ver));
+ title.push_str(&format!("Stable since Rust version {ver}"));
}
let const_title_and_stability = match const_stability {
Some(ConstStability { level: StabilityLevel::Stable { since, .. }, .. })
if Some(since) != containing_const_ver =>
{
- Some((format!("const since {}", since), format!("const: {}", since)))
+ Some((format!("const since {since}"), format!("const: {since}")))
}
Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }) => {
let unstable = if let Some(n) = issue {
format!(
- r#"<a href="https://github.com/rust-lang/rust/issues/{}" title="Tracking issue for {}">unstable</a>"#,
- n, feature
+ "<a \
+ href=\"https://github.com/rust-lang/rust/issues/{n}\" \
+ title=\"Tracking issue for {feature}\"\
+ >unstable</a>"
)
} else {
String::from("unstable")
};
- Some((String::from("const unstable"), format!("const: {}", unstable)))
+ Some((String::from("const unstable"), format!("const: {unstable}")))
}
_ => None,
};
if let Some((const_title, const_stability)) = const_title_and_stability {
if !title.is_empty() {
- title.push_str(&format!(", {}", const_title));
+ title.push_str(&format!(", {const_title}"));
} else {
title.push_str(&const_title);
}
if !stability.is_empty() {
- stability.push_str(&format!(" ({})", const_stability));
+ stability.push_str(&format!(" ({const_stability})"));
} else {
stability.push_str(&const_stability);
}
@@ -986,19 +990,22 @@ fn render_assoc_item(
clean::MethodItem(m, _) => {
assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode)
}
- kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => assoc_const(
- w,
- item,
- ty,
- match kind {
- clean::TyAssocConstItem(_) => None,
- clean::AssocConstItem(_, default) => Some(default),
- _ => unreachable!(),
- },
- link,
- if parent == ItemType::Trait { " " } else { "" },
- cx,
- ),
+ kind @ (clean::TyAssocConstItem(generics, ty) | clean::AssocConstItem(generics, ty, _)) => {
+ assoc_const(
+ w,
+ item,
+ generics,
+ ty,
+ match kind {
+ clean::TyAssocConstItem(..) => None,
+ clean::AssocConstItem(.., default) => Some(default),
+ _ => unreachable!(),
+ },
+ link,
+ if parent == ItemType::Trait { 4 } else { 0 },
+ cx,
+ )
+ }
clean::TyAssocTypeItem(ref generics, ref bounds) => assoc_type(
w,
item,
@@ -1032,7 +1039,7 @@ fn render_attributes_in_pre<'a, 'b: 'a>(
) -> impl fmt::Display + Captures<'a> + Captures<'b> {
crate::html::format::display_fn(move |f| {
for a in it.attributes(tcx, false) {
- writeln!(f, "{}{}", prefix, a)?;
+ writeln!(f, "{prefix}{a}")?;
}
Ok(())
})
@@ -1085,7 +1092,7 @@ pub(crate) fn render_all_impls(
let impls = impls.into_inner();
if !impls.is_empty() {
write_impl_section_heading(&mut w, "Trait Implementations", "trait-implementations");
- write!(w, "<div id=\"trait-implementations-list\">{}</div>", impls).unwrap();
+ write!(w, "<div id=\"trait-implementations-list\">{impls}</div>").unwrap();
}
if !synthetic.is_empty() {
@@ -1144,9 +1151,7 @@ fn render_assoc_items_inner(
AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
let id =
cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx))));
- if let Some(def_id) = type_.def_id(cx.cache()) {
- cx.deref_id_map.insert(def_id, id.clone());
- }
+ let derived_id = cx.derive_id(&id);
write_impl_section_heading(
&mut tmp_buf,
&format!(
@@ -1156,11 +1161,10 @@ fn render_assoc_items_inner(
),
&id,
);
- (
- RenderMode::ForDeref { mut_: deref_mut_ },
- cx.derive_id(id),
- r#" class="impl-items""#,
- )
+ if let Some(def_id) = type_.def_id(cx.cache()) {
+ cx.deref_id_map.insert(def_id, id);
+ }
+ (RenderMode::ForDeref { mut_: deref_mut_ }, derived_id, r#" class="impl-items""#)
}
};
let mut impls_buf = Buffer::html();
@@ -1183,10 +1187,13 @@ fn render_assoc_items_inner(
);
}
if !impls_buf.is_empty() {
- write!(w, "{}", tmp_buf.into_inner()).unwrap();
- write!(w, "<div id=\"{id}\"{class_html}>").unwrap();
- write!(w, "{}", impls_buf.into_inner()).unwrap();
- w.write_str("</div>").unwrap();
+ write!(
+ w,
+ "{}<div id=\"{id}\"{class_html}>{}</div>",
+ tmp_buf.into_inner(),
+ impls_buf.into_inner()
+ )
+ .unwrap();
}
}
@@ -1236,7 +1243,10 @@ fn render_deref_methods(
_ => None,
})
.expect("Expected associated type binding");
- debug!("Render deref methods for {:#?}, target {:#?}", impl_.inner_impl().for_, target);
+ debug!(
+ "Render deref methods for {for_:#?}, target {target:#?}",
+ for_ = impl_.inner_impl().for_
+ );
let what =
AssocItemRender::DerefFor { trait_: deref_type, type_: real_target, deref_mut_: deref_mut };
if let Some(did) = target.def_id(cache) {
@@ -1386,7 +1396,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
}
}
if out.is_empty() {
- write!(&mut out, "</code></pre>",);
+ out.write_str("</code></pre>");
}
(format!("{:#}", ty.print(cx)), out.into_inner())
@@ -1532,25 +1542,25 @@ fn render_impl(
let toggled = !doc_buffer.is_empty();
if toggled {
let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
- write!(w, "<details class=\"toggle{}\" open><summary>", method_toggle_class);
+ write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>");
}
match &*item.kind {
clean::MethodItem(..) | clean::TyMethodItem(_) => {
// Only render when the method is not static or we allow static methods
if render_method_item {
- let id = cx.derive_id(format!("{}.{}", item_type, name));
+ let id = cx.derive_id(format!("{item_type}.{name}"));
let source_id = trait_
.and_then(|trait_| {
trait_.items.iter().find(|item| {
item.name.map(|n| n.as_str().eq(name.as_str())).unwrap_or(false)
})
})
- .map(|item| format!("{}.{}", item.type_(), name));
- write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
+ .map(|item| format!("{}.{name}", item.type_()));
+ write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
render_rightside(w, cx, item, containing_item, render_mode);
if trait_.is_some() {
// Anchors are only used on trait impls.
- write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
+ write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>");
}
w.write_str("<h4 class=\"code-header\">");
render_assoc_item(
@@ -1561,43 +1571,43 @@ fn render_impl(
cx,
render_mode,
);
- w.write_str("</h4>");
- w.write_str("</section>");
+ w.write_str("</h4></section>");
}
}
- kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => {
- let source_id = format!("{}.{}", item_type, name);
- let id = cx.derive_id(source_id.clone());
- write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
+ kind @ (clean::TyAssocConstItem(generics, ty)
+ | clean::AssocConstItem(generics, ty, _)) => {
+ let source_id = format!("{item_type}.{name}");
+ let id = cx.derive_id(&source_id);
+ write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
render_rightside(w, cx, item, containing_item, render_mode);
if trait_.is_some() {
// Anchors are only used on trait impls.
- write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
+ write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>");
}
w.write_str("<h4 class=\"code-header\">");
assoc_const(
w,
item,
+ generics,
ty,
match kind {
- clean::TyAssocConstItem(_) => None,
- clean::AssocConstItem(_, default) => Some(default),
+ clean::TyAssocConstItem(..) => None,
+ clean::AssocConstItem(.., default) => Some(default),
_ => unreachable!(),
},
link.anchor(if trait_.is_some() { &source_id } else { &id }),
- "",
+ 0,
cx,
);
- w.write_str("</h4>");
- w.write_str("</section>");
+ w.write_str("</h4></section>");
}
clean::TyAssocTypeItem(generics, bounds) => {
- let source_id = format!("{}.{}", item_type, name);
- let id = cx.derive_id(source_id.clone());
- write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
+ let source_id = format!("{item_type}.{name}");
+ let id = cx.derive_id(&source_id);
+ write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
if trait_.is_some() {
// Anchors are only used on trait impls.
- write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
+ write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>");
}
w.write_str("<h4 class=\"code-header\">");
assoc_type(
@@ -1610,16 +1620,15 @@ fn render_impl(
0,
cx,
);
- w.write_str("</h4>");
- w.write_str("</section>");
+ w.write_str("</h4></section>");
}
clean::AssocTypeItem(tydef, _bounds) => {
- let source_id = format!("{}.{}", item_type, name);
- let id = cx.derive_id(source_id.clone());
- write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
+ let source_id = format!("{item_type}.{name}");
+ let id = cx.derive_id(&source_id);
+ write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
if trait_.is_some() {
// Anchors are only used on trait impls.
- write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
+ write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>");
}
w.write_str("<h4 class=\"code-header\">");
assoc_type(
@@ -1632,8 +1641,7 @@ fn render_impl(
0,
cx,
);
- w.write_str("</h4>");
- w.write_str("</section>");
+ w.write_str("</h4></section>");
}
clean::StrippedItem(..) => return,
_ => panic!("can't make docs for trait item with name {:?}", item.name),
@@ -1678,11 +1686,11 @@ fn render_impl(
rendering_params: ImplRenderingParameters,
) {
for trait_item in &t.items {
- // Skip over any default trait items that are impossible to call
+ // Skip over any default trait items that are impossible to reference
// (e.g. if it has a `Self: Sized` bound on an unsized type).
if let Some(impl_def_id) = parent.item_id.as_def_id()
&& let Some(trait_item_def_id) = trait_item.item_id.as_def_id()
- && cx.tcx().is_impossible_method((impl_def_id, trait_item_def_id))
+ && cx.tcx().is_impossible_associated_item((impl_def_id, trait_item_def_id))
{
continue;
}
@@ -1736,10 +1744,10 @@ fn render_impl(
close_tags.insert_str(0, "</details>");
write!(
w,
- "<details class=\"toggle implementors-toggle\"{}>",
+ "<details class=\"toggle implementors-toggle\"{}>\
+ <summary>",
if rendering_params.toggle_open_by_default { " open" } else { "" }
);
- write!(w, "<summary>")
}
render_impl_summary(
w,
@@ -1752,15 +1760,15 @@ fn render_impl(
aliases,
);
if toggled {
- write!(w, "</summary>")
+ w.write_str("</summary>");
}
if let Some(ref dox) = i.impl_item.opt_doc_value() {
if trait_.is_none() && i.inner_impl().items.is_empty() {
w.write_str(
"<div class=\"item-info\">\
- <div class=\"stab empty-impl\">This impl block contains no items.</div>\
- </div>",
+ <div class=\"stab empty-impl\">This impl block contains no items.</div>\
+ </div>",
);
}
write!(
@@ -1819,11 +1827,11 @@ fn render_rightside(
const_stable_since,
if has_src_ref { "" } else { " rightside" },
);
- if let Some(l) = src_href {
+ if let Some(link) = src_href {
if has_stability {
- write!(rightside, " · <a class=\"srclink\" href=\"{}\">source</a>", l)
+ write!(rightside, " · <a class=\"src\" href=\"{link}\">source</a>")
} else {
- write!(rightside, "<a class=\"srclink rightside\" href=\"{}\">source</a>", l)
+ write!(rightside, "<a class=\"src rightside\" href=\"{link}\">source</a>")
}
}
if has_stability && has_src_ref {
@@ -1852,10 +1860,13 @@ pub(crate) fn render_impl_summary(
} else {
format!(" data-aliases=\"{}\"", aliases.join(","))
};
- write!(w, "<section id=\"{}\" class=\"impl\"{}>", id, aliases);
+ write!(w, "<section id=\"{id}\" class=\"impl\"{aliases}>");
render_rightside(w, cx, &i.impl_item, containing_item, RenderMode::Normal);
- write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
- write!(w, "<h3 class=\"code-header\">");
+ write!(
+ w,
+ "<a href=\"#{id}\" class=\"anchor\">§</a>\
+ <h3 class=\"code-header\">"
+ );
if let Some(use_absolute) = use_absolute {
write!(w, "{}", inner_impl.print(use_absolute, cx));
@@ -1880,15 +1891,16 @@ pub(crate) fn render_impl_summary(
} else {
write!(w, "{}", inner_impl.print(false, cx));
}
- write!(w, "</h3>");
+ w.write_str("</h3>");
let is_trait = inner_impl.trait_.is_some();
if is_trait {
if let Some(portability) = portability(&i.impl_item, Some(parent)) {
write!(
w,
- "<span class=\"item-info\"><div class=\"stab portability\">{}</div></span>",
- portability
+ "<span class=\"item-info\">\
+ <div class=\"stab portability\">{portability}</div>\
+ </span>",
);
}
}
@@ -1941,7 +1953,7 @@ pub(crate) fn small_url_encode(s: String) -> String {
// consistent with itself when encoding them.
st += "+";
} else {
- write!(st, "%{:02X}", b).unwrap();
+ write!(st, "%{b:02X}").unwrap();
}
// Invariant: if the current byte is not at the start of a multi-byte character,
// we need to get down here so that when the next turn of the loop comes around,
@@ -1988,7 +2000,9 @@ pub(crate) fn get_filtered_impls_for_reference<'a>(
) -> (Vec<&'a Impl>, Vec<&'a Impl>, Vec<&'a Impl>) {
let def_id = it.item_id.expect_def_id();
// If the reference primitive is somehow not defined, exit early.
- let Some(v) = shared.cache.impls.get(&def_id) else { return (Vec::new(), Vec::new(), Vec::new()) };
+ let Some(v) = shared.cache.impls.get(&def_id) else {
+ return (Vec::new(), Vec::new(), Vec::new());
+ };
// Since there is no "direct implementation" on the reference primitive type, we filter out
// every implementation which isn't a trait implementation.
let traits = v.iter().filter(|i| i.inner_impl().trait_.is_some());
@@ -2254,7 +2268,7 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &mut Context<'_>, item: &c
format!("lines {}-{}", line_lo + 1, line_hi + 1),
)
};
- let url = format!("{}{}#{}", cx.root_path(), call_data.url, anchor);
+ let url = format!("{}{}#{anchor}", cx.root_path(), call_data.url);
(url, title)
};
@@ -2264,7 +2278,7 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &mut Context<'_>, item: &c
Ok(contents) => contents,
Err(err) => {
let span = item.span(tcx).map_or(rustc_span::DUMMY_SP, |span| span.inner());
- tcx.sess.span_err(span, format!("failed to read file {}: {}", path.display(), err));
+ tcx.sess.span_err(span, format!("failed to read file {}: {err}", path.display()));
return false;
}
};
@@ -2323,7 +2337,7 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &mut Context<'_>, item: &c
.unwrap();
if line_ranges.len() > 1 {
- write!(w, r#"<button class="prev">&pr;</button> <button class="next">&sc;</button>"#)
+ w.write_str(r#"<button class="prev">&pr;</button> <button class="next">&sc;</button>"#)
.unwrap();
}
@@ -2359,7 +2373,7 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &mut Context<'_>, item: &c
highlight::DecorationInfo(decoration_info),
sources::SourceContext::Embedded { offset: line_min, needs_expansion },
);
- write!(w, "</div></div>").unwrap();
+ w.write_str("</div></div>").unwrap();
true
};
@@ -2426,8 +2440,10 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &mut Context<'_>, item: &c
// For the remaining examples, generate a <ul> containing links to the source files.
if it.peek().is_some() {
- write!(w, r#"<div class="example-links">Additional examples can be found in:<br><ul>"#)
- .unwrap();
+ w.write_str(
+ r#"<div class="example-links">Additional examples can be found in:<br><ul>"#,
+ )
+ .unwrap();
it.for_each(|(_, call_data)| {
let (url, _) = link_to_loc(call_data, &call_data.locations[0]);
write!(
@@ -2438,11 +2454,11 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &mut Context<'_>, item: &c
)
.unwrap();
});
- write!(w, "</ul></div>").unwrap();
+ w.write_str("</ul></div>").unwrap();
}
- write!(w, "</div></details>").unwrap();
+ w.write_str("</div></details>").unwrap();
}
- write!(w, "</div>").unwrap();
+ w.write_str("</div>").unwrap();
}
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 383e3c170..6cab34986 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -310,9 +310,8 @@ fn toggle_open(mut w: impl fmt::Write, text: impl fmt::Display) {
w,
"<details class=\"toggle type-contents-toggle\">\
<summary class=\"hideme\">\
- <span>Show {}</span>\
+ <span>Show {text}</span>\
</summary>",
- text
)
.unwrap();
}
@@ -412,7 +411,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
)
});
- debug!("{:?}", indices);
+ debug!("{indices:?}");
let mut last_section = None;
for &idx in &indices {
@@ -431,9 +430,8 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
w,
"<h2 id=\"{id}\" class=\"small-section-header\">\
<a href=\"#{id}\">{name}</a>\
- </h2>{}",
- ITEM_TABLE_OPEN,
- id = cx.derive_id(my_section.id().to_owned()),
+ </h2>{ITEM_TABLE_OPEN}",
+ id = cx.derive_id(my_section.id()),
name = my_section.name(),
);
}
@@ -485,7 +483,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
w.write_str(ITEM_TABLE_ROW_OPEN);
let id = match import.kind {
clean::ImportKind::Simple(s) => {
- format!(" id=\"{}\"", cx.derive_id(format!("reexport.{}", s)))
+ format!(" id=\"{}\"", cx.derive_id(format!("reexport.{s}")))
}
clean::ImportKind::Glob => String::new(),
};
@@ -583,10 +581,8 @@ fn extra_info_tags<'a, 'tcx: 'a>(
display_fn(move |f| {
write!(
f,
- r#"<span class="stab {}" title="{}">{}</span>"#,
- class,
- Escape(title),
- contents
+ r#"<span class="stab {class}" title="{title}">{contents}</span>"#,
+ title = Escape(title),
)
})
}
@@ -614,7 +610,12 @@ fn extra_info_tags<'a, 'tcx: 'a>(
(cfg, _) => cfg.as_deref().cloned(),
};
- debug!("Portability name={:?} {:?} - {:?} = {:?}", item.name, item.cfg, parent.cfg, cfg);
+ debug!(
+ "Portability name={name:?} {cfg:?} - {parent_cfg:?} = {cfg:?}",
+ name = item.name,
+ cfg = item.cfg,
+ parent_cfg = parent.cfg
+ );
if let Some(ref cfg) = cfg {
write!(
f,
@@ -689,14 +690,13 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
wrap_item(w, |mut w| {
write!(
w,
- "{attrs}{}{}{}trait {}{}{}",
- visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
- t.unsafety(tcx).print_with_space(),
- if t.is_auto(tcx) { "auto " } else { "" },
- it.name.unwrap(),
- t.generics.print(cx),
- bounds,
+ "{attrs}{vis}{unsafety}{is_auto}trait {name}{generics}{bounds}",
attrs = render_attributes_in_pre(it, "", tcx),
+ vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
+ unsafety = t.unsafety(tcx).print_with_space(),
+ is_auto = if t.is_auto(tcx) { "auto " } else { "" },
+ name = it.name.unwrap(),
+ generics = t.generics.print(cx),
);
if !t.generics.where_predicates.is_empty() {
@@ -742,11 +742,10 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
toggle_open(
&mut w,
format_args!(
- "{} associated constant{} and {} method{}",
- count_consts,
- pluralize(count_consts),
- count_methods,
- pluralize(count_methods),
+ "{count_consts} associated constant{plural_const} and \
+ {count_methods} method{plural_method}",
+ plural_const = pluralize(count_consts),
+ plural_method = pluralize(count_methods),
),
);
}
@@ -768,7 +767,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
}
if !toggle && should_hide_fields(count_methods) {
toggle = true;
- toggle_open(&mut w, format_args!("{} methods", count_methods));
+ toggle_open(&mut w, format_args!("{count_methods} methods"));
}
if count_consts != 0 && count_methods != 0 {
w.write_str("\n");
@@ -837,9 +836,9 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
fn trait_item(w: &mut Buffer, cx: &mut Context<'_>, m: &clean::Item, t: &clean::Item) {
let name = m.name.unwrap();
- info!("Documenting {} on {:?}", name, t.name);
+ info!("Documenting {name} on {ty_name:?}", ty_name = t.name);
let item_type = m.type_();
- let id = cx.derive_id(format!("{}.{}", item_type, name));
+ let id = cx.derive_id(format!("{item_type}.{name}"));
let mut content = Buffer::empty_from(w);
write!(&mut content, "{}", document(cx, m, Some(t), HeadingOffset::H5));
let toggled = !content.is_empty();
@@ -847,7 +846,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>");
}
- write!(w, "<section id=\"{}\" class=\"method\">", id);
+ write!(w, "<section id=\"{id}\" class=\"method\">");
render_rightside(w, cx, m, t, RenderMode::Normal);
write!(w, "<h4 class=\"code-header\">");
render_assoc_item(
@@ -1170,12 +1169,12 @@ fn item_trait_alias(
wrap_item(w, |w| {
write!(
w,
- "{attrs}trait {}{}{} = {};",
- it.name.unwrap(),
- t.generics.print(cx),
- print_where_clause(&t.generics, cx, 0, Ending::Newline),
- bounds(&t.bounds, true, cx),
+ "{attrs}trait {name}{generics}{where_b} = {bounds};",
attrs = render_attributes_in_pre(it, "", cx.tcx()),
+ name = it.name.unwrap(),
+ generics = t.generics.print(cx),
+ where_b = print_where_clause(&t.generics, cx, 0, Ending::Newline),
+ bounds = bounds(&t.bounds, true, cx),
)
.unwrap();
});
@@ -1198,12 +1197,12 @@ fn item_opaque_ty(
wrap_item(w, |w| {
write!(
w,
- "{attrs}type {}{}{where_clause} = impl {bounds};",
- it.name.unwrap(),
- t.generics.print(cx),
+ "{attrs}type {name}{generics}{where_clause} = impl {bounds};",
+ attrs = render_attributes_in_pre(it, "", cx.tcx()),
+ name = it.name.unwrap(),
+ generics = t.generics.print(cx),
where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
bounds = bounds(&t.bounds, false, cx),
- attrs = render_attributes_in_pre(it, "", cx.tcx()),
)
.unwrap();
});
@@ -1223,13 +1222,13 @@ fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clea
wrap_item(w, |w| {
write!(
w,
- "{attrs}{}type {}{}{where_clause} = {type_};",
- visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
- it.name.unwrap(),
- t.generics.print(cx),
+ "{attrs}{vis}type {name}{generics}{where_clause} = {type_};",
+ attrs = render_attributes_in_pre(it, "", cx.tcx()),
+ vis = visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
+ name = it.name.unwrap(),
+ generics = t.generics.print(cx),
where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
type_ = t.type_.print(cx),
- attrs = render_attributes_in_pre(it, "", cx.tcx()),
);
});
}
@@ -1354,7 +1353,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
w.write_str("{\n");
let toggle = should_hide_fields(count_variants);
if toggle {
- toggle_open(&mut w, format_args!("{} variants", count_variants));
+ toggle_open(&mut w, format_args!("{count_variants} variants"));
}
for v in e.variants() {
w.write_str(" ");
@@ -1362,7 +1361,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
match *v.kind {
// FIXME(#101337): Show discriminant
clean::VariantItem(ref var) => match var.kind {
- clean::VariantKind::CLike => write!(w, "{}", name),
+ clean::VariantKind::CLike => w.write_str(name.as_str()),
clean::VariantKind::Tuple(ref s) => {
write!(w, "{name}({})", print_tuple_struct_fields(cx, s),);
}
@@ -1418,7 +1417,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() };
if let clean::VariantKind::Tuple(ref s) = variant_data.kind {
- write!(w, "({})", print_tuple_struct_fields(cx, s),);
+ write!(w, "({})", print_tuple_struct_fields(cx, s));
}
w.write_str("</h3></section>");
@@ -1543,10 +1542,12 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle
write!(
w,
- "{vis}const {name}: {typ}",
+ "{vis}const {name}{generics}: {typ}{where_clause}",
vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
name = it.name.unwrap(),
+ generics = c.generics.print(cx),
typ = c.type_.print(cx),
+ where_clause = print_where_clause(&c.generics, cx, 0, Ending::NoNewline),
);
// FIXME: The code below now prints
@@ -1615,7 +1616,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
for (index, (field, ty)) in fields.enumerate() {
let field_name =
field.name.map_or_else(|| index.to_string(), |sym| sym.as_str().to_string());
- let id = cx.derive_id(format!("{}.{}", ItemType::StructField, field_name));
+ let id = cx.derive_id(format!("{typ}.{field_name}", typ = ItemType::StructField));
write!(
w,
"<span id=\"{id}\" class=\"{item_type} small-section-header\">\
@@ -1720,7 +1721,7 @@ pub(super) fn full_path(cx: &Context<'_>, item: &clean::Item) -> String {
pub(super) fn item_path(ty: ItemType, name: &str) -> String {
match ty {
ItemType::Module => format!("{}index.html", ensure_trailing_slash(name)),
- _ => format!("{}.{}.html", ty, name),
+ _ => format!("{ty}.{name}.html"),
}
}
@@ -1843,7 +1844,7 @@ fn render_union<'a, 'cx: 'a>(
fields.iter().filter(|field| matches!(*field.kind, clean::StructFieldItem(..))).count();
let toggle = should_hide_fields(count_fields);
if toggle {
- toggle_open(&mut f, format_args!("{} fields", count_fields));
+ toggle_open(&mut f, format_args!("{count_fields} fields"));
}
for field in fields {
@@ -1906,26 +1907,25 @@ fn render_struct(
let has_visible_fields = count_fields > 0;
let toggle = should_hide_fields(count_fields);
if toggle {
- toggle_open(&mut w, format_args!("{} fields", count_fields));
+ toggle_open(&mut w, format_args!("{count_fields} fields"));
}
for field in fields {
if let clean::StructFieldItem(ref ty) = *field.kind {
write!(
w,
- "\n{} {}{}: {},",
- tab,
- visibility_print_with_space(field.visibility(tcx), field.item_id, cx),
- field.name.unwrap(),
- ty.print(cx),
+ "\n{tab} {vis}{name}: {ty},",
+ vis = visibility_print_with_space(field.visibility(tcx), field.item_id, cx),
+ name = field.name.unwrap(),
+ ty = ty.print(cx),
);
}
}
if has_visible_fields {
if it.has_stripped_entries().unwrap() {
- write!(w, "\n{} /* private fields */", tab);
+ write!(w, "\n{tab} /* private fields */");
}
- write!(w, "\n{}", tab);
+ write!(w, "\n{tab}");
} else if it.has_stripped_entries().unwrap() {
write!(w, " /* private fields */ ");
}
diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs
index 455b4e9ae..f3da61056 100644
--- a/src/librustdoc/html/render/sidebar.rs
+++ b/src/librustdoc/html/render/sidebar.rs
@@ -330,7 +330,7 @@ fn sidebar_deref_methods<'a>(
) {
let c = cx.cache();
- debug!("found Deref: {:?}", impl_);
+ debug!("found Deref: {impl_:?}");
if let Some((target, real_target)) =
impl_.inner_impl().items.iter().find_map(|item| match *item.kind {
clean::AssocTypeItem(box ref t, _) => Some(match *t {
@@ -340,7 +340,7 @@ fn sidebar_deref_methods<'a>(
_ => None,
})
{
- debug!("found target, real_target: {:?} {:?}", target, real_target);
+ debug!("found target, real_target: {target:?} {real_target:?}");
if let Some(did) = target.def_id(c) &&
let Some(type_did) = impl_.inner_impl().for_.def_id(c) &&
// `impl Deref<Target = S> for S`
@@ -357,7 +357,7 @@ fn sidebar_deref_methods<'a>(
})
.and_then(|did| c.impls.get(&did));
if let Some(impls) = inner_impl {
- debug!("found inner_impl: {:?}", impls);
+ debug!("found inner_impl: {impls:?}");
let mut ret = impls
.iter()
.filter(|i| i.inner_impl().trait_.is_none())
@@ -510,10 +510,10 @@ fn get_next_url(used_links: &mut FxHashSet<String>, url: String) -> String {
return url;
}
let mut add = 1;
- while !used_links.insert(format!("{}-{}", url, add)) {
+ while !used_links.insert(format!("{url}-{add}")) {
add += 1;
}
- format!("{}-{}", url, add)
+ format!("{url}-{add}")
}
fn get_methods<'a>(
@@ -529,7 +529,7 @@ fn get_methods<'a>(
Some(ref name) if !name.is_empty() && item.is_method() => {
if !for_deref || super::should_render_item(item, deref_mut, tcx) {
Some(Link::new(
- get_next_url(used_links, format!("{}.{}", ItemType::Method, name)),
+ get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::Method)),
name.as_str(),
))
} else {
@@ -549,7 +549,7 @@ fn get_associated_constants<'a>(
.iter()
.filter_map(|item| match item.name {
Some(ref name) if !name.is_empty() && item.is_associated_const() => Some(Link::new(
- get_next_url(used_links, format!("{}.{}", ItemType::AssocConst, name)),
+ get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::AssocConst)),
name.as_str(),
)),
_ => None,
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index eb9262f47..5f130f187 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -1,11 +1,11 @@
-use crate::clean::{self, PrimitiveType};
+use crate::clean::{self, rustc_span, PrimitiveType};
use crate::html::sources;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{ExprKind, HirId, Mod, Node};
+use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::TyCtxt;
use rustc_span::hygiene::MacroKind;
@@ -25,6 +25,7 @@ pub(crate) enum LinkFromSrc {
Local(clean::Span),
External(DefId),
Primitive(PrimitiveType),
+ Doc(DefId),
}
/// This function will do at most two things:
@@ -65,24 +66,43 @@ struct SpanMapVisitor<'tcx> {
impl<'tcx> SpanMapVisitor<'tcx> {
/// This function is where we handle `hir::Path` elements and add them into the "span map".
fn handle_path(&mut self, path: &rustc_hir::Path<'_>) {
- let info = match path.res {
+ match path.res {
// FIXME: For now, we handle `DefKind` if it's not a `DefKind::TyParam`.
// Would be nice to support them too alongside the other `DefKind`
// (such as primitive types!).
- Res::Def(kind, def_id) if kind != DefKind::TyParam => Some(def_id),
- Res::Local(_) => None,
+ Res::Def(kind, def_id) if kind != DefKind::TyParam => {
+ let link = if def_id.as_local().is_some() {
+ LinkFromSrc::Local(rustc_span(def_id, self.tcx))
+ } else {
+ LinkFromSrc::External(def_id)
+ };
+ self.matches.insert(path.span, link);
+ }
+ Res::Local(_) => {
+ if let Some(span) = self.tcx.hir().res_span(path.res) {
+ self.matches.insert(path.span, LinkFromSrc::Local(clean::Span::new(span)));
+ }
+ }
Res::PrimTy(p) => {
// FIXME: Doesn't handle "path-like" primitives like arrays or tuples.
self.matches.insert(path.span, LinkFromSrc::Primitive(PrimitiveType::from(p)));
- return;
}
- Res::Err => return,
- _ => return,
- };
- if let Some(span) = self.tcx.hir().res_span(path.res) {
- self.matches.insert(path.span, LinkFromSrc::Local(clean::Span::new(span)));
- } else if let Some(def_id) = info {
- self.matches.insert(path.span, LinkFromSrc::External(def_id));
+ Res::Err => {}
+ _ => {}
+ }
+ }
+
+ /// Used to generate links on items' definition to go to their documentation page.
+ pub(crate) fn extract_info_from_hir_id(&mut self, hir_id: HirId) {
+ if let Some(Node::Item(item)) = self.tcx.hir().find(hir_id) {
+ if let Some(span) = self.tcx.def_ident_span(item.owner_id) {
+ let cspan = clean::Span::new(span);
+ // If the span isn't from the current crate, we ignore it.
+ if cspan.inner().is_dummy() || cspan.cnum(self.tcx.sess) != LOCAL_CRATE {
+ return;
+ }
+ self.matches.insert(span, LinkFromSrc::Doc(item.owner_id.to_def_id()));
+ }
}
}
@@ -117,10 +137,13 @@ impl<'tcx> SpanMapVisitor<'tcx> {
_ => return true,
};
let link_from_src = match data.macro_def_id {
- Some(macro_def_id) if macro_def_id.is_local() => {
- LinkFromSrc::Local(clean::Span::new(data.def_site))
+ Some(macro_def_id) => {
+ if macro_def_id.is_local() {
+ LinkFromSrc::Local(clean::Span::new(data.def_site))
+ } else {
+ LinkFromSrc::External(macro_def_id)
+ }
}
- Some(macro_def_id) => LinkFromSrc::External(macro_def_id),
None => return true,
};
let new_span = data.call_site;
@@ -160,6 +183,9 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
LinkFromSrc::Local(clean::Span::new(m.spans.inner_span)),
);
}
+ } else {
+ // If it's a "mod foo {}", we want to look to its documentation page.
+ self.extract_info_from_hir_id(id);
}
intravisit::walk_mod(self, m, id);
}
@@ -176,13 +202,12 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
.tcx
.typeck_body(hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"));
if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
- self.matches.insert(
- segment.ident.span,
- match hir.span_if_local(def_id) {
- Some(span) => LinkFromSrc::Local(clean::Span::new(span)),
- None => LinkFromSrc::External(def_id),
- },
- );
+ let link = if def_id.as_local().is_some() {
+ LinkFromSrc::Local(rustc_span(def_id, self.tcx))
+ } else {
+ LinkFromSrc::External(def_id)
+ };
+ self.matches.insert(segment.ident.span, link);
}
} else if self.handle_macro(expr.span) {
// We don't want to go deeper into the macro.
@@ -190,4 +215,28 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
}
intravisit::walk_expr(self, expr);
}
+
+ fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
+ match item.kind {
+ ItemKind::Static(_, _, _)
+ | ItemKind::Const(_, _, _)
+ | ItemKind::Fn(_, _, _)
+ | ItemKind::Macro(_, _)
+ | ItemKind::TyAlias(_, _)
+ | ItemKind::Enum(_, _)
+ | ItemKind::Struct(_, _)
+ | ItemKind::Union(_, _)
+ | ItemKind::Trait(_, _, _, _, _)
+ | ItemKind::TraitAlias(_, _) => self.extract_info_from_hir_id(item.hir_id()),
+ ItemKind::Impl(_)
+ | ItemKind::Use(_, _)
+ | ItemKind::ExternCrate(_)
+ | ItemKind::ForeignMod { .. }
+ | ItemKind::GlobalAsm(_)
+ | ItemKind::OpaqueTy(_)
+ // We already have "visit_mod" above so no need to check it here.
+ | ItemKind::Mod(_) => {}
+ }
+ intravisit::walk_item(self, item);
+ }
}
diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs
index 0bc32ea5a..377daaeb9 100644
--- a/src/librustdoc/html/render/type_layout.rs
+++ b/src/librustdoc/html/render/type_layout.rs
@@ -39,7 +39,7 @@ pub(crate) fn document_type_layout<'a, 'cx: 'a>(
let tcx = cx.tcx();
let param_env = tcx.param_env(ty_def_id);
- let ty = tcx.type_of(ty_def_id).subst_identity();
+ let ty = tcx.type_of(ty_def_id).instantiate_identity();
let type_layout = tcx.layout_of(param_env.and(ty));
let variants =
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index 54749e9a3..e824651e7 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -73,7 +73,7 @@ pub(super) fn write_shared(
}
let bytes = try_err!(fs::read(&entry.path), &entry.path);
- let filename = format!("{}{}.{}", theme, cx.shared.resource_suffix, extension);
+ let filename = format!("{theme}{suffix}.{extension}", suffix = cx.shared.resource_suffix);
cx.shared.fs.write(cx.dst.join(filename), bytes)?;
}
@@ -112,7 +112,7 @@ pub(super) fn write_shared(
let mut krates = Vec::new();
if path.exists() {
- let prefix = format!("\"{}\"", krate);
+ let prefix = format!("\"{krate}\"");
for line in BufReader::new(File::open(path)?).lines() {
let line = line?;
if !line.starts_with('"') {
@@ -157,7 +157,7 @@ pub(super) fn write_shared(
let mut krates = Vec::new();
if path.exists() {
- let prefix = format!("\"{}\"", krate);
+ let prefix = format!("\"{krate}\"");
for line in BufReader::new(File::open(path)?).lines() {
let line = line?;
if !line.starts_with('"') {
@@ -213,10 +213,10 @@ pub(super) fn write_shared(
let dirs = if subs.is_empty() && files.is_empty() {
String::new()
} else {
- format!(",[{}]", subs)
+ format!(",[{subs}]")
};
let files = files.join(",");
- let files = if files.is_empty() { String::new() } else { format!(",[{}]", files) };
+ let files = if files.is_empty() { String::new() } else { format!(",[{files}]") };
format!(
"[\"{name}\"{dirs}{files}]",
name = self.elem.to_str().expect("invalid osstring conversion"),
@@ -270,7 +270,7 @@ pub(super) fn write_shared(
hierarchy.add_path(source);
}
let hierarchy = Rc::try_unwrap(hierarchy).unwrap();
- let dst = cx.dst.join(&format!("source-files{}.js", cx.shared.resource_suffix));
+ let dst = cx.dst.join(&format!("src-files{}.js", cx.shared.resource_suffix));
let make_sources = || {
let (mut all_sources, _krates) =
try_err!(collect_json(&dst, krate.name(cx.tcx()).as_str()), &dst);
@@ -286,12 +286,12 @@ pub(super) fn write_shared(
.replace("\\\"", "\\\\\"")
));
all_sources.sort();
- let mut v = String::from("var sourcesIndex = JSON.parse('{\\\n");
+ let mut v = String::from("var srcIndex = JSON.parse('{\\\n");
v.push_str(&all_sources.join(",\\\n"));
- v.push_str("\\\n}');\ncreateSourceSidebar();\n");
+ v.push_str("\\\n}');\ncreateSrcSidebar();\n");
Ok(v.into_bytes())
};
- write_invocation_specific("source-files.js", &make_sources)?;
+ write_invocation_specific("src-files.js", &make_sources)?;
}
// Update the search index and crate list.
@@ -319,8 +319,8 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex};
})?;
write_invocation_specific("crates.js", &|| {
- let krates = krates.iter().map(|k| format!("\"{}\"", k)).join(",");
- Ok(format!("window.ALL_CRATES = [{}];", krates).into_bytes())
+ let krates = krates.iter().map(|k| format!("\"{k}\"")).join(",");
+ Ok(format!("window.ALL_CRATES = [{krates}];").into_bytes())
})?;
if options.enable_index_page {
@@ -349,9 +349,8 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex};
.iter()
.map(|s| {
format!(
- "<li><a href=\"{}index.html\">{}</a></li>",
- ensure_trailing_slash(s),
- s
+ "<li><a href=\"{trailing_slash}index.html\">{s}</a></li>",
+ trailing_slash = ensure_trailing_slash(s),
)
})
.collect::<String>()
@@ -444,7 +443,7 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex};
mydst.push(part.to_string());
}
cx.shared.ensure_dir(&mydst)?;
- mydst.push(&format!("{}.{}.js", remote_item_type, remote_path[remote_path.len() - 1]));
+ mydst.push(&format!("{remote_item_type}.{}.js", remote_path[remote_path.len() - 1]));
let (mut all_implementors, _) =
try_err!(collect(&mydst, krate.name(cx.tcx()).as_str()), &mydst);
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index a26fa3749..c4a1ebbec 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -146,9 +146,8 @@ impl DocVisitor for SourceCollector<'_, '_> {
self.cx.shared.tcx.sess.span_err(
span,
format!(
- "failed to render source code for `{}`: {}",
- filename.prefer_local(),
- e,
+ "failed to render source code for `{filename}`: {e}",
+ filename = filename.prefer_local(),
),
);
false
@@ -227,7 +226,7 @@ impl SourceCollector<'_, '_> {
let desc = format!("Source of the Rust file `{}`.", filename.prefer_remapped());
let page = layout::Page {
title: &title,
- css_class: "source",
+ css_class: "src",
root_path: &root_path,
static_root_path: shared.static_root_path.as_deref(),
description: &desc,
diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css
index 54e8b6561..93aa11a58 100644
--- a/src/librustdoc/html/static/css/noscript.css
+++ b/src/librustdoc/html/static/css/noscript.css
@@ -19,7 +19,7 @@ nav.sub {
display: none;
}
-.source .sidebar {
+.src .sidebar {
display: none;
}
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index b7f455259..b1de8c152 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -194,7 +194,7 @@ h1, h2, h3, h4, h5, h6,
.item-name > a,
.out-of-band,
span.since,
-a.srclink,
+a.src,
#help-button > a,
summary.hideme,
.scraped-example-list,
@@ -206,7 +206,7 @@ ul.all-items {
#toggle-all-docs,
a.anchor,
.small-section-header a,
-#source-sidebar a,
+#src-sidebar a,
.rust a,
.sidebar h2 a,
.sidebar h3 a,
@@ -315,7 +315,7 @@ main {
min-width: 0; /* avoid growing beyond the size limit */
}
-.source main {
+.src main {
padding: 15px;
}
@@ -350,10 +350,10 @@ pre.item-decl {
contain: initial;
}
-.source .content pre {
+.src .content pre {
padding: 20px;
}
-.rustdoc.source .example-wrap pre.src-line-numbers {
+.rustdoc.src .example-wrap pre.src-line-numbers {
padding: 20px 0 20px 4px;
}
@@ -392,7 +392,7 @@ img {
left: 0;
}
-.rustdoc.source .sidebar {
+.rustdoc.src .sidebar {
flex-basis: 50px;
border-right: 1px solid;
overflow-x: hidden;
@@ -402,7 +402,7 @@ img {
}
.sidebar, .mobile-topbar, .sidebar-menu-toggle,
-#src-sidebar-toggle, #source-sidebar {
+#src-sidebar-toggle, #src-sidebar {
background-color: var(--sidebar-background-color);
}
@@ -410,16 +410,16 @@ img {
background-color: var(--sidebar-background-color-hover);
}
-.source .sidebar > *:not(#src-sidebar-toggle) {
+.src .sidebar > *:not(#src-sidebar-toggle) {
visibility: hidden;
}
-.source-sidebar-expanded .source .sidebar {
+.src-sidebar-expanded .src .sidebar {
overflow-y: auto;
flex-basis: 300px;
}
-.source-sidebar-expanded .source .sidebar > *:not(#src-sidebar-toggle) {
+.src-sidebar-expanded .src .sidebar > *:not(#src-sidebar-toggle) {
visibility: visible;
}
@@ -544,7 +544,7 @@ ul.block, .block li {
flex-grow: 1;
}
-.rustdoc:not(.source) .example-wrap pre {
+.rustdoc:not(.src) .example-wrap pre {
overflow: auto hidden;
}
@@ -619,7 +619,7 @@ ul.block, .block li {
}
.docblock code, .docblock-short code,
-pre, .rustdoc.source .example-wrap {
+pre, .rustdoc.src .example-wrap {
background-color: var(--code-block-background-color);
}
@@ -676,7 +676,7 @@ nav.sub {
height: 34px;
flex-grow: 1;
}
-.source nav.sub {
+.src nav.sub {
margin: 0 0 15px 0;
}
@@ -776,7 +776,6 @@ table,
}
#crate-search {
min-width: 115px;
- /* keep these two in sync with "@-moz-document url-prefix()" below */
padding: 0 23px 0 4px;
/* prevents the <select> from overflowing the containing div in case it's shrunk */
max-width: 100%;
@@ -798,14 +797,6 @@ table,
#crate-search:hover, #crate-search:focus {
border-color: var(--crate-search-hover-border);
}
-/* cancel stylistic differences in padding in firefox
-for "appearance: none"-style (or equivalent) <select>s */
-@-moz-document url-prefix() {
- #crate-search {
- padding-left: 0px; /* == 4px - 4px */
- padding-right: 19px; /* == 23px - 4px */
- }
-}
/* pseudo-element for holding the dropdown-arrow image; needs to be a separate thing
so that we can apply CSS-filters to change the arrow color in themes */
#crate-search-div::after {
@@ -888,7 +879,7 @@ so that we can apply CSS-filters to change the arrow color in themes */
justify-content: start;
flex: 3;
}
-.search-results .result-name span.alias {
+.search-results .result-name .alias {
color: var(--search-results-alias-color);
}
.search-results .result-name .grey {
@@ -904,6 +895,9 @@ so that we can apply CSS-filters to change the arrow color in themes */
max-width: calc(100% - var(--search-typename-width));
display: inline-block;
}
+.search-results .result-name .path > * {
+ display: inline;
+}
.popover {
position: absolute;
@@ -1074,7 +1068,7 @@ pre.rust .doccomment {
color: var(--code-highlight-doc-comment-color);
}
-.rustdoc.source .example-wrap pre.rust a {
+.rustdoc.src .example-wrap pre.rust a {
background: var(--codeblock-link-background);
}
@@ -1301,22 +1295,22 @@ a.tooltip:hover::after {
align-items: stretch;
z-index: 10;
}
-#source-sidebar {
+#src-sidebar {
width: 100%;
overflow: auto;
}
-#source-sidebar > .title {
+#src-sidebar > .title {
font-size: 1.5rem;
text-align: center;
border-bottom: 1px solid var(--border-color);
margin-bottom: 6px;
}
-#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
-#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
- background-color: var(--source-sidebar-background-hover);
+#src-sidebar div.files > a:hover, details.dir-entry summary:hover,
+#src-sidebar div.files > a:focus, details.dir-entry summary:focus {
+ background-color: var(--src-sidebar-background-hover);
}
-#source-sidebar div.files > a.selected {
- background-color: var(--source-sidebar-background-selected);
+#src-sidebar div.files > a.selected {
+ background-color: var(--src-sidebar-background-selected);
}
#src-sidebar-toggle > button {
font-size: inherit;
@@ -1562,7 +1556,7 @@ However, it's not needed with smaller screen width because the doc/code block is
/*
WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY
If you update this line, then you also need to update the line with the same warning
-in source-script.js
+in src-script.js
*/
@media (max-width: 700px) {
/* When linking to an item with an `id` (for instance, by clicking a link in the sidebar,
@@ -1619,8 +1613,8 @@ in source-script.js
/* The source view uses a different design for the sidebar toggle, and doesn't have a topbar,
so don't bump down the main content or the sidebar. */
- .source main,
- .rustdoc.source .sidebar {
+ .src main,
+ .rustdoc.src .sidebar {
top: 0;
padding: 0;
height: 100vh;
@@ -1628,8 +1622,8 @@ in source-script.js
}
.sidebar.shown,
- .source-sidebar-expanded .source .sidebar,
- .rustdoc:not(.source) .sidebar:focus-within {
+ .src-sidebar-expanded .src .sidebar,
+ .rustdoc:not(.src) .sidebar:focus-within {
left: 0;
}
@@ -1709,7 +1703,7 @@ in source-script.js
border-left: 0;
}
- .source-sidebar-expanded #src-sidebar-toggle {
+ .src-sidebar-expanded #src-sidebar-toggle {
left: unset;
top: unset;
width: unset;
@@ -1749,7 +1743,7 @@ in source-script.js
display: inline;
}
- .source-sidebar-expanded .source .sidebar {
+ .src-sidebar-expanded .src .sidebar {
max-width: 100vw;
width: 100vw;
}
@@ -1769,7 +1763,7 @@ in source-script.js
margin-left: 34px;
}
- .source nav.sub {
+ .src nav.sub {
margin: 0;
padding: var(--nav-sub-mobile-padding);
}
@@ -1792,7 +1786,7 @@ in source-script.js
}
@media print {
- nav.sidebar, nav.sub, .out-of-band, a.srclink, #copy-path,
+ nav.sidebar, nav.sub, .out-of-band, a.src, #copy-path,
details.toggle[open] > summary::before, details.toggle > summary::before,
details.toggle.top-doc > summary {
display: none;
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index 7145baad2..d8dae51eb 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -89,8 +89,8 @@ Original by Dempfi (https://github.com/dempfi/ayu)
--crate-search-div-hover-filter: invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg)
brightness(113%) contrast(76%);
--crate-search-hover-border: #e0e0e0;
- --source-sidebar-background-selected: #14191f;
- --source-sidebar-background-hover: #14191f;
+ --src-sidebar-background-selected: #14191f;
+ --src-sidebar-background-hover: #14191f;
--table-alt-row-background-color: #191f26;
--codeblock-link-background: #333;
--scrape-example-toggle-line-background: #999;
@@ -107,7 +107,7 @@ Original by Dempfi (https://github.com/dempfi/ayu)
h1, h2, h3, h4,
h1 a, .sidebar h2 a, .sidebar h3 a,
-#source-sidebar > .title {
+#src-sidebar > .title {
color: #fff;
}
h4 {
@@ -124,15 +124,15 @@ h4 {
.docblock pre > code,
pre, pre > code,
.item-info code,
-.rustdoc.source .example-wrap {
+.rustdoc.src .example-wrap {
color: #e6e1cf;
}
.sidebar .current,
.sidebar a:hover,
-#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
-#source-sidebar div.files > a:focus, details.dir-entry summary:focus,
-#source-sidebar div.files > a.selected {
+#src-sidebar div.files > a:hover, details.dir-entry summary:hover,
+#src-sidebar div.files > a:focus, details.dir-entry summary:focus,
+#src-sidebar div.files > a.selected {
color: #ffb44c;
}
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index 3c1186a56..2b3029887 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -68,7 +68,7 @@
--test-arrow-color: #dedede;
--test-arrow-background-color: rgba(78, 139, 202, 0.2);
--test-arrow-hover-color: #dedede;
- --test-arrow-hover-background-color: #4e8bca;
+ --test-arrow-hover-background-color: rgb(78, 139, 202);
--target-background-color: #494a3d;
--target-border-color: #bb7410;
--kbd-color: #000;
@@ -84,8 +84,8 @@
--crate-search-div-hover-filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg)
brightness(100%) contrast(91%);
--crate-search-hover-border: #2196f3;
- --source-sidebar-background-selected: #333;
- --source-sidebar-background-hover: #444;
+ --src-sidebar-background-selected: #333;
+ --src-sidebar-background-hover: #444;
--table-alt-row-background-color: #2A2A2A;
--codeblock-link-background: #333;
--scrape-example-toggle-line-background: #999;
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index f8c287137..56fd8cbef 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -68,7 +68,7 @@
--test-arrow-color: #f5f5f5;
--test-arrow-background-color: rgba(78, 139, 202, 0.2);
--test-arrow-hover-color: #f5f5f5;
- --test-arrow-hover-background-color: #4e8bca;
+ --test-arrow-hover-background-color: rgb(78, 139, 202);
--target-background-color: #fdffd3;
--target-border-color: #ad7c37;
--kbd-color: #000;
@@ -81,8 +81,8 @@
--crate-search-div-hover-filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg)
brightness(96%) contrast(93%);
--crate-search-hover-border: #717171;
- --source-sidebar-background-selected: #fff;
- --source-sidebar-background-hover: #e0e0e0;
+ --src-sidebar-background-selected: #fff;
+ --src-sidebar-background-hover: #e0e0e0;
--table-alt-row-background-color: #F5F5F5;
--codeblock-link-background: #eee;
--scrape-example-toggle-line-background: #ccc;
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 51d8e81ca..42088e735 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -2108,29 +2108,22 @@ function initSearch(rawSearchIndex) {
const resultName = document.createElement("div");
resultName.className = "result-name";
- if (item.is_alias) {
- const alias = document.createElement("span");
- alias.className = "alias";
-
- const bold = document.createElement("b");
- bold.innerText = item.alias;
- alias.appendChild(bold);
-
- alias.insertAdjacentHTML(
- "beforeend",
- "<i class=\"grey\">&nbsp;- see&nbsp;</i>");
+ resultName.insertAdjacentHTML(
+ "beforeend",
+ `<span class="typename">${typeName}</span>`);
+ link.appendChild(resultName);
- resultName.appendChild(alias);
+ let alias = " ";
+ if (item.is_alias) {
+ alias = ` <div class="alias">\
+<b>${item.alias}</b><i class="grey">&nbsp;- see&nbsp;</i>\
+</div>`;
}
-
resultName.insertAdjacentHTML(
"beforeend",
- `\
-<span class="typename">${typeName}</span>\
-<div class="path">\
- ${item.displayPath}<span class="${type}">${name}</span>\
+ `<div class="path">${alias}\
+${item.displayPath}<span class="${type}">${name}</span>\
</div>`);
- link.appendChild(resultName);
const description = document.createElement("div");
description.className = "desc";
diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/src-script.js
index 6eb991360..679c2341f 100644
--- a/src/librustdoc/html/static/js/source-script.js
+++ b/src/librustdoc/html/static/js/src-script.js
@@ -1,5 +1,5 @@
// From rust:
-/* global sourcesIndex */
+/* global srcIndex */
// Local js definitions:
/* global addClass, getCurrentValue, onEachLazy, removeClass, browserSupportsHistoryApi */
@@ -74,11 +74,11 @@ function createDirEntry(elem, parent, fullPath, hasFoundFile) {
function toggleSidebar() {
const child = this.parentNode.children[0];
if (child.innerText === ">") {
- addClass(document.documentElement, "source-sidebar-expanded");
+ addClass(document.documentElement, "src-sidebar-expanded");
child.innerText = "<";
updateLocalStorage("source-sidebar-show", "true");
} else {
- removeClass(document.documentElement, "source-sidebar-expanded");
+ removeClass(document.documentElement, "src-sidebar-expanded");
child.innerText = ">";
updateLocalStorage("source-sidebar-show", "false");
}
@@ -101,16 +101,16 @@ function createSidebarToggle() {
return sidebarToggle;
}
-// This function is called from "source-files.js", generated in `html/render/write_shared.rs`.
+// This function is called from "src-files.js", generated in `html/render/write_shared.rs`.
// eslint-disable-next-line no-unused-vars
-function createSourceSidebar() {
+function createSrcSidebar() {
const container = document.querySelector("nav.sidebar");
const sidebarToggle = createSidebarToggle();
container.insertBefore(sidebarToggle, container.firstChild);
const sidebar = document.createElement("div");
- sidebar.id = "source-sidebar";
+ sidebar.id = "src-sidebar";
let hasFoundFile = false;
@@ -118,9 +118,9 @@ function createSourceSidebar() {
title.className = "title";
title.innerText = "Files";
sidebar.appendChild(title);
- Object.keys(sourcesIndex).forEach(key => {
- sourcesIndex[key][NAME_OFFSET] = key;
- hasFoundFile = createDirEntry(sourcesIndex[key], sidebar, "", hasFoundFile);
+ Object.keys(srcIndex).forEach(key => {
+ srcIndex[key][NAME_OFFSET] = key;
+ hasFoundFile = createDirEntry(srcIndex[key], sidebar, "", hasFoundFile);
});
container.appendChild(sidebar);
@@ -133,7 +133,7 @@ function createSourceSidebar() {
const lineNumbersRegex = /^#?(\d+)(?:-(\d+))?$/;
-function highlightSourceLines(match) {
+function highlightSrcLines(match) {
if (typeof match === "undefined") {
match = window.location.hash.match(lineNumbersRegex);
}
@@ -172,7 +172,7 @@ function highlightSourceLines(match) {
}
}
-const handleSourceHighlight = (function() {
+const handleSrcHighlight = (function() {
let prev_line_id = 0;
const set_fragment = name => {
@@ -180,7 +180,7 @@ const handleSourceHighlight = (function() {
y = window.scrollY;
if (browserSupportsHistoryApi()) {
history.replaceState(null, null, "#" + name);
- highlightSourceLines();
+ highlightSrcLines();
} else {
location.replace("#" + name);
}
@@ -221,15 +221,15 @@ const handleSourceHighlight = (function() {
window.addEventListener("hashchange", () => {
const match = window.location.hash.match(lineNumbersRegex);
if (match) {
- return highlightSourceLines(match);
+ return highlightSrcLines(match);
}
});
onEachLazy(document.getElementsByClassName("src-line-numbers"), el => {
- el.addEventListener("click", handleSourceHighlight);
+ el.addEventListener("click", handleSrcHighlight);
});
-highlightSourceLines();
+highlightSrcLines();
-window.createSourceSidebar = createSourceSidebar;
+window.createSrcSidebar = createSrcSidebar;
})();
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index 71961f6f2..af3ca42a6 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -185,7 +185,7 @@ updateTheme();
if (getSettingValue("source-sidebar-show") === "true") {
// At this point in page load, `document.body` is not available yet.
// Set a class on the `<html>` element instead.
- addClass(document.documentElement, "source-sidebar-expanded");
+ addClass(document.documentElement, "src-sidebar-expanded");
}
// If we navigate away (for example to a settings page), and then use the back or
diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs
index 767b974cc..a27aa2b58 100644
--- a/src/librustdoc/html/static_files.rs
+++ b/src/librustdoc/html/static_files.rs
@@ -53,7 +53,7 @@ pub(crate) fn suffix_path(filename: &str, suffix: &str) -> PathBuf {
// which would result in `style.min-suffix.css` which isn't what we
// want.
let (base, ext) = filename.split_once('.').unwrap();
- let filename = format!("{}{}.{}", base, suffix, ext);
+ let filename = format!("{base}{suffix}.{ext}");
filename.into()
}
@@ -97,7 +97,7 @@ static_files! {
main_js => "static/js/main.js",
search_js => "static/js/search.js",
settings_js => "static/js/settings.js",
- source_script_js => "static/js/source-script.js",
+ src_script_js => "static/js/src-script.js",
storage_js => "static/js/storage.js",
scrape_examples_js => "static/js/scrape-examples.js",
wheel_svg => "static/images/wheel.svg",
diff --git a/src/librustdoc/html/templates/STYLE.md b/src/librustdoc/html/templates/STYLE.md
index 0281b1c47..38aac2a60 100644
--- a/src/librustdoc/html/templates/STYLE.md
+++ b/src/librustdoc/html/templates/STYLE.md
@@ -32,7 +32,7 @@ Askama templates support quite sophisticated control flow. To keep our templates
simple and understandable, we use only a subset: `if` and `for`. In particular
we avoid [assignments in the template logic][assignments] and [Askama
macros][macros]. This also may make things easier if we switch to a different
-Jinja-style template system, like Askama, in the future.
+Jinja-style template system in the future.
[assignments]: https://djc.github.io/askama/template_syntax.html#assignments
[macros]: https://djc.github.io/askama/template_syntax.html#macros
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index d4ec9c34b..60ccfe4da 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -42,9 +42,9 @@
<script src="{{static_root_path|safe}}{{files.storage_js}}"></script> {# #}
{% if page.css_class.contains("crate") %}
<script defer src="{{page.root_path|safe}}crates{{page.resource_suffix}}.js"></script> {# #}
- {% else if page.css_class == "source" %}
- <script defer src="{{static_root_path|safe}}{{files.source_script_js}}"></script> {# #}
- <script defer src="{{page.root_path|safe}}source-files{{page.resource_suffix}}.js"></script> {# #}
+ {% else if page.css_class == "src" %}
+ <script defer src="{{static_root_path|safe}}{{files.src_script_js}}"></script> {# #}
+ <script defer src="{{page.root_path|safe}}src-files{{page.resource_suffix}}.js"></script> {# #}
{% else if !page.css_class.contains("mod") %}
<script defer src="sidebar-items{{page.resource_suffix}}.js"></script> {# #}
{% endif %}
@@ -85,7 +85,7 @@
</div> {# #}
<![endif]--> {# #}
{{ layout.external_html.before_content|safe }}
- {% if page.css_class != "source" %}
+ {% if page.css_class != "src" %}
<nav class="mobile-topbar"> {# #}
<button class="sidebar-menu-toggle">&#9776;</button> {# #}
<a class="logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {# #}
@@ -99,7 +99,7 @@
</nav> {# #}
{% endif %}
<nav class="sidebar"> {# #}
- {% if page.css_class != "source" %}
+ {% if page.css_class != "src" %}
<a class="logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {# #}
{% if !layout.logo.is_empty() %}
<img src="{{layout.logo}}" alt="logo"> {# #}
@@ -111,9 +111,9 @@
{{ sidebar|safe }}
</nav> {# #}
<main> {# #}
- {% if page.css_class != "source" %}<div class="width-limiter">{% endif %}
+ {% if page.css_class != "src" %}<div class="width-limiter">{% endif %}
<nav class="sub"> {# #}
- {% if page.css_class == "source" %}
+ {% if page.css_class == "src" %}
<a class="sub-logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {# #}
{% if !layout.logo.is_empty() %}
<img src="{{layout.logo}}" alt="logo"> {# #}
@@ -144,7 +144,7 @@
</form> {# #}
</nav> {# #}
<section id="main-content" class="content">{{ content|safe }}</section> {# #}
- {% if page.css_class != "source" %}</div>{% endif %}
+ {% if page.css_class != "src" %}</div>{% endif %}
</main> {# #}
{{ layout.external_html.after_content|safe }}
</body> {# #}
diff --git a/src/librustdoc/html/templates/print_item.html b/src/librustdoc/html/templates/print_item.html
index 68a295ae0..1d215c269 100644
--- a/src/librustdoc/html/templates/print_item.html
+++ b/src/librustdoc/html/templates/print_item.html
@@ -18,7 +18,7 @@
{% endif %}
{% match src_href %}
{% when Some with (href) %}
- <a class="srclink" href="{{href|safe}}">source</a> · {#+ #}
+ <a class="src" href="{{href|safe}}">source</a> · {#+ #}
{% else %}
{% endmatch %}
<button id="toggle-all-docs" title="collapse all docs"> {# #}
diff --git a/src/librustdoc/html/templates/type_layout.html b/src/librustdoc/html/templates/type_layout.html
index 20e09a548..287cbab07 100644
--- a/src/librustdoc/html/templates/type_layout.html
+++ b/src/librustdoc/html/templates/type_layout.html
@@ -44,6 +44,11 @@
<strong>Note:</strong> Encountered an error during type layout; {#+ #}
the type was too big. {# #}
</p> {# #}
+ {% when Err(LayoutError::ReferencesError(_)) %}
+ <p> {# #}
+ <strong>Note:</strong> Encountered an error during type layout; {#+ #}
+ the type references errors. {# #}
+ </p> {# #}
{% when Err(LayoutError::NormalizationFailure(_, _)) %}
<p> {# #}
<strong>Note:</strong> Encountered an error during type layout; {#+ #}
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 91cd55b11..8673138f6 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -171,6 +171,7 @@ impl FromWithTcx<clean::GenericArg> for GenericArg {
}
impl FromWithTcx<clean::Constant> for Constant {
+ // FIXME(generic_const_items): Add support for generic const items.
fn from_tcx(constant: clean::Constant, tcx: TyCtxt<'_>) -> Self {
let expr = constant.expr(tcx);
let value = constant.value(tcx);
@@ -321,8 +322,12 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
impls: Vec::new(), // Added in JsonRenderer::item
})
}
- TyAssocConstItem(ty) => ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: None },
- AssocConstItem(ty, default) => {
+ // FIXME(generic_const_items): Add support for generic associated consts.
+ TyAssocConstItem(_generics, ty) => {
+ ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: None }
+ }
+ // FIXME(generic_const_items): Add support for generic associated consts.
+ AssocConstItem(_generics, ty, default) => {
ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: Some(default.expr(tcx)) }
}
TyAssocTypeItem(g, b) => ItemEnum::AssocType {
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 9392dd4d0..cd791ce00 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -139,7 +139,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
fn item(&mut self, item: clean::Item) -> Result<(), Error> {
let item_type = item.type_();
let item_name = item.name;
- trace!("rendering {} {:?}", item_type, item_name);
+ trace!("rendering {item_type} {item_name:?}");
// Flatten items that recursively store other items. We include orphaned items from
// stripped modules and etc that are otherwise reachable.
@@ -203,11 +203,11 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
if !can_be_ignored {
assert_eq!(old_item, new_item);
}
- trace!("replaced {:?}\nwith {:?}", old_item, new_item);
+ trace!("replaced {old_item:?}\nwith {new_item:?}");
}
}
- trace!("done rendering {} {:?}", item_type, item_name);
+ trace!("done rendering {item_type} {item_name:?}");
Ok(())
}
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index f28deae79..8220df5d4 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -192,8 +192,7 @@ fn init_logging(handler: &EarlyErrorHandler) {
Ok("never") => false,
Ok("auto") | Err(VarError::NotPresent) => io::stdout().is_terminal(),
Ok(value) => handler.early_error(format!(
- "invalid log color value '{}': expected one of always, never, or auto",
- value
+ "invalid log color value '{value}': expected one of always, never, or auto",
)),
Err(VarError::NotUnicode(value)) => handler.early_error(format!(
"invalid log color value '{}': expected one of always, never, or auto",
@@ -224,7 +223,7 @@ fn get_args(handler: &EarlyErrorHandler) -> Option<Vec<String>> {
.map(|(i, arg)| {
arg.into_string()
.map_err(|arg| {
- handler.early_warn(format!("Argument {} is not valid Unicode: {:?}", i, arg));
+ handler.early_warn(format!("Argument {i} is not valid Unicode: {arg:?}"));
})
.ok()
})
@@ -665,11 +664,10 @@ fn usage(argv0: &str) {
for option in opts() {
(option.apply)(&mut options);
}
- println!("{}", options.usage(&format!("{} [options] <input>", argv0)));
+ println!("{}", options.usage(&format!("{argv0} [options] <input>")));
println!(" @path Read newline separated options from `path`\n");
println!(
- "More information available at {}/rustdoc/what-is-rustdoc.html",
- DOC_RUST_LANG_ORG_CHANNEL
+ "More information available at {DOC_RUST_LANG_ORG_CHANNEL}/rustdoc/what-is-rustdoc.html",
);
}
@@ -699,7 +697,7 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
tcx.sess.struct_err(format!("couldn't generate documentation: {}", e.error));
let file = e.file.display().to_string();
if !file.is_empty() {
- msg.note(format!("failed to create or modify \"{}\"", file));
+ msg.note(format!("failed to create or modify \"{file}\""));
}
Err(msg.emit())
}
@@ -744,9 +742,6 @@ fn main_args(handler: &mut EarlyErrorHandler, at_args: &[String]) -> MainResult
}
};
- // Set parallel mode before error handler creation, which will create `Lock`s.
- interface::set_thread_safe_mode(&options.unstable_opts);
-
let diag = core::new_handler(
options.error_format,
None,
diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs
index 749c1ff51..d45040e34 100644
--- a/src/librustdoc/lint.rs
+++ b/src/librustdoc/lint.rs
@@ -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,
]
});
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index 4321d4aa3..526eea304 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -43,7 +43,7 @@ pub(crate) fn render<P: AsRef<Path>>(
edition: Edition,
) -> Result<(), String> {
if let Err(e) = create_dir_all(&options.output) {
- return Err(format!("{}: {}", options.output.display(), e));
+ return Err(format!("{output}: {e}", output = options.output.display()));
}
let input = input.as_ref();
@@ -57,11 +57,13 @@ pub(crate) fn render<P: AsRef<Path>>(
.expect("Writing to a String can't fail");
}
- let input_str = read_to_string(input).map_err(|err| format!("{}: {}", input.display(), err))?;
+ let input_str =
+ read_to_string(input).map_err(|err| format!("{input}: {err}", input = input.display()))?;
let playground_url = options.markdown_playground_url.or(options.playground_url);
let playground = playground_url.map(|url| markdown::Playground { crate_name: None, url });
- let mut out = File::create(&output).map_err(|e| format!("{}: {}", output.display(), e))?;
+ let mut out =
+ File::create(&output).map_err(|e| format!("{output}: {e}", output = output.display()))?;
let (metadata, text) = extract_leading_metadata(&input_str);
if metadata.is_empty() {
@@ -129,7 +131,7 @@ pub(crate) fn render<P: AsRef<Path>>(
);
match err {
- Err(e) => Err(format!("cannot write to `{}`: {}", output.display(), e)),
+ Err(e) => Err(format!("cannot write to `{output}`: {e}", output = output.display())),
Ok(_) => Ok(()),
}
}
@@ -137,7 +139,7 @@ pub(crate) fn render<P: AsRef<Path>>(
/// Runs any tests/code examples in the markdown file `input`.
pub(crate) fn test(options: Options) -> Result<(), String> {
let input_str = read_to_string(&options.input)
- .map_err(|err| format!("{}: {}", options.input.display(), err))?;
+ .map_err(|err| format!("{input}: {err}", input = options.input.display()))?;
let mut opts = GlobalTestOptions::default();
opts.no_crate_inject = true;
let mut collector = Collector::new(
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index 6ead0cd96..592dd0a14 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -146,8 +146,10 @@ impl<'a, 'b> CoverageCalculator<'a, 'b> {
examples_percentage: f64,
) {
println!(
- "| {:<35} | {:>10} | {:>9.1}% | {:>10} | {:>9.1}% |",
- name, count.with_docs, percentage, count.with_examples, examples_percentage,
+ "| {name:<35} | {with_docs:>10} | {percentage:>9.1}% | {with_examples:>10} | \
+ {examples_percentage:>9.1}% |",
+ with_docs = count.with_docs,
+ with_examples = count.with_examples,
);
}
@@ -249,7 +251,7 @@ impl<'a, 'b> DocVisitor for CoverageCalculator<'a, 'b> {
if let Some(span) = i.span(self.ctx.tcx) {
let filename = span.filename(self.ctx.sess());
- debug!("counting {:?} {:?} in {:?}", i.type_(), i.name, filename);
+ debug!("counting {:?} {:?} in {filename:?}", i.type_(), i.name);
self.items.entry(filename).or_default().count_item(
has_docs,
has_doc_example,
diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs
index b6cd897d3..e732a4057 100644
--- a/src/librustdoc/passes/check_doc_test_visibility.rs
+++ b/src/librustdoc/passes/check_doc_test_visibility.rs
@@ -7,11 +7,11 @@
use super::Pass;
use crate::clean;
+use crate::clean::utils::inherits_doc_hidden;
use crate::clean::*;
use crate::core::DocContext;
use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString};
use crate::visit::DocVisitor;
-use crate::visit_ast::inherits_doc_hidden;
use rustc_hir as hir;
use rustc_middle::lint::LintLevelSource;
use rustc_session::lint;
@@ -92,8 +92,8 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -
return false;
}
- if cx.tcx.is_doc_hidden(def_id.to_def_id())
- || inherits_doc_hidden(cx.tcx, def_id, None)
+ if (!cx.render_options.document_hidden
+ && (cx.tcx.is_doc_hidden(def_id.to_def_id()) || inherits_doc_hidden(cx.tcx, def_id, None)))
|| cx.tcx.def_span(def_id.to_def_id()).in_derive_expansion()
{
return false;
@@ -106,8 +106,7 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -
}
pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) {
- let Some(hir_id) = DocContext::as_local_hir_id(cx.tcx, item.item_id)
- else {
+ let Some(hir_id) = DocContext::as_local_hir_id(cx.tcx, item.item_id) else {
// If non-local, no need to check anything.
return;
};
@@ -118,7 +117,7 @@ pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item
if tests.found_tests == 0 && cx.tcx.features().rustdoc_missing_doc_code_examples {
if should_have_doc_example(cx, item) {
- debug!("reporting error for {:?} (hir_id={:?})", item, hir_id);
+ debug!("reporting error for {item:?} (hir_id={hir_id:?})");
let sp = item.attr_span(cx.tcx);
cx.tcx.struct_span_lint_hir(
crate::lint::MISSING_DOC_CODE_EXAMPLES,
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 0dd9e590b..7b0a7a90d 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -14,7 +14,7 @@ use rustc_hir::def::{DefKind, Namespace, PerNS};
use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
use rustc_hir::Mutability;
use rustc_middle::ty::{Ty, TyCtxt};
-use rustc_middle::{bug, ty};
+use rustc_middle::{bug, span_bug, ty};
use rustc_resolve::rustdoc::{has_primitive_or_keyword_docs, prepare_to_doc_link_resolution};
use rustc_resolve::rustdoc::{strip_generics_from_path, MalformedGenerics};
use rustc_session::lint::Lint;
@@ -150,7 +150,7 @@ impl TryFrom<ResolveRes> for Res {
PrimTy(prim) => Ok(Res::Primitive(PrimitiveType::from_hir(prim))),
// e.g. `#[derive]`
ToolMod | NonMacroAttr(..) | Err => Result::Err(()),
- other => bug!("unrecognized res {:?}", other),
+ other => bug!("unrecognized res {other:?}"),
}
}
}
@@ -224,7 +224,7 @@ impl UrlFragment {
"structfield."
}
}
- kind => bug!("unexpected associated item kind: {:?}", kind),
+ kind => bug!("unexpected associated item kind: {kind:?}"),
};
s.push_str(kind);
s.push_str(tcx.item_name(def_id).as_str());
@@ -279,7 +279,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
unresolved: path_str.into(),
};
- debug!("looking for enum variant {}", path_str);
+ debug!("looking for enum variant {path_str}");
let mut split = path_str.rsplitn(3, "::");
let variant_field_name = split
.next()
@@ -298,7 +298,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
let ty_res = self.resolve_path(&path, TypeNS, item_id, module_id).ok_or_else(no_res)?;
match ty_res {
- Res::Def(DefKind::Enum, did) => match tcx.type_of(did).subst_identity().kind() {
+ Res::Def(DefKind::Enum, did) => match tcx.type_of(did).instantiate_identity().kind() {
ty::Adt(def, _) if def.is_enum() => {
if let Some(variant) = def.variants().iter().find(|v| v.name == variant_name)
&& let Some(field) = variant.fields.iter().find(|f| f.name == variant_field_name) {
@@ -402,10 +402,15 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
// `doc_link_resolutions` is missing a `path_str`, that means that there are valid links
// that are being missed. To fix the ICE, change
// `rustc_resolve::rustdoc::attrs_to_preprocessed_links` to cache the link.
- .unwrap_or_else(|| panic!("no resolution for {:?} {:?} {:?}", path_str, ns, module_id))
+ .unwrap_or_else(|| {
+ span_bug!(
+ self.cx.tcx.def_span(item_id),
+ "no resolution for {path_str:?} {ns:?} {module_id:?}",
+ )
+ })
.and_then(|res| res.try_into().ok())
.or_else(|| resolve_primitive(path_str, ns));
- debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
+ debug!("{path_str} resolved to {result:?} in namespace {ns:?}");
result
}
@@ -448,7 +453,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
// If there's no `::`, it's not an associated item.
// So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved.
.ok_or_else(|| {
- debug!("found no `::`, assuming {} was correctly not in scope", item_name);
+ debug!("found no `::`, assuming {item_name} was correctly not in scope");
UnresolvedPath {
item_id,
module_id,
@@ -493,7 +498,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
/// This is used for resolving type aliases.
fn def_id_to_res(&self, ty_id: DefId) -> Option<Res> {
use PrimitiveType::*;
- Some(match *self.cx.tcx.type_of(ty_id).subst_identity().kind() {
+ Some(match *self.cx.tcx.type_of(ty_id).instantiate_identity().kind() {
ty::Bool => Res::Primitive(Bool),
ty::Char => Res::Primitive(Char),
ty::Int(ity) => Res::Primitive(ity.into()),
@@ -587,7 +592,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
.unwrap_or(Vec::new())
}
}
- Res::Def(DefKind::TyAlias, did) => {
+ Res::Def(DefKind::TyAlias { .. }, did) => {
// Resolve the link on the type the alias points to.
// FIXME: if the associated item is defined directly on the type alias,
// it will show up on its documentation page, we should link there instead.
@@ -598,10 +603,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
def_kind @ (DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::ForeignTy),
did,
) => {
- debug!("looking for associated item named {} for item {:?}", item_name, did);
+ debug!("looking for associated item named {item_name} for item {did:?}");
// Checks if item_name is a variant of the `SomeItem` enum
if ns == TypeNS && def_kind == DefKind::Enum {
- match tcx.type_of(did).subst_identity().kind() {
+ match tcx.type_of(did).instantiate_identity().kind() {
ty::Adt(adt_def, _) => {
for variant in adt_def.variants() {
if variant.name == item_name {
@@ -635,7 +640,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
// To handle that properly resolve() would have to support
// something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
assoc_items = resolve_associated_trait_item(
- tcx.type_of(did).subst_identity(),
+ tcx.type_of(did).instantiate_identity(),
module_id,
item_name,
ns,
@@ -646,7 +651,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
.collect::<Vec<_>>();
}
- debug!("got associated item {:?}", assoc_items);
+ debug!("got associated item {assoc_items:?}");
if !assoc_items.is_empty() {
return assoc_items;
@@ -655,7 +660,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
if ns != Namespace::ValueNS {
return Vec::new();
}
- debug!("looking for fields named {} for {:?}", item_name, did);
+ debug!("looking for fields named {item_name} for {did:?}");
// FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?)
// NOTE: it's different from variant_field because it only resolves struct fields,
// not variant fields (2 path segments, not 3).
@@ -671,7 +676,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
// they also look like associated items (`module::Type::Variant`),
// because they are real Rust syntax (unlike the intra-doc links
// field syntax) and are handled by the compiler's resolver.
- let def = match tcx.type_of(did).subst_identity().kind() {
+ let def = match tcx.type_of(did).instantiate_identity().kind() {
ty::Adt(def, _) if !def.is_enum() => def,
_ => return Vec::new(),
};
@@ -722,7 +727,7 @@ fn resolve_associated_trait_item<'a>(
// Give precedence to inherent impls.
let traits = trait_impls_for(cx, ty, module);
let tcx = cx.tcx;
- debug!("considering traits {:?}", traits);
+ debug!("considering traits {traits:?}");
let candidates = traits
.iter()
.flat_map(|&(impl_, trait_)| {
@@ -739,7 +744,7 @@ fn resolve_associated_trait_item<'a>(
})
.collect::<Vec<_>>();
// FIXME(#74563): warn about ambiguity
- debug!("the candidates were {:?}", candidates);
+ debug!("the candidates were {candidates:?}");
candidates
}
@@ -785,10 +790,8 @@ fn trait_impls_for<'a>(
// Check if these are the same type.
let impl_type = trait_ref.skip_binder().self_ty();
trace!(
- "comparing type {} with kind {:?} against type {:?}",
- impl_type,
- impl_type.kind(),
- ty
+ "comparing type {impl_type} with kind {kind:?} against type {ty:?}",
+ kind = impl_type.kind(),
);
// Fast path: if this is a primitive simple `==` will work
// NOTE: the `match` is necessary; see #92662.
@@ -935,7 +938,7 @@ fn preprocess_link(
let path_str = match strip_generics_from_path(path_str) {
Ok(path) => path,
Err(err) => {
- debug!("link has malformed generics: {}", path_str);
+ debug!("link has malformed generics: {path_str}");
return Some(Err(PreprocessingError::MalformedGenerics(err, path_str.to_owned())));
}
};
@@ -963,6 +966,7 @@ fn preprocessed_markdown_links(s: &str) -> Vec<PreprocessedMarkdownLink> {
}
impl LinkCollector<'_, '_> {
+ #[instrument(level = "debug", skip_all)]
fn resolve_links(&mut self, item: &Item) {
if !self.cx.render_options.document_private
&& let Some(def_id) = item.item_id.as_def_id()
@@ -981,7 +985,7 @@ impl LinkCollector<'_, '_> {
if !may_have_doc_links(&doc) {
continue;
}
- debug!("combined_docs={}", doc);
+ debug!("combined_docs={doc}");
// NOTE: if there are links that start in one crate and end in another, this will not resolve them.
// This is a degenerate case and it's not supported by rustdoc.
let item_id = item_id.unwrap_or_else(|| item.item_id.expect_def_id());
@@ -990,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);
}
@@ -1003,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 {
@@ -1018,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;
@@ -1036,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?
@@ -1124,10 +1142,10 @@ impl LinkCollector<'_, '_> {
item: &Item,
diag_info: &DiagnosticInfo<'_>,
) -> Option<()> {
- debug!("intra-doc link to {} resolved to {:?}", path_str, (kind, id));
+ debug!("intra-doc link to {path_str} resolved to {:?}", (kind, id));
// Disallow e.g. linking to enums with `struct@`
- debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator);
+ debug!("saw kind {kind:?} with disambiguator {disambiguator:?}");
match (kind, disambiguator) {
| (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const)))
// NOTE: this allows 'method' to mean both normal functions and associated functions
@@ -1168,7 +1186,7 @@ impl LinkCollector<'_, '_> {
diag_info: &DiagnosticInfo<'_>,
) {
// The resolved item did not match the disambiguator; give a better error than 'not found'
- let msg = format!("incompatible link kind for `{}`", path_str);
+ let msg = format!("incompatible link kind for `{path_str}`");
let callback = |diag: &mut Diagnostic, sp: Option<rustc_span::Span>, link_range| {
let note = format!(
"this link resolved to {} {}, which is not {} {}",
@@ -1217,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 {
@@ -1224,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.
@@ -1275,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;
@@ -1304,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![];
}
}
@@ -1341,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<_>>()
@@ -1368,6 +1396,58 @@ 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();
+
+ if display_text.len() == explicit_link.len() {
+ // Whether they are same or not, skip the resolve process.
+ return;
+ }
+
+ if explicit_link.ends_with(&display_text[..]) || display_text.ends_with(&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,
@@ -1453,7 +1533,7 @@ impl Disambiguator {
"value" => NS(Namespace::ValueNS),
"macro" => NS(Namespace::MacroNS),
"prim" | "primitive" => Primitive,
- _ => return Err((format!("unknown disambiguator `{}`", prefix), 0..idx)),
+ _ => return Err((format!("unknown disambiguator `{prefix}`"), 0..idx)),
};
Ok(Some((d, &rest[1..], &rest[1..])))
} else {
@@ -1521,7 +1601,7 @@ enum Suggestion {
impl Suggestion {
fn descr(&self) -> Cow<'static, str> {
match self {
- Self::Prefix(x) => format!("prefix with `{}@`", x).into(),
+ Self::Prefix(x) => format!("prefix with `{x}@`").into(),
Self::Function => "add parentheses".into(),
Self::Macro => "add an exclamation mark".into(),
Self::RemoveDisambiguator => "remove the disambiguator".into(),
@@ -1531,9 +1611,9 @@ impl Suggestion {
fn as_help(&self, path_str: &str) -> String {
// FIXME: if this is an implied shortcut link, it's bad style to suggest `@`
match self {
- Self::Prefix(prefix) => format!("{}@{}", prefix, path_str),
- Self::Function => format!("{}()", path_str),
- Self::Macro => format!("{}!", path_str),
+ Self::Prefix(prefix) => format!("{prefix}@{path_str}"),
+ Self::Function => format!("{path_str}()"),
+ Self::Macro => format!("{path_str}!"),
Self::RemoveDisambiguator => path_str.into(),
}
}
@@ -1568,7 +1648,7 @@ impl Suggestion {
match self {
Self::Prefix(prefix) => {
// FIXME: if this is an implied shortcut link, it's bad style to suggest `@`
- let mut sugg = vec![(sp.with_hi(inner_sp.lo()), format!("{}@", prefix))];
+ let mut sugg = vec![(sp.with_hi(inner_sp.lo()), format!("{prefix}@"))];
if sp.hi() != inner_sp.hi() {
sugg.push((inner_sp.shrink_to_hi().with_hi(sp.hi()), String::new()));
}
@@ -1610,10 +1690,9 @@ fn report_diagnostic(
DiagnosticInfo { item, ori_link: _, dox, link_range }: &DiagnosticInfo<'_>,
decorate: impl FnOnce(&mut Diagnostic, Option<rustc_span::Span>, MarkdownLinkRange),
) {
- let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.item_id)
- else {
+ let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.item_id) else {
// If non-local, no need to check anything.
- info!("ignoring warning from parent crate: {}", msg);
+ info!("ignoring warning from parent crate: {msg}");
return;
};
@@ -1691,15 +1770,14 @@ fn resolution_failure(
report_diagnostic(
tcx,
BROKEN_INTRA_DOC_LINKS,
- format!("unresolved link to `{}`", path_str),
+ format!("unresolved link to `{path_str}`"),
&diag_info,
|diag, sp, link_range| {
- let item = |res: Res| format!("the {} `{}`", res.descr(), res.name(tcx),);
+ let item = |res: Res| format!("the {} `{}`", res.descr(), res.name(tcx));
let assoc_item_not_allowed = |res: Res| {
let name = res.name(tcx);
format!(
- "`{}` is {} {}, not a module or type, and cannot have associated items",
- name,
+ "`{name}` is {} {}, not a module or type, and cannot have associated items",
res.article(),
res.descr()
)
@@ -1745,7 +1823,7 @@ fn resolution_failure(
name = start;
for ns in [TypeNS, ValueNS, MacroNS] {
if let Ok(v_res) = collector.resolve(start, ns, item_id, module_id) {
- debug!("found partial_res={:?}", v_res);
+ debug!("found partial_res={v_res:?}");
if !v_res.is_empty() {
*partial_res = Some(full_res(tcx, v_res[0]));
*unresolved = end.into();
@@ -1766,10 +1844,10 @@ fn resolution_failure(
let note = if partial_res.is_some() {
// Part of the link resolved; e.g. `std::io::nonexistent`
let module_name = tcx.item_name(module);
- format!("no item named `{}` in module `{}`", unresolved, module_name)
+ format!("no item named `{unresolved}` in module `{module_name}`")
} else {
// None of the link resolved; e.g. `Notimported`
- format!("no item named `{}` in scope", unresolved)
+ format!("no item named `{unresolved}` in scope")
};
if let Some(span) = sp {
diag.span_label(span, note);
@@ -1811,7 +1889,7 @@ fn resolution_failure(
Res::Primitive(_) => None,
};
let is_struct_variant = |did| {
- if let ty::Adt(def, _) = tcx.type_of(did).subst_identity().kind()
+ if let ty::Adt(def, _) = tcx.type_of(did).instantiate_identity().kind()
&& def.is_enum()
&& let Some(variant) = def.variants().iter().find(|v| v.name == res.name(tcx)) {
// ctor is `None` if variant is a struct
@@ -1860,8 +1938,13 @@ fn resolution_failure(
}
return;
}
- Trait | TyAlias | ForeignTy | OpaqueTy | ImplTraitPlaceholder
- | TraitAlias | TyParam | Static(_) => "associated item",
+ Trait
+ | TyAlias { .. }
+ | ForeignTy
+ | OpaqueTy
+ | TraitAlias
+ | TyParam
+ | Static(_) => "associated item",
Impl { .. } | GlobalAsm => unreachable!("not a path"),
}
} else {
@@ -1869,11 +1952,9 @@ fn resolution_failure(
};
let name = res.name(tcx);
let note = format!(
- "the {} `{}` has no {} named `{}`",
- res.descr(),
- name,
- disambiguator.map_or(path_description, |d| d.descr()),
- unresolved,
+ "the {res} `{name}` has no {disamb_res} named `{unresolved}`",
+ res = res.descr(),
+ disamb_res = disambiguator.map_or(path_description, |d| d.descr()),
);
if let Some(span) = sp {
diag.span_label(span, note);
@@ -1968,7 +2049,7 @@ fn report_malformed_generics(
report_diagnostic(
cx.tcx,
BROKEN_INTRA_DOC_LINKS,
- format!("unresolved link to `{}`", path_str),
+ format!("unresolved link to `{path_str}`"),
&diag_info,
|diag, sp, _link_range| {
let note = match err {
@@ -2020,7 +2101,7 @@ fn ambiguity_error(
return false;
}
- let mut msg = format!("`{}` is ", path_str);
+ let mut msg = format!("`{path_str}` is ");
match kinds.as_slice() {
[res1, res2] => {
msg += &format!(
@@ -2084,7 +2165,7 @@ fn suggest_disambiguator(
diag.span_suggestion_verbose(sp, help, suggestion_text, Applicability::MaybeIncorrect);
}
} else {
- diag.help(format!("{}: {}", help, suggestion.as_help(path_str)));
+ diag.help(format!("{help}: {}", suggestion.as_help(path_str)));
}
}
@@ -2098,8 +2179,7 @@ fn privacy_error(cx: &DocContext<'_>, diag_info: &DiagnosticInfo<'_>, path_str:
}
None => "<unknown>",
};
- let msg =
- format!("public documentation for `{}` links to private item `{}`", item_name, path_str);
+ let msg = format!("public documentation for `{item_name}` links to private item `{path_str}`");
report_diagnostic(cx.tcx, PRIVATE_INTRA_DOC_LINKS, msg, diag_info, |diag, sp, _link_range| {
if let Some(sp) = sp {
@@ -2150,6 +2230,6 @@ fn resolve_primitive(path_str: &str, ns: Namespace) -> Option<Res> {
"never" | "!" => Never,
_ => return None,
};
- debug!("resolved primitives {:?}", prim);
+ debug!("resolved primitives {prim:?}");
Some(Res::Primitive(prim))
}
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index fbf827cce..ff89d4e08 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -103,11 +103,11 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
// nothing to do with the inherent impl.
//
// Rustdoc currently uses these `impl` block as a source of
- // the `Ty`, as well as the `ParamEnv`, `SubstsRef`, and
+ // the `Ty`, as well as the `ParamEnv`, `GenericArgsRef`, and
// `Generics`. To avoid relying on the `impl` block, these
// things would need to be created from wholecloth, in a
// form that is valid for use in type inference.
- let ty = tcx.type_of(def_id).subst_identity();
+ let ty = tcx.type_of(def_id).instantiate_identity();
match ty.kind() {
ty::Slice(ty)
| ty::Ref(_, ty, _)
diff --git a/src/librustdoc/passes/lint.rs b/src/librustdoc/passes/lint.rs
index e653207b9..c6d5b7bd3 100644
--- a/src/librustdoc/passes/lint.rs
+++ b/src/librustdoc/passes/lint.rs
@@ -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)
}
diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs
index e9cee92d2..97078a5cb 100644
--- a/src/librustdoc/passes/lint/bare_urls.rs
+++ b/src/librustdoc/passes/lint/bare_urls.rs
@@ -13,11 +13,10 @@ use std::mem;
use std::sync::LazyLock;
pub(super) 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 Some(hir_id) = DocContext::as_local_hir_id(cx.tcx, item.item_id) else {
+ // If non-local, no need to check anything.
+ return;
+ };
let dox = item.doc_value();
if !dox.is_empty() {
let report_diag =
@@ -29,7 +28,7 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item) {
.span_suggestion(
sp,
"use an automatic link instead",
- format!("<{}>", url),
+ format!("<{url}>"),
Applicability::MachineApplicable,
)
});
@@ -75,7 +74,7 @@ fn find_raw_urls(
range: Range<usize>,
f: &impl Fn(&DocContext<'_>, &'static str, &str, Range<usize>),
) {
- trace!("looking for raw urls in {}", text);
+ trace!("looking for raw urls in {text}");
// For now, we only check "full" URLs (meaning, starting with "http://" or "https://").
for match_ in URL_REGEX.find_iter(text) {
let url = match_.as_str();
diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs
index f489f5081..37e28e1fb 100644
--- a/src/librustdoc/passes/lint/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs
@@ -40,7 +40,7 @@ fn check_rust_syntax(
let emitter = BufferEmitter { buffer: Lrc::clone(&buffer), fallback_bundle };
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
- let handler = Handler::with_emitter(false, None, Box::new(emitter));
+ let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings();
let source = dox[code_block.code].to_owned();
let sess = ParseSess::with_span_handler(handler, sm);
@@ -67,12 +67,11 @@ fn check_rust_syntax(
return;
}
- let Some(local_id) = item.item_id.as_def_id().and_then(|x| x.as_local())
- else {
- // We don't need to check the syntax for other crates so returning
- // without doing anything should not be a problem.
- return;
- };
+ let Some(local_id) = item.item_id.as_def_id().and_then(|x| x.as_local()) else {
+ // We don't need to check the syntax for other crates so returning
+ // without doing anything should not be a problem.
+ return;
+ };
let empty_block = code_block.lang_string == Default::default() && code_block.is_fenced;
let is_ignore = code_block.lang_string.ignore != markdown::Ignore::None;
@@ -108,7 +107,7 @@ fn check_rust_syntax(
// just give a `help` instead.
lint.span_help(
sp.from_inner(InnerSpan::new(0, 3)),
- format!("{}: ```text", explanation),
+ format!("{explanation}: ```text"),
);
} else if empty_block {
lint.span_suggestion(
@@ -119,7 +118,7 @@ fn check_rust_syntax(
);
}
} else if empty_block || is_ignore {
- lint.help(format!("{}: ```text", explanation));
+ lint.help(format!("{explanation}: ```text"));
}
// FIXME(#67563): Provide more context for these errors by displaying the spans inline.
@@ -161,7 +160,7 @@ impl Emitter for BufferEmitter {
.translate_message(&diag.message[0].0, &fluent_args)
.unwrap_or_else(|e| panic!("{e}"));
- buffer.messages.push(format!("error from rustc: {}", translated_main_message));
+ buffer.messages.push(format!("error from rustc: {translated_main_message}"));
if diag.is_error() {
buffer.has_errors = true;
}
diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs
index 5273f52bc..c135c584c 100644
--- a/src/librustdoc/passes/lint/html_tags.rs
+++ b/src/librustdoc/passes/lint/html_tags.rs
@@ -14,7 +14,9 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
let tcx = cx.tcx;
let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.item_id)
// If non-local, no need to check anything.
- else { return };
+ else {
+ return;
+ };
let dox = item.doc_value();
if !dox.is_empty() {
let report_diag = |msg: String, range: &Range<usize>, is_open_tag: bool| {
@@ -153,7 +155,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
let t = t.to_lowercase();
!ALLOWED_UNCLOSED.contains(&t.as_str())
}) {
- report_diag(format!("unclosed HTML tag `{}`", tag), range, true);
+ report_diag(format!("unclosed HTML tag `{tag}`"), range, true);
}
if let Some(range) = is_in_comment {
@@ -192,14 +194,14 @@ fn drop_tag(
// `tags` is used as a queue, meaning that everything after `pos` is included inside it.
// So `<h2><h3></h2>` will look like `["h2", "h3"]`. So when closing `h2`, we will still
// have `h3`, meaning the tag wasn't closed as it should have.
- f(format!("unclosed HTML tag `{}`", last_tag_name), &last_tag_span, true);
+ f(format!("unclosed HTML tag `{last_tag_name}`"), &last_tag_span, true);
}
// Remove the `tag_name` that was originally closed
tags.pop();
} else {
// It can happen for example in this case: `<h2></script></h2>` (the `h2` tag isn't required
// but it helps for the visualization).
- f(format!("unopened HTML tag `{}`", tag_name), &range, false);
+ f(format!("unopened HTML tag `{tag_name}`"), &range, false);
}
}
@@ -353,7 +355,7 @@ fn extract_html_tag(
if let Some(quote_pos) = quote_pos {
let qr = Range { start: quote_pos, end: quote_pos };
f(
- format!("unclosed quoted HTML attribute on tag `{}`", tag_name),
+ format!("unclosed quoted HTML attribute on tag `{tag_name}`"),
&qr,
false,
);
@@ -366,7 +368,7 @@ fn extract_html_tag(
at == "svg" || at == "math"
});
if !valid {
- f(format!("invalid self-closing HTML tag `{}`", tag_name), &r, false);
+ f(format!("invalid self-closing HTML tag `{tag_name}`"), &r, false);
}
} else {
tags.push((tag_name, r));
diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs
new file mode 100644
index 000000000..67cd2cc97
--- /dev/null
+++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs
@@ -0,0 +1,347 @@
+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()?;
+
+ if explicit_link.ends_with(&display_link) || display_link.ends_with(&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,
+ }
+}
diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs
index 8a33e51b3..95273a225 100644
--- a/src/librustdoc/passes/propagate_doc_cfg.rs
+++ b/src/librustdoc/passes/propagate_doc_cfg.rs
@@ -38,8 +38,9 @@ impl<'a, 'tcx> CfgPropagator<'a, 'tcx> {
_ => return,
};
- let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local())
- else { return };
+ let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) else {
+ return;
+ };
if check_parent {
let expected_parent = self.cx.tcx.opt_local_parent(def_id);
diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs
index e2e38d3e7..81a90ed49 100644
--- a/src/librustdoc/passes/strip_hidden.rs
+++ b/src/librustdoc/passes/strip_hidden.rs
@@ -6,11 +6,11 @@ use rustc_span::symbol::sym;
use std::mem;
use crate::clean;
+use crate::clean::utils::inherits_doc_hidden;
use crate::clean::{Item, ItemIdSet};
use crate::core::DocContext;
use crate::fold::{strip_item, DocFolder};
use crate::passes::{ImplStripper, Pass};
-use crate::visit_ast::inherits_doc_hidden;
pub(crate) const STRIP_HIDDEN: Pass = Pass {
name: "strip-hidden",
@@ -42,6 +42,7 @@ pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clea
cache: &cx.cache,
is_json_output,
document_private: cx.render_options.document_private,
+ document_hidden: cx.render_options.document_hidden,
};
stripper.fold_crate(krate)
}
diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs
index 4c992e948..468712ba3 100644
--- a/src/librustdoc/passes/strip_priv_imports.rs
+++ b/src/librustdoc/passes/strip_priv_imports.rs
@@ -13,5 +13,10 @@ pub(crate) const STRIP_PRIV_IMPORTS: Pass = Pass {
pub(crate) fn strip_priv_imports(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
let is_json_output = cx.output_format.is_json() && !cx.show_coverage;
- ImportStripper { tcx: cx.tcx, is_json_output }.fold_crate(krate)
+ ImportStripper {
+ tcx: cx.tcx,
+ is_json_output,
+ document_hidden: cx.render_options.document_hidden,
+ }
+ .fold_crate(krate)
}
diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs
index bb6dccb7c..3b6f484fd 100644
--- a/src/librustdoc/passes/strip_private.rs
+++ b/src/librustdoc/passes/strip_private.rs
@@ -28,8 +28,12 @@ pub(crate) fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) ->
is_json_output,
tcx: cx.tcx,
};
- krate =
- ImportStripper { tcx: cx.tcx, is_json_output }.fold_crate(stripper.fold_crate(krate));
+ krate = ImportStripper {
+ tcx: cx.tcx,
+ is_json_output,
+ document_hidden: cx.render_options.document_hidden,
+ }
+ .fold_crate(stripper.fold_crate(krate));
}
// strip all impls referencing private items
@@ -39,6 +43,7 @@ pub(crate) fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) ->
cache: &cx.cache,
is_json_output,
document_private: cx.render_options.document_private,
+ document_hidden: cx.render_options.document_hidden,
};
stripper.fold_crate(krate)
}
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index 90c361d9d..64a4ace5b 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -3,6 +3,7 @@ use rustc_hir::def_id::DefId;
use rustc_middle::ty::{TyCtxt, Visibility};
use std::mem;
+use crate::clean::utils::inherits_doc_hidden;
use crate::clean::{self, Item, ItemId, ItemIdSet};
use crate::fold::{strip_item, DocFolder};
use crate::formats::cache::Cache;
@@ -151,6 +152,7 @@ pub(crate) struct ImplStripper<'a, 'tcx> {
pub(crate) cache: &'a Cache,
pub(crate) is_json_output: bool,
pub(crate) document_private: bool,
+ pub(crate) document_hidden: bool,
}
impl<'a> ImplStripper<'a, '_> {
@@ -162,7 +164,13 @@ impl<'a> ImplStripper<'a, '_> {
// If the "for" item is exported and the impl block isn't `#[doc(hidden)]`, then we
// need to keep it.
self.cache.effective_visibilities.is_exported(self.tcx, for_def_id)
- && !item.is_doc_hidden()
+ && (self.document_hidden
+ || ((!item.is_doc_hidden()
+ && for_def_id
+ .as_local()
+ .map(|def_id| !inherits_doc_hidden(self.tcx, def_id, None))
+ .unwrap_or(true))
+ || self.cache.inlined_items.contains(&for_def_id)))
} else {
false
}
@@ -231,6 +239,7 @@ impl<'a> DocFolder for ImplStripper<'a, '_> {
pub(crate) struct ImportStripper<'tcx> {
pub(crate) tcx: TyCtxt<'tcx>,
pub(crate) is_json_output: bool,
+ pub(crate) document_hidden: bool,
}
impl<'tcx> ImportStripper<'tcx> {
@@ -247,8 +256,12 @@ impl<'tcx> ImportStripper<'tcx> {
impl<'tcx> DocFolder for ImportStripper<'tcx> {
fn fold_item(&mut self, i: Item) -> Option<Item> {
match *i.kind {
- clean::ImportItem(imp) if self.import_should_be_hidden(&i, &imp) => None,
- clean::ImportItem(_) if i.is_doc_hidden() => None,
+ clean::ImportItem(imp)
+ if !self.document_hidden && self.import_should_be_hidden(&i, &imp) =>
+ {
+ None
+ }
+ // clean::ImportItem(_) if !self.document_hidden && i.is_doc_hidden() => None,
clean::ExternCrateItem { .. } | clean::ImportItem(..)
if i.visibility(self.tcx) != Some(Visibility::Public) =>
{
diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs
index d2fa7769b..534c6eebb 100644
--- a/src/librustdoc/scrape_examples.rs
+++ b/src/librustdoc/scrape_examples.rs
@@ -169,7 +169,7 @@ where
};
let ident_span = path.ident.span;
- (tcx.type_of(def_id).subst_identity(), call_span, ident_span)
+ (tcx.type_of(def_id).instantiate_identity(), call_span, ident_span)
}
_ => {
return;
@@ -255,7 +255,7 @@ where
let fn_key = tcx.def_path_hash(*def_id);
let fn_entries = self.calls.entry(fn_key).or_default();
- trace!("Including expr: {:?}", call_span);
+ trace!("Including expr: {call_span:?}");
let enclosing_item_span =
source_map.span_extend_to_prev_char(enclosing_item_span, '\n', false);
let location =
@@ -345,7 +345,7 @@ pub(crate) fn load_call_locations(
let inner = || {
let mut all_calls: AllCallLocations = FxHashMap::default();
for path in with_examples {
- let bytes = fs::read(&path).map_err(|e| format!("{} (for path {})", e, path))?;
+ let bytes = fs::read(&path).map_err(|e| format!("{e} (for path {path})"))?;
let mut decoder = MemDecoder::new(&bytes, 0);
let calls = AllCallLocations::decode(&mut decoder);
@@ -358,7 +358,7 @@ pub(crate) fn load_call_locations(
};
inner().map_err(|e: String| {
- diag.err(format!("failed to load examples: {}", e));
+ diag.err(format!("failed to load examples: {e}"));
1
})
}
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index fcf591a93..549fd67e3 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -16,6 +16,7 @@ use rustc_span::Span;
use std::mem;
+use crate::clean::utils::{inherits_doc_hidden, should_ignore_res};
use crate::clean::{cfg::Cfg, reexport_chain, AttributesExt, NestedAttributesExt};
use crate::core;
@@ -35,6 +36,8 @@ pub(crate) struct Module<'hir> {
(LocalDefId, Option<Symbol>),
(&'hir hir::Item<'hir>, Option<Symbol>, Option<LocalDefId>),
>,
+ /// Same as for `items`.
+ pub(crate) inlined_foreigns: FxIndexMap<(DefId, Option<Symbol>), (Res, LocalDefId)>,
pub(crate) foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option<Symbol>)>,
}
@@ -54,6 +57,7 @@ impl Module<'_> {
import_id,
mods: Vec::new(),
items: FxIndexMap::default(),
+ inlined_foreigns: FxIndexMap::default(),
foreigns: Vec::new(),
}
}
@@ -70,33 +74,6 @@ fn def_id_to_path(tcx: TyCtxt<'_>, did: DefId) -> Vec<Symbol> {
std::iter::once(crate_name).chain(relative).collect()
}
-pub(crate) fn inherits_doc_hidden(
- tcx: TyCtxt<'_>,
- mut def_id: LocalDefId,
- stop_at: Option<LocalDefId>,
-) -> bool {
- let hir = tcx.hir();
- while let Some(id) = tcx.opt_local_parent(def_id) {
- if let Some(stop_at) = stop_at && id == stop_at {
- return false;
- }
- def_id = id;
- if tcx.is_doc_hidden(def_id.to_def_id()) {
- return true;
- } else if let Some(node) = hir.find_by_def_id(def_id) &&
- matches!(
- node,
- hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }),
- )
- {
- // `impl` blocks stand a bit on their own: unless they have `#[doc(hidden)]` directly
- // on them, they don't inherit it from the parent context.
- return false;
- }
- }
- false
-}
-
pub(crate) struct RustdocVisitor<'a, 'tcx> {
cx: &'a mut core::DocContext<'tcx>,
view_item_stack: LocalDefIdSet,
@@ -203,7 +180,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
/// 1. The items which are not glob imports/reexports.
/// 2. The glob imports/reexports.
fn visit_mod_contents(&mut self, def_id: LocalDefId, m: &'tcx hir::Mod<'tcx>) {
- debug!("Going through module {:?}", m);
+ debug!("Going through module {m:?}");
// Keep track of if there were any private modules in the path.
let orig_inside_public_path = self.inside_public_path;
self.inside_public_path &= self.cx.tcx.local_visibility(def_id).is_public();
@@ -226,7 +203,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
}
}
self.inside_public_path = orig_inside_public_path;
- debug!("Leaving module {:?}", m);
+ debug!("Leaving module {m:?}");
}
/// Tries to resolve the target of a `pub use` statement and inlines the
@@ -262,34 +239,44 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
return false;
};
+ let document_hidden = self.cx.render_options.document_hidden;
let use_attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(def_id));
// Don't inline `doc(hidden)` imports so they can be stripped at a later stage.
let is_no_inline = use_attrs.lists(sym::doc).has_word(sym::no_inline)
- || use_attrs.lists(sym::doc).has_word(sym::hidden);
+ || (document_hidden && use_attrs.lists(sym::doc).has_word(sym::hidden));
if is_no_inline {
return false;
}
- // For cross-crate impl inlining we need to know whether items are
- // reachable in documentation -- a previously unreachable item can be
- // made reachable by cross-crate inlining which we're checking here.
- // (this is done here because we need to know this upfront).
- if !ori_res_did.is_local() && !is_no_inline {
- crate::visit_lib::lib_embargo_visit_item(self.cx, ori_res_did);
- return false;
- }
-
+ let is_hidden = !document_hidden && tcx.is_doc_hidden(ori_res_did);
let Some(res_did) = ori_res_did.as_local() else {
- return false;
+ // For cross-crate impl inlining we need to know whether items are
+ // reachable in documentation -- a previously unreachable item can be
+ // made reachable by cross-crate inlining which we're checking here.
+ // (this is done here because we need to know this upfront).
+ crate::visit_lib::lib_embargo_visit_item(self.cx, ori_res_did);
+ if is_hidden || glob {
+ return false;
+ }
+ // We store inlined foreign items otherwise, it'd mean that the `use` item would be kept
+ // around. It's not a problem unless this `use` imports both a local AND a foreign item.
+ // If a local item is inlined, its `use` is not supposed to still be around in `clean`,
+ // which would make appear the `use` in the generated documentation like the local item
+ // was not inlined even though it actually was.
+ self.modules
+ .last_mut()
+ .unwrap()
+ .inlined_foreigns
+ .insert((ori_res_did, renamed), (res, def_id));
+ return true;
};
let is_private = !self.cx.cache.effective_visibilities.is_directly_public(tcx, ori_res_did);
- let is_hidden = tcx.is_doc_hidden(ori_res_did);
let item = tcx.hir().get_by_def_id(res_did);
if !please_inline {
- let inherits_hidden = inherits_doc_hidden(tcx, res_did, None);
+ let inherits_hidden = !document_hidden && inherits_doc_hidden(tcx, res_did, None);
// Only inline if requested or if the item would otherwise be stripped.
if (!is_private && !inherits_hidden) || (
is_hidden &&
@@ -313,7 +300,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
return false;
}
- let inlined = match tcx.hir().get_by_def_id(res_did) {
+ let inlined = match item {
// Bang macros are handled a bit on their because of how they are handled by the
// compiler. If they have `#[doc(hidden)]` and the re-export doesn't have
// `#[doc(inline)]`, then we don't inline it.
@@ -345,7 +332,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
};
self.view_item_stack.remove(&res_did);
if inlined {
- self.cx.cache.inlined_items.insert(res_did.to_def_id());
+ self.cx.cache.inlined_items.insert(ori_res_did);
}
inlined
}
@@ -359,8 +346,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
import_def_id: LocalDefId,
target_def_id: LocalDefId,
) -> bool {
+ if self.cx.render_options.document_hidden {
+ return true;
+ }
let tcx = self.cx.tcx;
- let item_def_id = reexport_chain(tcx, import_def_id, target_def_id)
+ let item_def_id = reexport_chain(tcx, import_def_id, target_def_id.to_def_id())
.iter()
.flat_map(|reexport| reexport.id())
.map(|id| id.expect_local())
@@ -404,7 +394,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
renamed: Option<Symbol>,
import_id: Option<LocalDefId>,
) {
- debug!("visiting item {:?}", item);
+ debug!("visiting item {item:?}");
if self.inside_body {
// Only impls can be "seen" outside a body. For example:
//
@@ -450,7 +440,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
for &res in &path.res {
// Struct and variant constructors and proc macro stubs always show up alongside
// their definitions, we've already processed them so just discard these.
- if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = res {
+ if should_ignore_res(res) {
continue;
}
@@ -479,7 +469,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
continue;
}
}
-
self.add_to_current_mod(item, renamed, import_id);
}
}
diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs
index fd4f92541..82c974661 100644
--- a/src/librustdoc/visit_lib.rs
+++ b/src/librustdoc/visit_lib.rs
@@ -33,6 +33,7 @@ pub(crate) fn lib_embargo_visit_item(cx: &mut DocContext<'_>, def_id: DefId) {
tcx: cx.tcx,
extern_public: &mut cx.cache.effective_visibilities.extern_public,
visited_mods: Default::default(),
+ document_hidden: cx.render_options.document_hidden,
}
.visit_item(def_id)
}
@@ -45,6 +46,7 @@ struct LibEmbargoVisitor<'a, 'tcx> {
extern_public: &'a mut DefIdSet,
// Keeps track of already visited modules, in case a module re-exports its parent
visited_mods: DefIdSet,
+ document_hidden: bool,
}
impl LibEmbargoVisitor<'_, '_> {
@@ -63,7 +65,7 @@ impl LibEmbargoVisitor<'_, '_> {
}
fn visit_item(&mut self, def_id: DefId) {
- if !self.tcx.is_doc_hidden(def_id) {
+ if self.document_hidden || !self.tcx.is_doc_hidden(def_id) {
self.extern_public.insert(def_id);
if self.tcx.def_kind(def_id) == DefKind::Mod {
self.visit_mod(def_id);