Fix broken handling of primitive items
- Fix broken handling of primitive associated items - Remove fragment hack Fixes 83083 - more logging - Update CrateNum hacks The CrateNum has no relation to where in the dependency tree the crate is, only when it's loaded. Explicitly special-case core instead of assuming it will be the first DefId. - Update and add tests - Cache calculation of primitive locations This could possibly be avoided by passing a Cache into collect_intra_doc_links; but that's a much larger change, and doesn't seem valuable other than for this.
This commit is contained in:
parent
f78acaee03
commit
cb7e527692
@ -461,60 +461,20 @@ impl Item {
|
|||||||
.map_or(&[][..], |v| v.as_slice())
|
.map_or(&[][..], |v| v.as_slice())
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|ItemLink { link: s, link_text, did, ref fragment }| {
|
.filter_map(|ItemLink { link: s, link_text, did, ref fragment }| {
|
||||||
match did {
|
debug!(?did);
|
||||||
Some(did) => {
|
if let Ok((mut href, ..)) = href(*did, cx) {
|
||||||
if let Ok((mut href, ..)) = href(*did, cx) {
|
debug!(?href);
|
||||||
if let Some(ref fragment) = *fragment {
|
if let Some(ref fragment) = *fragment {
|
||||||
href.push('#');
|
href.push('#');
|
||||||
href.push_str(fragment);
|
href.push_str(fragment);
|
||||||
}
|
|
||||||
Some(RenderedLink {
|
|
||||||
original_text: s.clone(),
|
|
||||||
new_text: link_text.clone(),
|
|
||||||
href,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// FIXME(83083): using fragments as a side-channel for
|
|
||||||
// primitive names is very unfortunate
|
|
||||||
None => {
|
|
||||||
let relative_to = &cx.current;
|
|
||||||
if let Some(ref fragment) = *fragment {
|
|
||||||
let url = match cx.cache().extern_locations.get(&self.def_id.krate()) {
|
|
||||||
Some(&ExternalLocation::Local) => {
|
|
||||||
if relative_to[0] == "std" {
|
|
||||||
let depth = relative_to.len() - 1;
|
|
||||||
"../".repeat(depth)
|
|
||||||
} else {
|
|
||||||
let depth = relative_to.len();
|
|
||||||
format!("{}std/", "../".repeat(depth))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(ExternalLocation::Remote(ref s)) => {
|
|
||||||
format!("{}/std/", s.trim_end_matches('/'))
|
|
||||||
}
|
|
||||||
Some(ExternalLocation::Unknown) | None => {
|
|
||||||
format!("{}/std/", crate::DOC_RUST_LANG_ORG_CHANNEL)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// This is a primitive so the url is done "by hand".
|
|
||||||
let tail = fragment.find('#').unwrap_or_else(|| fragment.len());
|
|
||||||
Some(RenderedLink {
|
|
||||||
original_text: s.clone(),
|
|
||||||
new_text: link_text.clone(),
|
|
||||||
href: format!(
|
|
||||||
"{}primitive.{}.html{}",
|
|
||||||
url,
|
|
||||||
&fragment[..tail],
|
|
||||||
&fragment[tail..]
|
|
||||||
),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
panic!("This isn't a primitive?!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Some(RenderedLink {
|
||||||
|
original_text: s.clone(),
|
||||||
|
new_text: link_text.clone(),
|
||||||
|
href,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
@ -531,18 +491,10 @@ impl Item {
|
|||||||
.get(&self.def_id)
|
.get(&self.def_id)
|
||||||
.map_or(&[][..], |v| v.as_slice())
|
.map_or(&[][..], |v| v.as_slice())
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|ItemLink { link: s, link_text, did, fragment }| {
|
.map(|ItemLink { link: s, link_text, .. }| RenderedLink {
|
||||||
// FIXME(83083): using fragments as a side-channel for
|
original_text: s.clone(),
|
||||||
// primitive names is very unfortunate
|
new_text: link_text.clone(),
|
||||||
if did.is_some() || fragment.is_some() {
|
href: String::new(),
|
||||||
Some(RenderedLink {
|
|
||||||
original_text: s.clone(),
|
|
||||||
new_text: link_text.clone(),
|
|
||||||
href: String::new(),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
@ -963,7 +915,7 @@ crate struct Attributes {
|
|||||||
crate other_attrs: Vec<ast::Attribute>,
|
crate other_attrs: Vec<ast::Attribute>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
/// A link that has not yet been rendered.
|
/// A link that has not yet been rendered.
|
||||||
///
|
///
|
||||||
/// This link will be turned into a rendered link by [`Item::links`].
|
/// This link will be turned into a rendered link by [`Item::links`].
|
||||||
@ -975,7 +927,7 @@ crate struct ItemLink {
|
|||||||
/// This may not be the same as `link` if there was a disambiguator
|
/// This may not be the same as `link` if there was a disambiguator
|
||||||
/// in an intra-doc link (e.g. \[`fn@f`\])
|
/// in an intra-doc link (e.g. \[`fn@f`\])
|
||||||
pub(crate) link_text: String,
|
pub(crate) link_text: String,
|
||||||
pub(crate) did: Option<DefId>,
|
pub(crate) did: DefId,
|
||||||
/// The url fragment to append to the link
|
/// The url fragment to append to the link
|
||||||
pub(crate) fragment: Option<String>,
|
pub(crate) fragment: Option<String>,
|
||||||
}
|
}
|
||||||
@ -1802,6 +1754,39 @@ impl PrimitiveType {
|
|||||||
Never => sym::never,
|
Never => sym::never,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the DefId of the module with `doc(primitive)` for this primitive type.
|
||||||
|
/// Panics if there is no such module.
|
||||||
|
///
|
||||||
|
/// This gives precedence to primitives defined in the current crate, and deprioritizes primitives defined in `core`,
|
||||||
|
/// but otherwise, if multiple crates define the same primitive, there is no guarantee of which will be picked.
|
||||||
|
/// In particular, if a crate depends on both `std` and another crate that also defines `doc(primitive)`, then
|
||||||
|
/// it's entirely random whether `std` or the other crate is picked. (no_std crates are usually fine unless multiple dependencies define a primitive.)
|
||||||
|
crate fn primitive_locations(tcx: TyCtxt<'_>) -> &FxHashMap<PrimitiveType, DefId> {
|
||||||
|
static PRIMITIVE_LOCATIONS: OnceCell<FxHashMap<PrimitiveType, DefId>> = OnceCell::new();
|
||||||
|
PRIMITIVE_LOCATIONS.get_or_init(|| {
|
||||||
|
let mut primitive_locations = FxHashMap::default();
|
||||||
|
// NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate.
|
||||||
|
// This is a degenerate case that I don't plan to support.
|
||||||
|
for &crate_num in tcx.crates(()) {
|
||||||
|
let e = ExternalCrate { crate_num };
|
||||||
|
let crate_name = e.name(tcx);
|
||||||
|
debug!(?crate_num, ?crate_name);
|
||||||
|
for &(def_id, prim) in &e.primitives(tcx) {
|
||||||
|
// HACK: try to link to std instead where possible
|
||||||
|
if crate_name == sym::core && primitive_locations.get(&prim).is_some() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
primitive_locations.insert(prim, def_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
|
||||||
|
for (def_id, prim) in local_primitives {
|
||||||
|
primitive_locations.insert(prim, def_id);
|
||||||
|
}
|
||||||
|
primitive_locations
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ast::IntTy> for PrimitiveType {
|
impl From<ast::IntTy> for PrimitiveType {
|
||||||
|
@ -6,7 +6,7 @@ use rustc_middle::middle::privacy::AccessLevels;
|
|||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
|
|
||||||
use crate::clean::{self, GetDefId, ItemId};
|
use crate::clean::{self, GetDefId, ItemId, PrimitiveType};
|
||||||
use crate::config::RenderOptions;
|
use crate::config::RenderOptions;
|
||||||
use crate::fold::DocFolder;
|
use crate::fold::DocFolder;
|
||||||
use crate::formats::item_type::ItemType;
|
use crate::formats::item_type::ItemType;
|
||||||
@ -159,17 +159,16 @@ impl Cache {
|
|||||||
self.external_paths.insert(e.def_id(), (vec![name.to_string()], ItemType::Module));
|
self.external_paths.insert(e.def_id(), (vec![name.to_string()], ItemType::Module));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache where all known primitives have their documentation located.
|
// FIXME: avoid this clone (requires implementing Default manually)
|
||||||
//
|
self.primitive_locations = PrimitiveType::primitive_locations(tcx).clone();
|
||||||
// Favor linking to as local extern as possible, so iterate all crates in
|
for (prim, &def_id) in &self.primitive_locations {
|
||||||
// reverse topological order.
|
let crate_name = tcx.crate_name(def_id.krate);
|
||||||
for &e in krate.externs.iter().rev() {
|
// Recall that we only allow primitive modules to be at the root-level of the crate.
|
||||||
for &(def_id, prim) in &e.primitives(tcx) {
|
// If that restriction is ever lifted, this will have to include the relative paths instead.
|
||||||
self.primitive_locations.insert(prim, def_id);
|
self.external_paths.insert(
|
||||||
}
|
def_id,
|
||||||
}
|
(vec![crate_name.to_string(), prim.as_sym().to_string()], ItemType::Primitive),
|
||||||
for &(def_id, prim) in &krate.primitives {
|
);
|
||||||
self.primitive_locations.insert(prim, def_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
krate = CacheBuilder { tcx, cache: self }.fold_crate(krate);
|
krate = CacheBuilder { tcx, cache: self }.fold_crate(krate);
|
||||||
|
@ -509,7 +509,11 @@ crate fn href_with_root_path(
|
|||||||
if shortty == ItemType::Module { fqp } else { &fqp[..fqp.len() - 1] }
|
if shortty == ItemType::Module { fqp } else { &fqp[..fqp.len() - 1] }
|
||||||
}
|
}
|
||||||
|
|
||||||
if !did.is_local() && !cache.access_levels.is_public(did) && !cache.document_private {
|
if !did.is_local()
|
||||||
|
&& !cache.access_levels.is_public(did)
|
||||||
|
&& !cache.document_private
|
||||||
|
&& !cache.primitive_locations.values().any(|&id| id == did)
|
||||||
|
{
|
||||||
return Err(HrefError::Private);
|
return Err(HrefError::Private);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -517,6 +521,7 @@ crate fn href_with_root_path(
|
|||||||
let (fqp, shortty, mut url_parts) = match cache.paths.get(&did) {
|
let (fqp, shortty, mut url_parts) = match cache.paths.get(&did) {
|
||||||
Some(&(ref fqp, shortty)) => (fqp, shortty, {
|
Some(&(ref fqp, shortty)) => (fqp, shortty, {
|
||||||
let module_fqp = to_module_fqp(shortty, fqp);
|
let module_fqp = to_module_fqp(shortty, fqp);
|
||||||
|
debug!(?fqp, ?shortty, ?module_fqp);
|
||||||
href_relative_parts(module_fqp, relative_to)
|
href_relative_parts(module_fqp, relative_to)
|
||||||
}),
|
}),
|
||||||
None => {
|
None => {
|
||||||
@ -548,6 +553,7 @@ crate fn href_with_root_path(
|
|||||||
url_parts.insert(0, root);
|
url_parts.insert(0, root);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
debug!(?url_parts);
|
||||||
let last = &fqp.last().unwrap()[..];
|
let last = &fqp.last().unwrap()[..];
|
||||||
let filename;
|
let filename;
|
||||||
match shortty {
|
match shortty {
|
||||||
|
@ -30,9 +30,7 @@ impl JsonRenderer<'_> {
|
|||||||
.get(&item.def_id)
|
.get(&item.def_id)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
.filter_map(|clean::ItemLink { link, did, .. }| {
|
.map(|clean::ItemLink { link, did, .. }| (link.clone(), from_item_id((*did).into())))
|
||||||
did.map(|did| (link.clone(), from_item_id(did.into())))
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
let docs = item.attrs.collapsed_doc_value();
|
let docs = item.attrs.collapsed_doc_value();
|
||||||
let attrs = item
|
let attrs = item
|
||||||
|
@ -14,7 +14,7 @@ use rustc_hir::def::{
|
|||||||
};
|
};
|
||||||
use rustc_hir::def_id::{CrateNum, DefId};
|
use rustc_hir::def_id::{CrateNum, DefId};
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_middle::{bug, ty};
|
use rustc_middle::{bug, span_bug, ty};
|
||||||
use rustc_resolve::ParentScope;
|
use rustc_resolve::ParentScope;
|
||||||
use rustc_session::lint::Lint;
|
use rustc_session::lint::Lint;
|
||||||
use rustc_span::hygiene::{MacroKind, SyntaxContext};
|
use rustc_span::hygiene::{MacroKind, SyntaxContext};
|
||||||
@ -98,14 +98,10 @@ impl Res {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn def_id(self) -> DefId {
|
fn def_id(self, tcx: TyCtxt<'_>) -> DefId {
|
||||||
self.opt_def_id().expect("called def_id() on a primitive")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn opt_def_id(self) -> Option<DefId> {
|
|
||||||
match self {
|
match self {
|
||||||
Res::Def(_, id) => Some(id),
|
Res::Def(_, id) => id,
|
||||||
Res::Primitive(_) => None,
|
Res::Primitive(prim) => *PrimitiveType::primitive_locations(tcx).get(&prim).unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,10 +233,7 @@ enum AnchorFailure {
|
|||||||
/// link, Rustdoc disallows having a user-specified anchor.
|
/// link, Rustdoc disallows having a user-specified anchor.
|
||||||
///
|
///
|
||||||
/// Most of the time this is fine, because you can just link to the page of
|
/// Most of the time this is fine, because you can just link to the page of
|
||||||
/// the item if you want to provide your own anchor. For primitives, though,
|
/// the item if you want to provide your own anchor.
|
||||||
/// rustdoc uses the anchor as a side channel to know which page to link to;
|
|
||||||
/// it doesn't show up in the generated link. Ideally, rustdoc would remove
|
|
||||||
/// this limitation, allowing you to link to subheaders on primitives.
|
|
||||||
RustdocAnchorConflict(Res),
|
RustdocAnchorConflict(Res),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,7 +381,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
|||||||
ty::AssocKind::Const => "associatedconstant",
|
ty::AssocKind::Const => "associatedconstant",
|
||||||
ty::AssocKind::Type => "associatedtype",
|
ty::AssocKind::Type => "associatedtype",
|
||||||
};
|
};
|
||||||
let fragment = format!("{}#{}.{}", prim_ty.as_sym(), out, item_name);
|
let fragment = format!("{}.{}", out, item_name);
|
||||||
(Res::Primitive(prim_ty), fragment, Some((kind.as_def_kind(), item.def_id)))
|
(Res::Primitive(prim_ty), fragment, Some((kind.as_def_kind(), item.def_id)))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -475,14 +468,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
|||||||
return handle_variant(self.cx, res, extra_fragment);
|
return handle_variant(self.cx, res, extra_fragment);
|
||||||
}
|
}
|
||||||
// Not a trait item; just return what we found.
|
// Not a trait item; just return what we found.
|
||||||
Res::Primitive(ty) => {
|
|
||||||
if extra_fragment.is_some() {
|
|
||||||
return Err(ErrorKind::AnchorFailure(
|
|
||||||
AnchorFailure::RustdocAnchorConflict(res),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return Ok((res, Some(ty.as_sym().to_string())));
|
|
||||||
}
|
|
||||||
_ => return Ok((res, extra_fragment.clone())),
|
_ => return Ok((res, extra_fragment.clone())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -517,6 +502,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
|||||||
let (res, fragment, side_channel) =
|
let (res, fragment, side_channel) =
|
||||||
self.resolve_associated_item(ty_res, item_name, ns, module_id)?;
|
self.resolve_associated_item(ty_res, item_name, ns, module_id)?;
|
||||||
let result = if extra_fragment.is_some() {
|
let result = if extra_fragment.is_some() {
|
||||||
|
// NOTE: can never be a primitive since `side_channel.is_none()` only when `res`
|
||||||
|
// is a trait (and the side channel DefId is always an associated item).
|
||||||
let diag_res = side_channel.map_or(res, |(k, r)| Res::Def(k, r));
|
let diag_res = side_channel.map_or(res, |(k, r)| Res::Def(k, r));
|
||||||
Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(diag_res)))
|
Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(diag_res)))
|
||||||
} else {
|
} else {
|
||||||
@ -1152,7 +1139,7 @@ impl LinkCollector<'_, '_> {
|
|||||||
module_id = DefId { krate, index: CRATE_DEF_INDEX };
|
module_id = DefId { krate, index: CRATE_DEF_INDEX };
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mut res, mut fragment) = self.resolve_with_disambiguator_cached(
|
let (mut res, fragment) = self.resolve_with_disambiguator_cached(
|
||||||
ResolutionInfo {
|
ResolutionInfo {
|
||||||
module_id,
|
module_id,
|
||||||
dis: disambiguator,
|
dis: disambiguator,
|
||||||
@ -1174,16 +1161,7 @@ impl LinkCollector<'_, '_> {
|
|||||||
if let Some(prim) = resolve_primitive(path_str, TypeNS) {
|
if let Some(prim) = resolve_primitive(path_str, TypeNS) {
|
||||||
// `prim@char`
|
// `prim@char`
|
||||||
if matches!(disambiguator, Some(Disambiguator::Primitive)) {
|
if matches!(disambiguator, Some(Disambiguator::Primitive)) {
|
||||||
if fragment.is_some() {
|
|
||||||
anchor_failure(
|
|
||||||
self.cx,
|
|
||||||
diag_info,
|
|
||||||
AnchorFailure::RustdocAnchorConflict(prim),
|
|
||||||
);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
res = prim;
|
res = prim;
|
||||||
fragment = Some(prim.name(self.cx.tcx).to_string());
|
|
||||||
} else {
|
} else {
|
||||||
// `[char]` when a `char` module is in scope
|
// `[char]` when a `char` module is in scope
|
||||||
let candidates = vec![res, prim];
|
let candidates = vec![res, prim];
|
||||||
@ -1303,12 +1281,17 @@ impl LinkCollector<'_, '_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(ItemLink { link: ori_link.link, link_text, did: None, fragment })
|
Some(ItemLink {
|
||||||
|
link: ori_link.link,
|
||||||
|
link_text,
|
||||||
|
did: res.def_id(self.cx.tcx),
|
||||||
|
fragment,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
Res::Def(kind, id) => {
|
Res::Def(kind, id) => {
|
||||||
verify(kind, id)?;
|
verify(kind, id)?;
|
||||||
let id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id));
|
let id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id));
|
||||||
Some(ItemLink { link: ori_link.link, link_text, did: Some(id), fragment })
|
Some(ItemLink { link: ori_link.link, link_text, did: id, fragment })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2069,8 +2052,11 @@ fn anchor_failure(cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>, failure: A
|
|||||||
diag.span_label(sp, "invalid anchor");
|
diag.span_label(sp, "invalid anchor");
|
||||||
}
|
}
|
||||||
if let AnchorFailure::RustdocAnchorConflict(Res::Primitive(_)) = failure {
|
if let AnchorFailure::RustdocAnchorConflict(Res::Primitive(_)) = failure {
|
||||||
diag.note("this restriction may be lifted in a future release");
|
if let Some(sp) = sp {
|
||||||
diag.note("see https://github.com/rust-lang/rust/issues/83083 for more information");
|
span_bug!(sp, "anchors should be allowed now");
|
||||||
|
} else {
|
||||||
|
bug!("anchors should be allowed now");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -2198,10 +2184,11 @@ fn handle_variant(
|
|||||||
use rustc_middle::ty::DefIdTree;
|
use rustc_middle::ty::DefIdTree;
|
||||||
|
|
||||||
if extra_fragment.is_some() {
|
if extra_fragment.is_some() {
|
||||||
|
// NOTE: `res` can never be a primitive since this function is only called when `tcx.def_kind(res) == DefKind::Variant`.
|
||||||
return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res)));
|
return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res)));
|
||||||
}
|
}
|
||||||
cx.tcx
|
cx.tcx
|
||||||
.parent(res.def_id())
|
.parent(res.def_id(cx.tcx))
|
||||||
.map(|parent| {
|
.map(|parent| {
|
||||||
let parent_def = Res::Def(DefKind::Enum, parent);
|
let parent_def = Res::Def(DefKind::Enum, parent);
|
||||||
let variant = cx.tcx.expect_variant_res(res.as_hir_res().unwrap());
|
let variant = cx.tcx.expect_variant_res(res.as_hir_res().unwrap());
|
||||||
|
@ -37,13 +37,3 @@ pub fn bar() {}
|
|||||||
/// Damn enum's variants: [Enum::A#whatever].
|
/// Damn enum's variants: [Enum::A#whatever].
|
||||||
//~^ ERROR `Enum::A#whatever` contains an anchor
|
//~^ ERROR `Enum::A#whatever` contains an anchor
|
||||||
pub fn enum_link() {}
|
pub fn enum_link() {}
|
||||||
|
|
||||||
/// Primitives?
|
|
||||||
///
|
|
||||||
/// [u32#hello]
|
|
||||||
//~^ ERROR `u32#hello` contains an anchor
|
|
||||||
pub fn x() {}
|
|
||||||
|
|
||||||
/// [prim@usize#x]
|
|
||||||
//~^ ERROR `prim@usize#x` contains an anchor
|
|
||||||
pub mod usize {}
|
|
||||||
|
@ -1,19 +1,3 @@
|
|||||||
error: `prim@usize#x` contains an anchor, but links to builtin types are already anchored
|
|
||||||
--> $DIR/anchors.rs:47:6
|
|
||||||
|
|
|
||||||
LL | /// [prim@usize#x]
|
|
||||||
| ^^^^^^^^^^--
|
|
||||||
| |
|
|
||||||
| invalid anchor
|
|
||||||
|
|
|
||||||
note: the lint level is defined here
|
|
||||||
--> $DIR/anchors.rs:1:9
|
|
||||||
|
|
|
||||||
LL | #![deny(rustdoc::broken_intra_doc_links)]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
= note: this restriction may be lifted in a future release
|
|
||||||
= note: see https://github.com/rust-lang/rust/issues/83083 for more information
|
|
||||||
|
|
||||||
error: `Foo::f#hola` contains an anchor, but links to fields are already anchored
|
error: `Foo::f#hola` contains an anchor, but links to fields are already anchored
|
||||||
--> $DIR/anchors.rs:25:15
|
--> $DIR/anchors.rs:25:15
|
||||||
|
|
|
|
||||||
@ -21,6 +5,12 @@ LL | /// Or maybe [Foo::f#hola].
|
|||||||
| ^^^^^^-----
|
| ^^^^^^-----
|
||||||
| |
|
| |
|
||||||
| invalid anchor
|
| invalid anchor
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/anchors.rs:1:9
|
||||||
|
|
|
||||||
|
LL | #![deny(rustdoc::broken_intra_doc_links)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: `hello#people#!` contains multiple anchors
|
error: `hello#people#!` contains multiple anchors
|
||||||
--> $DIR/anchors.rs:31:28
|
--> $DIR/anchors.rs:31:28
|
||||||
@ -38,16 +28,5 @@ LL | /// Damn enum's variants: [Enum::A#whatever].
|
|||||||
| |
|
| |
|
||||||
| invalid anchor
|
| invalid anchor
|
||||||
|
|
||||||
error: `u32#hello` contains an anchor, but links to builtin types are already anchored
|
error: aborting due to 3 previous errors
|
||||||
--> $DIR/anchors.rs:43:6
|
|
||||||
|
|
|
||||||
LL | /// [u32#hello]
|
|
||||||
| ^^^------
|
|
||||||
| |
|
|
||||||
| invalid anchor
|
|
||||||
|
|
|
||||||
= note: this restriction may be lifted in a future release
|
|
||||||
= note: see https://github.com/rust-lang/rust/issues/83083 for more information
|
|
||||||
|
|
||||||
error: aborting due to 5 previous errors
|
|
||||||
|
|
||||||
|
@ -1,6 +1,14 @@
|
|||||||
// compile-flags: -Cmetadata=aux
|
// compile-flags: -Cmetadata=aux
|
||||||
|
|
||||||
#![doc(html_root_url = "http://example.com/")]
|
#![doc(html_root_url = "http://example.com/")]
|
||||||
|
#![feature(lang_items)]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
#[lang = "eh_personality"]
|
||||||
|
fn foo() {}
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn bar(_: &core::panic::PanicInfo) -> ! { loop {} }
|
||||||
|
|
||||||
/// dox
|
/// dox
|
||||||
#[doc(primitive = "pointer")]
|
#[doc(primitive = "pointer")]
|
||||||
|
@ -10,3 +10,15 @@ pub struct Something;
|
|||||||
///
|
///
|
||||||
/// To link to [Something#Anchor!]
|
/// To link to [Something#Anchor!]
|
||||||
pub struct SomeOtherType;
|
pub struct SomeOtherType;
|
||||||
|
|
||||||
|
/// Primitives?
|
||||||
|
///
|
||||||
|
/// [u32#hello]
|
||||||
|
// @has anchors/fn.x.html
|
||||||
|
// @has - '//a/@href' '{{channel}}/std/primitive.u32.html#hello'
|
||||||
|
pub fn x() {}
|
||||||
|
|
||||||
|
/// [prim@usize#x]
|
||||||
|
// @has anchors/usize/index.html
|
||||||
|
// @has - '//a/@href' '{{channel}}/std/primitive.usize.html#x'
|
||||||
|
pub mod usize {}
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
#![no_core]
|
#![no_core]
|
||||||
#![crate_type="rlib"]
|
#![crate_type="rlib"]
|
||||||
|
|
||||||
|
#[doc(primitive = "char")]
|
||||||
|
/// Some char docs
|
||||||
|
mod char {}
|
||||||
|
|
||||||
#[lang = "char"]
|
#[lang = "char"]
|
||||||
impl char {
|
impl char {
|
||||||
pub fn len_utf8(self) -> usize {
|
pub fn len_utf8(self) -> usize {
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
#![crate_type = "rlib"]
|
#![crate_type = "rlib"]
|
||||||
|
|
||||||
// @has prim_methods_external_core/index.html
|
// @has prim_methods_external_core/index.html
|
||||||
// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char'
|
// @has - '//*[@id="main"]//a[@href="../my_core/primitive.char.html"]' 'char'
|
||||||
// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
|
// @has - '//*[@id="main"]//a[@href="../my_core/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
|
||||||
|
|
||||||
//! A [`char`] and its [`char::len_utf8`].
|
//! A [`char`] and its [`char::len_utf8`].
|
||||||
|
|
||||||
|
@ -5,10 +5,13 @@
|
|||||||
|
|
||||||
|
|
||||||
// @has prim_methods_local/index.html
|
// @has prim_methods_local/index.html
|
||||||
// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char'
|
// @has - '//*[@id="main"]//a[@href="primitive.char.html"]' 'char'
|
||||||
// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
|
// @has - '//*[@id="main"]//a[@href="primitive.char.html#method.len_utf8"]' 'char::len_utf8'
|
||||||
|
|
||||||
//! A [`char`] and its [`char::len_utf8`].
|
//! A [prim@`char`] and its [`char::len_utf8`].
|
||||||
|
|
||||||
|
#[doc(primitive = "char")]
|
||||||
|
mod char {}
|
||||||
|
|
||||||
#[lang = "char"]
|
#[lang = "char"]
|
||||||
impl char {
|
impl char {
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
/// [Self::f]
|
/// [Self::f]
|
||||||
/// [Self::MAX]
|
/// [Self::MAX]
|
||||||
// @has intra_link_prim_self/primitive.usize.html
|
// @has intra_link_prim_self/primitive.usize.html
|
||||||
// @has - '//a[@href="{{channel}}/std/primitive.usize.html#method.f"]' 'Self::f'
|
// @has - '//a[@href="primitive.usize.html#method.f"]' 'Self::f'
|
||||||
// @has - '//a[@href="{{channel}}/std/primitive.usize.html#associatedconstant.MAX"]' 'Self::MAX'
|
// @has - '//a[@href="primitive.usize.html#associatedconstant.MAX"]' 'Self::MAX'
|
||||||
impl usize {
|
impl usize {
|
||||||
/// Some docs
|
/// Some docs
|
||||||
pub fn f() {}
|
pub fn f() {}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
// aux-build:issue-15318.rs
|
// aux-build:issue-15318.rs
|
||||||
// ignore-cross-compile
|
// ignore-cross-compile
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
extern crate issue_15318;
|
extern crate issue_15318;
|
||||||
|
|
||||||
|
6
src/test/rustdoc/no_std-primitive.rs
Normal file
6
src/test/rustdoc/no_std-primitive.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#![no_std]
|
||||||
|
|
||||||
|
/// Link to [intra-doc link][u8]
|
||||||
|
// @has 'no_std_primitive/fn.foo.html' '//a[@href="{{channel}}/core/primitive.u8.html"]' 'intra-doc link'
|
||||||
|
// @has - '//a[@href="{{channel}}/core/primitive.u8.html"]' 'u8'
|
||||||
|
pub fn foo() -> u8 {}
|
@ -1,5 +1,6 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
// @has no_std/fn.foo.html '//a/[@href="{{channel}}/core/primitive.u8.html"]' 'u8'
|
// @has no_std/fn.foo.html '//a/[@href="{{channel}}/core/primitive.u8.html"]' 'u8'
|
||||||
// Link to [u8]
|
// @has no_std/fn.foo.html '//a/[@href="{{channel}}/core/primitive.u8.html"]' 'primitive link'
|
||||||
|
/// Link to [primitive link][u8]
|
||||||
pub fn foo() -> u8 {}
|
pub fn foo() -> u8 {}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user