Auto merge of #76955 - jyn514:refactor-diagnostics, r=euclio

Refactor and fix intra-doc link diagnostics, and fix links to primitives

Closes https://github.com/rust-lang/rust/issues/76925, closes https://github.com/rust-lang/rust/issues/76693, closes https://github.com/rust-lang/rust/issues/76692.

Originally I only meant to fix #76925. But the hack with `has_primitive` was so bad it was easier to fix the primitive issues than to try and work around it.

Note that this still has one bug: `std::primitive::i32::MAX` does not resolve. However, this fixes the ICE so I'm fine with fixing the link in a later PR.

This is part of a series of refactors to make #76467 possible.

This is best reviewed commit-by-commit; it has detailed commit messages.

r? `@euclio`
This commit is contained in:
bors 2020-09-27 08:12:29 +00:00
commit 71bdb84817
11 changed files with 329 additions and 279 deletions

View File

@ -2004,6 +2004,30 @@ pub enum PrimTy {
Char, Char,
} }
impl PrimTy {
pub fn name_str(self) -> &'static str {
match self {
PrimTy::Int(i) => i.name_str(),
PrimTy::Uint(u) => u.name_str(),
PrimTy::Float(f) => f.name_str(),
PrimTy::Str => "str",
PrimTy::Bool => "bool",
PrimTy::Char => "char",
}
}
pub fn name(self) -> Symbol {
match self {
PrimTy::Int(i) => i.name(),
PrimTy::Uint(u) => u.name(),
PrimTy::Float(f) => f.name(),
PrimTy::Str => sym::str,
PrimTy::Bool => sym::bool,
PrimTy::Char => sym::char,
}
}
}
#[derive(Debug, HashStable_Generic)] #[derive(Debug, HashStable_Generic)]
pub struct BareFnTy<'hir> { pub struct BareFnTy<'hir> {
pub unsafety: Unsafety, pub unsafety: Unsafety,

View File

@ -57,45 +57,16 @@ enum ResolutionFailure<'a> {
/// This resolved, but with the wrong namespace. /// This resolved, but with the wrong namespace.
/// `Namespace` is the expected namespace (as opposed to the actual). /// `Namespace` is the expected namespace (as opposed to the actual).
WrongNamespace(Res, Namespace), WrongNamespace(Res, Namespace),
/// This has a partial resolution, but is not in the TypeNS and so cannot /// The link failed to resolve. `resolution_failure` should look to see if there's
/// have associated items or fields. /// a more helpful error that can be given.
CannotHaveAssociatedItems(Res, Namespace), NotResolved { module_id: DefId, partial_res: Option<Res>, unresolved: Cow<'a, str> },
/// `name` is the base name of the path (not necessarily the whole link)
NotInScope { module_id: DefId, name: Cow<'a, str> },
/// this is a primitive type without an impls (no associated methods)
/// when will this actually happen?
/// the `Res` is the primitive it resolved to
NoPrimitiveImpl(Res, String),
/// `[u8::not_found]`
/// the `Res` is the primitive it resolved to
NoPrimitiveAssocItem { res: Res, prim_name: &'a str, assoc_item: Symbol },
/// `[S::not_found]`
/// the `String` is the associated item that wasn't found
NoAssocItem(Res, Symbol),
/// should not ever happen /// should not ever happen
NoParentItem, NoParentItem,
/// this could be an enum variant, but the last path fragment wasn't resolved.
/// the `String` is the variant that didn't exist
NotAVariant(Res, Symbol),
/// used to communicate that this should be ignored, but shouldn't be reported to the user /// used to communicate that this should be ignored, but shouldn't be reported to the user
Dummy, Dummy,
} }
impl ResolutionFailure<'a> { impl ResolutionFailure<'a> {
// A partial or full resolution
fn res(&self) -> Option<Res> {
use ResolutionFailure::*;
match self {
NoPrimitiveAssocItem { res, .. }
| NoAssocItem(res, _)
| NoPrimitiveImpl(res, _)
| NotAVariant(res, _)
| WrongNamespace(res, _)
| CannotHaveAssociatedItems(res, _) => Some(*res),
NotInScope { .. } | NoParentItem | Dummy => None,
}
}
// This resolved fully (not just partially) but is erroneous for some other reason // This resolved fully (not just partially) but is erroneous for some other reason
fn full_res(&self) -> Option<Res> { fn full_res(&self) -> Option<Res> {
match self { match self {
@ -130,22 +101,25 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
path_str: &'path str, path_str: &'path str,
current_item: &Option<String>, current_item: &Option<String>,
module_id: DefId, module_id: DefId,
extra_fragment: &Option<String>,
) -> Result<(Res, Option<String>), ErrorKind<'path>> { ) -> Result<(Res, Option<String>), ErrorKind<'path>> {
let cx = self.cx; let cx = self.cx;
let no_res = || ResolutionFailure::NotResolved {
module_id,
partial_res: None,
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 mut split = path_str.rsplitn(3, "::");
let variant_field_name = split let (variant_field_str, variant_field_name) = split
.next() .next()
.map(|f| Symbol::intern(f)) .map(|f| (f, Symbol::intern(f)))
.expect("fold_item should ensure link is non-empty"); .expect("fold_item should ensure link is non-empty");
let variant_name = let (variant_str, variant_name) =
// we're not sure this is a variant at all, so use the full string // we're not sure this is a variant at all, so use the full string
split.next().map(|f| Symbol::intern(f)).ok_or_else(|| ResolutionFailure::NotInScope { // If there's no second component, the link looks like `[path]`.
module_id, // So there's no partial res and we should say the whole link failed to resolve.
name: path_str.into(), split.next().map(|f| (f, Symbol::intern(f))).ok_or_else(no_res)?;
})?;
let path = split let path = split
.next() .next()
.map(|f| { .map(|f| {
@ -156,10 +130,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
} }
f.to_owned() f.to_owned()
}) })
.ok_or_else(|| ResolutionFailure::NotInScope { // If there's no third component, we saw `[a::b]` before and it failed to resolve.
module_id, // So there's no partial res.
name: variant_name.to_string().into(), .ok_or_else(no_res)?;
})?;
let ty_res = cx let ty_res = cx
.enter_resolver(|resolver| { .enter_resolver(|resolver| {
resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id)
@ -167,7 +140,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
.map(|(_, res)| res) .map(|(_, res)| res)
.unwrap_or(Res::Err); .unwrap_or(Res::Err);
if let Res::Err = ty_res { if let Res::Err = ty_res {
return Err(ResolutionFailure::NotInScope { module_id, name: path.into() }.into()); return Err(no_res().into());
} }
let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); let ty_res = ty_res.map_id(|_| panic!("unexpected node_id"));
match ty_res { match ty_res {
@ -190,38 +163,27 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
ty_res, ty_res,
Some(format!( Some(format!(
"variant.{}.field.{}", "variant.{}.field.{}",
variant_name, variant_field_name variant_str, variant_field_name
)), )),
)) ))
} else { } else {
Err(ResolutionFailure::NotAVariant(ty_res, variant_field_name).into()) Err(ResolutionFailure::NotResolved {
module_id,
partial_res: Some(Res::Def(DefKind::Enum, def.did)),
unresolved: variant_field_str.into(),
}
.into())
} }
} }
_ => unreachable!(), _ => unreachable!(),
} }
} }
// `variant_field` looks at 3 different path segments in a row. _ => Err(ResolutionFailure::NotResolved {
// But `NoAssocItem` assumes there are only 2. Check to see if there's module_id,
// an intermediate segment that resolves. partial_res: Some(ty_res),
_ => { unresolved: variant_str.into(),
let intermediate_path = format!("{}::{}", path, variant_name);
// NOTE: we have to be careful here, because we're already in `resolve`.
// We know this doesn't recurse forever because we use a shorter path each time.
// NOTE: this uses `TypeNS` because nothing else has a valid path segment after
let kind = if let Some(intermediate) = self.check_full_res(
TypeNS,
&intermediate_path,
module_id,
current_item,
extra_fragment,
) {
ResolutionFailure::NoAssocItem(intermediate, variant_field_name)
} else {
// Even with the shorter path, it didn't resolve, so say that.
ResolutionFailure::NoAssocItem(ty_res, variant_name)
};
Err(kind.into())
} }
.into()),
} }
} }
@ -242,11 +204,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
false, false,
) { ) {
if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind { if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind {
return Some(Ok(res.map_id(|_| panic!("unexpected id")))); return Ok(res.map_id(|_| panic!("unexpected id")));
} }
} }
if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) { if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) {
return Some(Ok(res.map_id(|_| panic!("unexpected id")))); return Ok(res.map_id(|_| panic!("unexpected id")));
} }
debug!("resolving {} as a macro in the module {:?}", path_str, module_id); debug!("resolving {} as a macro in the module {:?}", path_str, module_id);
if let Ok((_, res)) = if let Ok((_, res)) =
@ -255,28 +217,14 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
// don't resolve builtins like `#[derive]` // don't resolve builtins like `#[derive]`
if let Res::Def(..) = res { if let Res::Def(..) = res {
let res = res.map_id(|_| panic!("unexpected node_id")); let res = res.map_id(|_| panic!("unexpected node_id"));
return Some(Ok(res)); return Ok(res);
} }
} }
None Err(ResolutionFailure::NotResolved {
}) module_id,
// This weird control flow is so we don't borrow the resolver more than once at a time partial_res: None,
.unwrap_or_else(|| { unresolved: path_str.into(),
let mut split = path_str.rsplitn(2, "::"); })
if let Some((parent, base)) = split.next().and_then(|x| Some((split.next()?, x))) {
if let Some(res) = self.check_full_res(TypeNS, parent, module_id, &None, &None) {
return Err(if matches!(res, Res::PrimTy(_)) {
ResolutionFailure::NoPrimitiveAssocItem {
res,
prim_name: parent,
assoc_item: Symbol::intern(base),
}
} else {
ResolutionFailure::NoAssocItem(res, Symbol::intern(base))
});
}
}
Err(ResolutionFailure::NotInScope { module_id, name: path_str.into() })
}) })
} }
@ -312,13 +260,13 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
return handle_variant(cx, res, extra_fragment); return handle_variant(cx, res, extra_fragment);
} }
// Not a trait item; just return what we found. // Not a trait item; just return what we found.
Res::PrimTy(..) => { Res::PrimTy(ty) => {
if extra_fragment.is_some() { if extra_fragment.is_some() {
return Err(ErrorKind::AnchorFailure( return Err(ErrorKind::AnchorFailure(
AnchorFailure::RustdocAnchorConflict(res), AnchorFailure::RustdocAnchorConflict(res),
)); ));
} }
return Ok((res, Some(path_str.to_owned()))); return Ok((res, Some(ty.name_str().to_owned())));
} }
Res::Def(DefKind::Mod, _) => { Res::Def(DefKind::Mod, _) => {
return Ok((res, extra_fragment.clone())); return Ok((res, extra_fragment.clone()));
@ -331,6 +279,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
if value != (ns == ValueNS) { if value != (ns == ValueNS) {
return Err(ResolutionFailure::WrongNamespace(res, ns).into()); return Err(ResolutionFailure::WrongNamespace(res, ns).into());
} }
// FIXME: why is this necessary?
} else if let Some((path, prim)) = is_primitive(path_str, ns) { } else if let Some((path, prim)) = is_primitive(path_str, ns) {
if extra_fragment.is_some() { if extra_fragment.is_some() {
return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(prim))); return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(prim)));
@ -341,7 +290,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
// Try looking for methods and associated items. // Try looking for methods and associated items.
let mut split = path_str.rsplitn(2, "::"); let mut split = path_str.rsplitn(2, "::");
// this can be an `unwrap()` because we ensure the link is never empty // this can be an `unwrap()` because we ensure the link is never empty
let item_name = Symbol::intern(split.next().unwrap()); let (item_str, item_name) = split.next().map(|i| (i, Symbol::intern(i))).unwrap();
let path_root = split let path_root = split
.next() .next()
.map(|f| { .map(|f| {
@ -356,12 +305,20 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
// So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved. // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved.
.ok_or_else(|| { .ok_or_else(|| {
debug!("found no `::`, assumming {} was correctly not in scope", item_name); debug!("found no `::`, assumming {} was correctly not in scope", item_name);
ResolutionFailure::NotInScope { module_id, name: item_name.to_string().into() } ResolutionFailure::NotResolved {
module_id,
partial_res: None,
unresolved: item_str.into(),
}
})?; })?;
if let Some((path, prim)) = is_primitive(&path_root, TypeNS) { if let Some((path, prim)) = is_primitive(&path_root, TypeNS) {
let impls = primitive_impl(cx, &path) let impls =
.ok_or_else(|| ResolutionFailure::NoPrimitiveImpl(prim, path_root.into()))?; primitive_impl(cx, &path).ok_or_else(|| ResolutionFailure::NotResolved {
module_id,
partial_res: Some(prim),
unresolved: item_str.into(),
})?;
for &impl_ in impls { for &impl_ in impls {
let link = cx let link = cx
.tcx .tcx
@ -377,7 +334,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
ty::AssocKind::Const => "associatedconstant", ty::AssocKind::Const => "associatedconstant",
ty::AssocKind::Type => "associatedtype", ty::AssocKind::Type => "associatedtype",
}) })
.map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_name)))); .map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_str))));
if let Some(link) = link { if let Some(link) = link {
return Ok(link); return Ok(link);
} }
@ -388,10 +345,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
item_name, item_name,
ns.descr() ns.descr()
); );
return Err(ResolutionFailure::NoPrimitiveAssocItem { return Err(ResolutionFailure::NotResolved {
res: prim, module_id,
prim_name: path, partial_res: Some(prim),
assoc_item: item_name, unresolved: item_str.into(),
} }
.into()); .into());
} }
@ -405,25 +362,14 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
let ty_res = match ty_res { let ty_res = match ty_res {
Err(()) | Ok(Res::Err) => { Err(()) | Ok(Res::Err) => {
return if ns == Namespace::ValueNS { return if ns == Namespace::ValueNS {
self.variant_field(path_str, current_item, module_id, extra_fragment) self.variant_field(path_str, current_item, module_id)
} else { } else {
// See if it only broke because of the namespace. Err(ResolutionFailure::NotResolved {
let kind = cx.enter_resolver(|resolver| { module_id,
// NOTE: this doesn't use `check_full_res` because we explicitly want to ignore `TypeNS` (we already checked it) partial_res: None,
for &ns in &[MacroNS, ValueNS] { unresolved: path_root.into(),
match resolver }
.resolve_str_path_error(DUMMY_SP, &path_root, ns, module_id) .into())
{
Ok((_, Res::Err)) | Err(()) => {}
Ok((_, res)) => {
let res = res.map_id(|_| panic!("unexpected node_id"));
return ResolutionFailure::CannotHaveAssociatedItems(res, ns);
}
}
}
ResolutionFailure::NotInScope { module_id, name: path_root.into() }
});
Err(kind.into())
}; };
} }
Ok(res) => res, Ok(res) => res,
@ -473,7 +419,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
// but the disambiguator logic expects the associated item. // but the disambiguator logic expects the associated item.
// Store the kind in a side channel so that only the disambiguator logic looks at it. // Store the kind in a side channel so that only the disambiguator logic looks at it.
self.kind_side_channel.set(Some((kind.as_def_kind(), id))); self.kind_side_channel.set(Some((kind.as_def_kind(), id)));
Ok((ty_res, Some(format!("{}.{}", out, item_name)))) Ok((ty_res, Some(format!("{}.{}", out, item_str))))
}) })
} else if ns == Namespace::ValueNS { } else if ns == Namespace::ValueNS {
debug!("looking for variants or fields named {} for {:?}", item_name, did); debug!("looking for variants or fields named {} for {:?}", item_name, did);
@ -516,7 +462,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
} }
} else { } else {
// We already know this isn't in ValueNS, so no need to check variant_field // We already know this isn't in ValueNS, so no need to check variant_field
return Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into()); return Err(ResolutionFailure::NotResolved {
module_id,
partial_res: Some(ty_res),
unresolved: item_str.into(),
}
.into());
} }
} }
Res::Def(DefKind::Trait, did) => cx Res::Def(DefKind::Trait, did) => cx
@ -540,16 +491,21 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res))) Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res)))
} else { } else {
let res = Res::Def(item.kind.as_def_kind(), item.def_id); let res = Res::Def(item.kind.as_def_kind(), item.def_id);
Ok((res, Some(format!("{}.{}", kind, item_name)))) Ok((res, Some(format!("{}.{}", kind, item_str))))
} }
}), }),
_ => None, _ => None,
}; };
res.unwrap_or_else(|| { res.unwrap_or_else(|| {
if ns == Namespace::ValueNS { if ns == Namespace::ValueNS {
self.variant_field(path_str, current_item, module_id, extra_fragment) self.variant_field(path_str, current_item, module_id)
} else { } else {
Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into()) Err(ResolutionFailure::NotResolved {
module_id,
partial_res: Some(ty_res),
unresolved: item_str.into(),
}
.into())
} }
}) })
} }
@ -1044,12 +1000,12 @@ impl LinkCollector<'_, '_> {
suggest_disambiguator(resolved, diag, path_str, dox, sp, &link_range); suggest_disambiguator(resolved, diag, path_str, dox, sp, &link_range);
}); });
}; };
if let Res::PrimTy(_) = res { if let Res::PrimTy(..) = res {
match disambiguator { match disambiguator {
Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => { Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {
item.attrs.links.push(ItemLink { item.attrs.links.push(ItemLink {
link: ori_link, link: ori_link,
link_text: path_str.to_owned(), link_text,
did: None, did: None,
fragment, fragment,
}); });
@ -1127,6 +1083,8 @@ impl LinkCollector<'_, '_> {
// We only looked in one namespace. Try to give a better error if possible. // We only looked in one namespace. Try to give a better error if possible.
if kind.full_res().is_none() { if kind.full_res().is_none() {
let other_ns = if ns == ValueNS { TypeNS } else { ValueNS }; let other_ns = if ns == ValueNS { TypeNS } else { ValueNS };
// FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator`
// See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach
for &new_ns in &[other_ns, MacroNS] { for &new_ns in &[other_ns, MacroNS] {
if let Some(res) = self.check_full_res( if let Some(res) = self.check_full_res(
new_ns, new_ns,
@ -1529,7 +1487,6 @@ fn resolution_failure(
dox, dox,
&link_range, &link_range,
|diag, sp| { |diag, sp| {
let in_scope = kinds.iter().any(|kind| kind.res().is_some());
let item = |res: Res| { let item = |res: Res| {
format!( format!(
"the {} `{}`", "the {} `{}`",
@ -1550,53 +1507,142 @@ fn resolution_failure(
// ignore duplicates // ignore duplicates
let mut variants_seen = SmallVec::<[_; 3]>::new(); let mut variants_seen = SmallVec::<[_; 3]>::new();
for mut failure in kinds { for mut failure in kinds {
// Check if _any_ parent of the path gets resolved.
// If so, report it and say the first which failed; if not, say the first path segment didn't resolve.
if let ResolutionFailure::NotInScope { module_id, name } = &mut failure {
let mut current = name.as_ref();
loop {
current = match current.rsplitn(2, "::").nth(1) {
Some(p) => p,
None => {
*name = current.to_owned().into();
break;
}
};
if let Some(res) =
collector.check_full_res(TypeNS, &current, *module_id, &None, &None)
{
failure = ResolutionFailure::NoAssocItem(res, Symbol::intern(current));
break;
}
}
}
let variant = std::mem::discriminant(&failure); let variant = std::mem::discriminant(&failure);
if variants_seen.contains(&variant) { if variants_seen.contains(&variant) {
continue; continue;
} }
variants_seen.push(variant); variants_seen.push(variant);
let note = match failure {
ResolutionFailure::NotInScope { module_id, name, .. } => { if let ResolutionFailure::NotResolved { module_id, partial_res, unresolved } =
if in_scope { &mut failure
continue; {
use DefKind::*;
let module_id = *module_id;
// FIXME(jynelson): this might conflict with my `Self` fix in #76467
// FIXME: maybe use itertools `collect_tuple` instead?
fn split(path: &str) -> Option<(&str, &str)> {
let mut splitter = path.rsplitn(2, "::");
splitter.next().and_then(|right| splitter.next().map(|left| (left, right)))
}
// Check if _any_ parent of the path gets resolved.
// If so, report it and say the first which failed; if not, say the first path segment didn't resolve.
let mut name = path_str;
'outer: loop {
let (start, end) = if let Some(x) = split(name) {
x
} else {
// avoid bug that marked [Quux::Z] as missing Z, not Quux
if partial_res.is_none() {
*unresolved = name.into();
}
break;
};
name = start;
for &ns in &[TypeNS, ValueNS, MacroNS] {
if let Some(res) =
collector.check_full_res(ns, &start, module_id, &None, &None)
{
debug!("found partial_res={:?}", res);
*partial_res = Some(res);
*unresolved = end.into();
break 'outer;
}
} }
// NOTE: uses an explicit `continue` so the `note:` will come before the `help:` *unresolved = end.into();
let module_name = collector.cx.tcx.item_name(module_id); }
let note = format!("no item named `{}` in `{}`", name, module_name);
let last_found_module = match *partial_res {
Some(Res::Def(DefKind::Mod, id)) => Some(id),
None => Some(module_id),
_ => None,
};
// See if this was a module: `[path]` or `[std::io::nope]`
if let Some(module) = last_found_module {
let module_name = collector.cx.tcx.item_name(module);
let note = format!(
"the module `{}` contains no item named `{}`",
module_name, unresolved
);
if let Some(span) = sp { if let Some(span) = sp {
diag.span_label(span, &note); diag.span_label(span, &note);
} else { } else {
diag.note(&note); diag.note(&note);
} }
// If the link has `::` in the path, assume it's meant to be an intra-doc link // If the link has `::` in it, assume it was meant to be an intra-doc link.
// Otherwise, the `[]` might be unrelated.
// FIXME: don't show this for autolinks (`<>`), `()` style links, or reference links
if !path_str.contains("::") { if !path_str.contains("::") {
// Otherwise, the `[]` might be unrelated.
// FIXME(https://github.com/raphlinus/pulldown-cmark/issues/373):
// don't show this for autolinks (`<>`), `()` style links, or reference links
diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#); diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#);
} }
continue; continue;
} }
// Otherwise, it must be an associated item or variant
let res = partial_res.expect("None case was handled by `last_found_module`");
let diagnostic_name;
let (kind, name) = match res {
Res::Def(kind, def_id) => {
diagnostic_name = collector.cx.tcx.item_name(def_id).as_str();
(Some(kind), &*diagnostic_name)
}
Res::PrimTy(ty) => (None, ty.name_str()),
_ => unreachable!("only ADTs and primitives are in scope at module level"),
};
let path_description = if let Some(kind) = kind {
match kind {
Mod | ForeignMod => "inner item",
Struct => "field or associated item",
Enum | Union => "variant or associated item",
Variant
| Field
| Closure
| Generator
| AssocTy
| AssocConst
| AssocFn
| Fn
| Macro(_)
| Const
| ConstParam
| ExternCrate
| Use
| LifetimeParam
| Ctor(_, _)
| AnonConst => {
let note = assoc_item_not_allowed(res);
if let Some(span) = sp {
diag.span_label(span, &note);
} else {
diag.note(&note);
}
return;
}
Trait | TyAlias | ForeignTy | OpaqueTy | TraitAlias | TyParam
| Static => "associated item",
Impl | GlobalAsm => unreachable!("not a path"),
}
} else {
"associated item"
};
let note = format!(
"the {} `{}` has no {} named `{}`",
res.descr(),
name,
disambiguator.map_or(path_description, |d| d.descr()),
unresolved,
);
if let Some(span) = sp {
diag.span_label(span, &note);
} else {
diag.note(&note);
}
continue;
}
let note = match failure {
ResolutionFailure::NotResolved { .. } => unreachable!("handled above"),
ResolutionFailure::Dummy => continue, ResolutionFailure::Dummy => continue,
ResolutionFailure::WrongNamespace(res, expected_ns) => { ResolutionFailure::WrongNamespace(res, expected_ns) => {
if let Res::Def(kind, _) = res { if let Res::Def(kind, _) = res {
@ -1621,79 +1667,6 @@ fn resolution_failure(
diag.level = rustc_errors::Level::Bug; diag.level = rustc_errors::Level::Bug;
"all intra doc links should have a parent item".to_owned() "all intra doc links should have a parent item".to_owned()
} }
ResolutionFailure::NoPrimitiveImpl(res, _) => format!(
"this link partially resolves to {}, which does not have any associated items",
item(res),
),
ResolutionFailure::NoPrimitiveAssocItem { prim_name, assoc_item, .. } => {
format!(
"the builtin type `{}` does not have an associated item named `{}`",
prim_name, assoc_item
)
}
ResolutionFailure::NoAssocItem(res, assoc_item) => {
use DefKind::*;
let (kind, def_id) = match res {
Res::Def(kind, def_id) => (kind, def_id),
x => unreachable!(
"primitives are covered above and other `Res` variants aren't possible at module scope: {:?}",
x,
),
};
let name = collector.cx.tcx.item_name(def_id);
let path_description = if let Some(disambiguator) = disambiguator {
disambiguator.descr()
} else {
match kind {
Mod | ForeignMod => "inner item",
Struct => "field or associated item",
Enum | Union => "variant or associated item",
Variant
| Field
| Closure
| Generator
| AssocTy
| AssocConst
| AssocFn
| Fn
| Macro(_)
| Const
| ConstParam
| ExternCrate
| Use
| LifetimeParam
| Ctor(_, _)
| AnonConst => {
let note = assoc_item_not_allowed(res);
if let Some(span) = sp {
diag.span_label(span, &note);
} else {
diag.note(&note);
}
return;
}
Trait | TyAlias | ForeignTy | OpaqueTy | TraitAlias | TyParam
| Static => "associated item",
Impl | GlobalAsm => unreachable!("not a path"),
}
};
format!(
"the {} `{}` has no {} named `{}`",
res.descr(),
name,
path_description,
assoc_item
)
}
ResolutionFailure::CannotHaveAssociatedItems(res, _) => {
assoc_item_not_allowed(res)
}
ResolutionFailure::NotAVariant(res, variant) => format!(
"this link partially resolves to {}, but there is no variant named {}",
item(res),
variant
),
}; };
if let Some(span) = sp { if let Some(span) = sp {
diag.span_label(span, &note); diag.span_label(span, &note);

View File

@ -2,7 +2,7 @@ error: unresolved link to `v2`
--> $DIR/deny-intra-link-resolution-failure.rs:3:6 --> $DIR/deny-intra-link-resolution-failure.rs:3:6
| |
LL | /// [v2] LL | /// [v2]
| ^^ no item named `v2` in `deny_intra_link_resolution_failure` | ^^ the module `deny_intra_link_resolution_failure` contains no item named `v2`
| |
note: the lint level is defined here note: the lint level is defined here
--> $DIR/deny-intra-link-resolution-failure.rs:1:9 --> $DIR/deny-intra-link-resolution-failure.rs:1:9

View File

@ -6,19 +6,23 @@
/// [path::to::nonexistent::module] /// [path::to::nonexistent::module]
//~^ ERROR unresolved link //~^ ERROR unresolved link
//~| NOTE no item named `path` in `intra_link_errors` //~| NOTE `intra_link_errors` contains no item named `path`
/// [path::to::nonexistent::macro!] /// [path::to::nonexistent::macro!]
//~^ ERROR unresolved link //~^ ERROR unresolved link
//~| NOTE no item named `path` in `intra_link_errors` //~| NOTE `intra_link_errors` contains no item named `path`
/// [type@path::to::nonexistent::type] /// [type@path::to::nonexistent::type]
//~^ ERROR unresolved link //~^ ERROR unresolved link
//~| NOTE no item named `path` in `intra_link_errors` //~| NOTE `intra_link_errors` contains no item named `path`
/// [std::io::not::here] /// [std::io::not::here]
//~^ ERROR unresolved link //~^ ERROR unresolved link
//~| NOTE the module `io` has no inner item //~| NOTE `io` contains no item named `not`
/// [type@std::io::not::here]
//~^ ERROR unresolved link
//~| NOTE `io` contains no item named `not`
/// [std::io::Error::x] /// [std::io::Error::x]
//~^ ERROR unresolved link //~^ ERROR unresolved link
@ -32,6 +36,10 @@
//~^ ERROR unresolved link //~^ ERROR unresolved link
//~| NOTE `f` is a function, not a module //~| NOTE `f` is a function, not a module
/// [f::A!]
//~^ ERROR unresolved link
//~| NOTE `f` is a function, not a module
/// [S::A] /// [S::A]
//~^ ERROR unresolved link //~^ ERROR unresolved link
//~| NOTE struct `S` has no field or associated item //~| NOTE struct `S` has no field or associated item
@ -46,7 +54,16 @@
/// [u8::not_found] /// [u8::not_found]
//~^ ERROR unresolved link //~^ ERROR unresolved link
//~| NOTE the builtin type `u8` does not have an associated item named `not_found` //~| NOTE the builtin type `u8` has no associated item named `not_found`
/// [std::primitive::u8::not_found]
//~^ ERROR unresolved link
//~| NOTE the builtin type `u8` has no associated item named `not_found`
/// [type@Vec::into_iter]
//~^ ERROR unresolved link
//~| HELP to link to the associated function, add parentheses
//~| NOTE this link resolves to the associated function `into_iter`
/// [S!] /// [S!]
//~^ ERROR unresolved link //~^ ERROR unresolved link

View File

@ -2,7 +2,7 @@ error: unresolved link to `path::to::nonexistent::module`
--> $DIR/intra-link-errors.rs:7:6 --> $DIR/intra-link-errors.rs:7:6
| |
LL | /// [path::to::nonexistent::module] LL | /// [path::to::nonexistent::module]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in `intra_link_errors` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the module `intra_link_errors` contains no item named `path`
| |
note: the lint level is defined here note: the lint level is defined here
--> $DIR/intra-link-errors.rs:1:9 --> $DIR/intra-link-errors.rs:1:9
@ -14,64 +14,91 @@ error: unresolved link to `path::to::nonexistent::macro`
--> $DIR/intra-link-errors.rs:11:6 --> $DIR/intra-link-errors.rs:11:6
| |
LL | /// [path::to::nonexistent::macro!] LL | /// [path::to::nonexistent::macro!]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in `intra_link_errors` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the module `intra_link_errors` contains no item named `path`
error: unresolved link to `path::to::nonexistent::type` error: unresolved link to `path::to::nonexistent::type`
--> $DIR/intra-link-errors.rs:15:6 --> $DIR/intra-link-errors.rs:15:6
| |
LL | /// [type@path::to::nonexistent::type] LL | /// [type@path::to::nonexistent::type]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in `intra_link_errors` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the module `intra_link_errors` contains no item named `path`
error: unresolved link to `std::io::not::here` error: unresolved link to `std::io::not::here`
--> $DIR/intra-link-errors.rs:19:6 --> $DIR/intra-link-errors.rs:19:6
| |
LL | /// [std::io::not::here] LL | /// [std::io::not::here]
| ^^^^^^^^^^^^^^^^^^ the module `io` has no inner item named `not` | ^^^^^^^^^^^^^^^^^^ the module `io` contains no item named `not`
error: unresolved link to `std::io::not::here`
--> $DIR/intra-link-errors.rs:23:6
|
LL | /// [type@std::io::not::here]
| ^^^^^^^^^^^^^^^^^^^^^^^ the module `io` contains no item named `not`
error: unresolved link to `std::io::Error::x` error: unresolved link to `std::io::Error::x`
--> $DIR/intra-link-errors.rs:23:6 --> $DIR/intra-link-errors.rs:27:6
| |
LL | /// [std::io::Error::x] LL | /// [std::io::Error::x]
| ^^^^^^^^^^^^^^^^^ the struct `Error` has no field or associated item named `x` | ^^^^^^^^^^^^^^^^^ the struct `Error` has no field or associated item named `x`
error: unresolved link to `std::io::ErrorKind::x` error: unresolved link to `std::io::ErrorKind::x`
--> $DIR/intra-link-errors.rs:27:6 --> $DIR/intra-link-errors.rs:31:6
| |
LL | /// [std::io::ErrorKind::x] LL | /// [std::io::ErrorKind::x]
| ^^^^^^^^^^^^^^^^^^^^^ the enum `ErrorKind` has no variant or associated item named `x` | ^^^^^^^^^^^^^^^^^^^^^ the enum `ErrorKind` has no variant or associated item named `x`
error: unresolved link to `f::A` error: unresolved link to `f::A`
--> $DIR/intra-link-errors.rs:31:6 --> $DIR/intra-link-errors.rs:35:6
| |
LL | /// [f::A] LL | /// [f::A]
| ^^^^ `f` is a function, not a module or type, and cannot have associated items | ^^^^ `f` is a function, not a module or type, and cannot have associated items
error: unresolved link to `f::A`
--> $DIR/intra-link-errors.rs:39:6
|
LL | /// [f::A!]
| ^^^^^ `f` is a function, not a module or type, and cannot have associated items
error: unresolved link to `S::A` error: unresolved link to `S::A`
--> $DIR/intra-link-errors.rs:35:6 --> $DIR/intra-link-errors.rs:43:6
| |
LL | /// [S::A] LL | /// [S::A]
| ^^^^ the struct `S` has no field or associated item named `A` | ^^^^ the struct `S` has no field or associated item named `A`
error: unresolved link to `S::fmt` error: unresolved link to `S::fmt`
--> $DIR/intra-link-errors.rs:39:6 --> $DIR/intra-link-errors.rs:47:6
| |
LL | /// [S::fmt] LL | /// [S::fmt]
| ^^^^^^ the struct `S` has no field or associated item named `fmt` | ^^^^^^ the struct `S` has no field or associated item named `fmt`
error: unresolved link to `E::D` error: unresolved link to `E::D`
--> $DIR/intra-link-errors.rs:43:6 --> $DIR/intra-link-errors.rs:51:6
| |
LL | /// [E::D] LL | /// [E::D]
| ^^^^ the enum `E` has no variant or associated item named `D` | ^^^^ the enum `E` has no variant or associated item named `D`
error: unresolved link to `u8::not_found` error: unresolved link to `u8::not_found`
--> $DIR/intra-link-errors.rs:47:6 --> $DIR/intra-link-errors.rs:55:6
| |
LL | /// [u8::not_found] LL | /// [u8::not_found]
| ^^^^^^^^^^^^^ the builtin type `u8` does not have an associated item named `not_found` | ^^^^^^^^^^^^^ the builtin type `u8` has no associated item named `not_found`
error: unresolved link to `std::primitive::u8::not_found`
--> $DIR/intra-link-errors.rs:59:6
|
LL | /// [std::primitive::u8::not_found]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the builtin type `u8` has no associated item named `not_found`
error: unresolved link to `Vec::into_iter`
--> $DIR/intra-link-errors.rs:63:6
|
LL | /// [type@Vec::into_iter]
| ^^^^^^^^^^^^^^^^^^^
| |
| this link resolves to the associated function `into_iter`, which is not in the type namespace
| help: to link to the associated function, add parentheses: `Vec::into_iter()`
error: unresolved link to `S` error: unresolved link to `S`
--> $DIR/intra-link-errors.rs:51:6 --> $DIR/intra-link-errors.rs:68:6
| |
LL | /// [S!] LL | /// [S!]
| ^^ | ^^
@ -80,7 +107,7 @@ LL | /// [S!]
| help: to link to the struct, prefix with `struct@`: `struct@S` | help: to link to the struct, prefix with `struct@`: `struct@S`
error: unresolved link to `T::g` error: unresolved link to `T::g`
--> $DIR/intra-link-errors.rs:69:6 --> $DIR/intra-link-errors.rs:86:6
| |
LL | /// [type@T::g] LL | /// [type@T::g]
| ^^^^^^^^^ | ^^^^^^^^^
@ -89,13 +116,13 @@ LL | /// [type@T::g]
| help: to link to the associated function, add parentheses: `T::g()` | help: to link to the associated function, add parentheses: `T::g()`
error: unresolved link to `T::h` error: unresolved link to `T::h`
--> $DIR/intra-link-errors.rs:74:6 --> $DIR/intra-link-errors.rs:91:6
| |
LL | /// [T::h!] LL | /// [T::h!]
| ^^^^^ the trait `T` has no macro named `h` | ^^^^^ the trait `T` has no macro named `h`
error: unresolved link to `S::h` error: unresolved link to `S::h`
--> $DIR/intra-link-errors.rs:61:6 --> $DIR/intra-link-errors.rs:78:6
| |
LL | /// [type@S::h] LL | /// [type@S::h]
| ^^^^^^^^^ | ^^^^^^^^^
@ -104,7 +131,7 @@ LL | /// [type@S::h]
| help: to link to the associated function, add parentheses: `S::h()` | help: to link to the associated function, add parentheses: `S::h()`
error: unresolved link to `m` error: unresolved link to `m`
--> $DIR/intra-link-errors.rs:81:6 --> $DIR/intra-link-errors.rs:98:6
| |
LL | /// [m()] LL | /// [m()]
| ^^^ | ^^^
@ -112,5 +139,5 @@ LL | /// [m()]
| this link resolves to the macro `m`, which is not in the value namespace | this link resolves to the macro `m`, which is not in the value namespace
| help: to link to the macro, add an exclamation mark: `m!` | help: to link to the macro, add an exclamation mark: `m!`
error: aborting due to 16 previous errors error: aborting due to 20 previous errors

View File

@ -2,7 +2,7 @@ error: unresolved link to `i`
--> $DIR/intra-link-span-ice-55723.rs:9:10 --> $DIR/intra-link-span-ice-55723.rs:9:10
| |
LL | /// arr[i] LL | /// arr[i]
| ^ no item named `i` in `intra_link_span_ice_55723` | ^ the module `intra_link_span_ice_55723` contains no item named `i`
| |
note: the lint level is defined here note: the lint level is defined here
--> $DIR/intra-link-span-ice-55723.rs:1:9 --> $DIR/intra-link-span-ice-55723.rs:1:9

View File

@ -2,7 +2,7 @@ warning: unresolved link to `error`
--> $DIR/intra-links-warning-crlf.rs:7:6 --> $DIR/intra-links-warning-crlf.rs:7:6
| |
LL | /// [error] LL | /// [error]
| ^^^^^ no item named `error` in `intra_links_warning_crlf` | ^^^^^ the module `intra_links_warning_crlf` contains no item named `error`
| |
= note: `#[warn(broken_intra_doc_links)]` on by default = note: `#[warn(broken_intra_doc_links)]` on by default
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
@ -11,7 +11,7 @@ warning: unresolved link to `error1`
--> $DIR/intra-links-warning-crlf.rs:12:11 --> $DIR/intra-links-warning-crlf.rs:12:11
| |
LL | /// docs [error1] LL | /// docs [error1]
| ^^^^^^ no item named `error1` in `intra_links_warning_crlf` | ^^^^^^ the module `intra_links_warning_crlf` contains no item named `error1`
| |
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
@ -19,7 +19,7 @@ warning: unresolved link to `error2`
--> $DIR/intra-links-warning-crlf.rs:15:11 --> $DIR/intra-links-warning-crlf.rs:15:11
| |
LL | /// docs [error2] LL | /// docs [error2]
| ^^^^^^ no item named `error2` in `intra_links_warning_crlf` | ^^^^^^ the module `intra_links_warning_crlf` contains no item named `error2`
| |
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
@ -27,7 +27,7 @@ warning: unresolved link to `error`
--> $DIR/intra-links-warning-crlf.rs:23:20 --> $DIR/intra-links-warning-crlf.rs:23:20
| |
LL | * It also has an [error]. LL | * It also has an [error].
| ^^^^^ no item named `error` in `intra_links_warning_crlf` | ^^^^^ the module `intra_links_warning_crlf` contains no item named `error`
| |
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`

View File

@ -10,37 +10,37 @@ warning: unresolved link to `Bar::foo`
--> $DIR/intra-links-warning.rs:3:35 --> $DIR/intra-links-warning.rs:3:35
| |
LL | //! Test with [Foo::baz], [Bar::foo], ... LL | //! Test with [Foo::baz], [Bar::foo], ...
| ^^^^^^^^ no item named `Bar` in `intra_links_warning` | ^^^^^^^^ the module `intra_links_warning` contains no item named `Bar`
warning: unresolved link to `Uniooon::X` warning: unresolved link to `Uniooon::X`
--> $DIR/intra-links-warning.rs:6:13 --> $DIR/intra-links-warning.rs:6:13
| |
LL | //! , [Uniooon::X] and [Qux::Z]. LL | //! , [Uniooon::X] and [Qux::Z].
| ^^^^^^^^^^ no item named `Uniooon` in `intra_links_warning` | ^^^^^^^^^^ the module `intra_links_warning` contains no item named `Uniooon`
warning: unresolved link to `Qux::Z` warning: unresolved link to `Qux::Z`
--> $DIR/intra-links-warning.rs:6:30 --> $DIR/intra-links-warning.rs:6:30
| |
LL | //! , [Uniooon::X] and [Qux::Z]. LL | //! , [Uniooon::X] and [Qux::Z].
| ^^^^^^ no item named `Qux` in `intra_links_warning` | ^^^^^^ the module `intra_links_warning` contains no item named `Qux`
warning: unresolved link to `Uniooon::X` warning: unresolved link to `Uniooon::X`
--> $DIR/intra-links-warning.rs:10:14 --> $DIR/intra-links-warning.rs:10:14
| |
LL | //! , [Uniooon::X] and [Qux::Z]. LL | //! , [Uniooon::X] and [Qux::Z].
| ^^^^^^^^^^ no item named `Uniooon` in `intra_links_warning` | ^^^^^^^^^^ the module `intra_links_warning` contains no item named `Uniooon`
warning: unresolved link to `Qux::Z` warning: unresolved link to `Qux::Z`
--> $DIR/intra-links-warning.rs:10:31 --> $DIR/intra-links-warning.rs:10:31
| |
LL | //! , [Uniooon::X] and [Qux::Z]. LL | //! , [Uniooon::X] and [Qux::Z].
| ^^^^^^ no item named `Qux` in `intra_links_warning` | ^^^^^^ the module `intra_links_warning` contains no item named `Qux`
warning: unresolved link to `Qux:Y` warning: unresolved link to `Qux:Y`
--> $DIR/intra-links-warning.rs:14:13 --> $DIR/intra-links-warning.rs:14:13
| |
LL | /// [Qux:Y] LL | /// [Qux:Y]
| ^^^^^ no item named `Qux:Y` in `intra_links_warning` | ^^^^^ the module `intra_links_warning` contains no item named `Qux:Y`
| |
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
@ -48,7 +48,7 @@ warning: unresolved link to `error`
--> $DIR/intra-links-warning.rs:58:30 --> $DIR/intra-links-warning.rs:58:30
| |
LL | * time to introduce a link [error]*/ LL | * time to introduce a link [error]*/
| ^^^^^ no item named `error` in `intra_links_warning` | ^^^^^ the module `intra_links_warning` contains no item named `error`
| |
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
@ -56,7 +56,7 @@ warning: unresolved link to `error`
--> $DIR/intra-links-warning.rs:64:30 --> $DIR/intra-links-warning.rs:64:30
| |
LL | * time to introduce a link [error] LL | * time to introduce a link [error]
| ^^^^^ no item named `error` in `intra_links_warning` | ^^^^^ the module `intra_links_warning` contains no item named `error`
| |
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
@ -70,7 +70,7 @@ LL | #[doc = "single line [error]"]
single line [error] single line [error]
^^^^^ ^^^^^
= note: no item named `error` in `intra_links_warning` = note: the module `intra_links_warning` contains no item named `error`
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
warning: unresolved link to `error` warning: unresolved link to `error`
@ -83,7 +83,7 @@ LL | #[doc = "single line with \"escaping\" [error]"]
single line with "escaping" [error] single line with "escaping" [error]
^^^^^ ^^^^^
= note: no item named `error` in `intra_links_warning` = note: the module `intra_links_warning` contains no item named `error`
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
warning: unresolved link to `error` warning: unresolved link to `error`
@ -98,14 +98,14 @@ LL | | /// [error]
[error] [error]
^^^^^ ^^^^^
= note: no item named `error` in `intra_links_warning` = note: the module `intra_links_warning` contains no item named `error`
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
warning: unresolved link to `error1` warning: unresolved link to `error1`
--> $DIR/intra-links-warning.rs:80:11 --> $DIR/intra-links-warning.rs:80:11
| |
LL | /// docs [error1] LL | /// docs [error1]
| ^^^^^^ no item named `error1` in `intra_links_warning` | ^^^^^^ the module `intra_links_warning` contains no item named `error1`
| |
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
@ -113,7 +113,7 @@ warning: unresolved link to `error2`
--> $DIR/intra-links-warning.rs:82:11 --> $DIR/intra-links-warning.rs:82:11
| |
LL | /// docs [error2] LL | /// docs [error2]
| ^^^^^^ no item named `error2` in `intra_links_warning` | ^^^^^^ the module `intra_links_warning` contains no item named `error2`
| |
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
@ -121,7 +121,7 @@ warning: unresolved link to `BarA`
--> $DIR/intra-links-warning.rs:21:10 --> $DIR/intra-links-warning.rs:21:10
| |
LL | /// bar [BarA] bar LL | /// bar [BarA] bar
| ^^^^ no item named `BarA` in `intra_links_warning` | ^^^^ the module `intra_links_warning` contains no item named `BarA`
| |
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
@ -129,7 +129,7 @@ warning: unresolved link to `BarB`
--> $DIR/intra-links-warning.rs:27:9 --> $DIR/intra-links-warning.rs:27:9
| |
LL | * bar [BarB] bar LL | * bar [BarB] bar
| ^^^^ no item named `BarB` in `intra_links_warning` | ^^^^ the module `intra_links_warning` contains no item named `BarB`
| |
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
@ -137,7 +137,7 @@ warning: unresolved link to `BarC`
--> $DIR/intra-links-warning.rs:34:6 --> $DIR/intra-links-warning.rs:34:6
| |
LL | bar [BarC] bar LL | bar [BarC] bar
| ^^^^ no item named `BarC` in `intra_links_warning` | ^^^^ the module `intra_links_warning` contains no item named `BarC`
| |
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
@ -151,7 +151,7 @@ LL | #[doc = "Foo\nbar [BarD] bar\nbaz"]
bar [BarD] bar bar [BarD] bar
^^^^ ^^^^
= note: no item named `BarD` in `intra_links_warning` = note: the module `intra_links_warning` contains no item named `BarD`
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
warning: unresolved link to `BarF` warning: unresolved link to `BarF`
@ -167,7 +167,7 @@ LL | f!("Foo\nbar [BarF] bar\nbaz");
bar [BarF] bar bar [BarF] bar
^^^^ ^^^^
= note: no item named `BarF` in `intra_links_warning` = note: the module `intra_links_warning` contains no item named `BarF`
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

View File

@ -32,7 +32,7 @@ error: unresolved link to `error`
--> $DIR/lint-group.rs:9:29 --> $DIR/lint-group.rs:9:29
| |
LL | /// what up, let's make an [error] LL | /// what up, let's make an [error]
| ^^^^^ no item named `error` in `lint_group` | ^^^^^ the module `lint_group` contains no item named `error`
| |
note: the lint level is defined here note: the lint level is defined here
--> $DIR/lint-group.rs:7:9 --> $DIR/lint-group.rs:7:9

View File

@ -3,8 +3,10 @@
/// [`std::collections::BTreeMap::into_iter`] /// [`std::collections::BTreeMap::into_iter`]
/// [`String::from`] is ambiguous as to which `From` impl /// [`String::from`] is ambiguous as to which `From` impl
/// [Vec::into_iter()] uses a disambiguator
// @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter' // @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter'
// @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/string/struct.String.html#method.from"]' 'String::from' // @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/string/struct.String.html#method.from"]' 'String::from'
// @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.into_iter"]' 'Vec::into_iter'
pub fn foo() {} pub fn foo() {}
/// Link to [MyStruct], [link from struct][MyStruct::method], [MyStruct::clone], [MyStruct::Input] /// Link to [MyStruct], [link from struct][MyStruct::method], [MyStruct::clone], [MyStruct::Input]

View File

@ -4,6 +4,13 @@
// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.u32.html"]' 'u32' // @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.u32.html"]' 'u32'
// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i64.html"]' 'i64' // @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i64.html"]' 'i64'
// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html"]' 'std::primitive::i32'
// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'std::primitive::str'
// FIXME: this doesn't resolve
// @ has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' 'std::primitive::i32::MAX'
/// It contains [`u32`] and [i64]. /// It contains [`u32`] and [i64].
/// It also links to [std::primitive::i32], [std::primitive::str],
/// and [`std::primitive::i32::MAX`].
pub struct Foo; pub struct Foo;