Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustdoc: Don't resolve link to field on different variant #107912

Merged
merged 1 commit into from
Feb 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions src/librustdoc/passes/collect_intra_doc_links.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
match ty_res {
Res::Def(DefKind::Enum, did) => match tcx.type_of(did).kind() {
ty::Adt(def, _) if def.is_enum() => {
if let Some(field) = def.all_fields().find(|f| f.name == variant_field_name) {
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) {
Ok((ty_res, field.did))
} else {
Err(UnresolvedPath {
Expand Down Expand Up @@ -1768,15 +1769,35 @@ fn resolution_failure(

// Otherwise, it must be an associated item or variant
let res = partial_res.expect("None case was handled by `last_found_module`");
let kind = match res {
Res::Def(kind, _) => Some(kind),
let kind_did = match res {
Res::Def(kind, did) => Some((kind, did)),
Res::Primitive(_) => None,
};
let path_description = if let Some(kind) = kind {
let is_struct_variant = |did| {
if let ty::Adt(def, _) = tcx.type_of(did).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
variant.ctor.is_none()
} else {
false
}
};
let path_description = if let Some((kind, did)) = kind_did {
match kind {
Mod | ForeignMod => "inner item",
Struct => "field or associated item",
Enum | Union => "variant or associated item",
Variant if is_struct_variant(did) => {
let variant = res.name(tcx);
let note = format!("variant `{variant}` has no such field");
if let Some(span) = sp {
diag.span_label(span, &note);
} else {
diag.note(&note);
}
return;
}
Variant
| Field
| Closure
Expand Down
16 changes: 16 additions & 0 deletions tests/rustdoc-ui/intra-doc/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,19 @@ pub trait T {
macro_rules! m {
() => {};
}

///[`TestEnum::Variant1::field_name`]
//~^ ERROR unresolved link
//~| NOTE variant `Variant1` has no such field
pub enum TestEnum {
Variant1 {},
Variant2 { field_name: u64 },
}

///[`TestEnumNoFields::Variant1::field_name`]
//~^ ERROR unresolved link
//~| NOTE `Variant1` is a variant, not a module or type, and cannot have associated items
pub enum TestEnumNoFields {
Variant1 (),
Variant2 {},
}
14 changes: 13 additions & 1 deletion tests/rustdoc-ui/intra-doc/errors.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,18 @@ error: unresolved link to `T::h`
LL | /// [T::h!]
| ^^^^^ the trait `T` has no macro named `h`

error: unresolved link to `TestEnum::Variant1::field_name`
--> $DIR/errors.rs:107:6
|
LL | ///[`TestEnum::Variant1::field_name`]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variant `Variant1` has no such field

error: unresolved link to `TestEnumNoFields::Variant1::field_name`
--> $DIR/errors.rs:115:6
|
LL | ///[`TestEnumNoFields::Variant1::field_name`]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Variant1` is a variant, not a module or type, and cannot have associated items

error: unresolved link to `m`
--> $DIR/errors.rs:98:6
|
Expand All @@ -153,5 +165,5 @@ help: to link to the macro, add an exclamation mark
LL | /// [m!()]
| +

error: aborting due to 20 previous errors
error: aborting due to 22 previous errors