Skip to content

Commit ef8de38

Browse files
committed
rustdoc: Don't resolve link to field on different variant
1 parent 2773383 commit ef8de38

File tree

3 files changed

+54
-5
lines changed

3 files changed

+54
-5
lines changed

src/librustdoc/passes/collect_intra_doc_links.rs

+25-4
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
338338
match ty_res {
339339
Res::Def(DefKind::Enum, did) => match tcx.type_of(did).kind() {
340340
ty::Adt(def, _) if def.is_enum() => {
341-
if let Some(field) = def.all_fields().find(|f| f.name == variant_field_name) {
341+
if let Some(variant) = def.variants().iter().find(|v| v.name == variant_name)
342+
&& let Some(field) = variant.fields.iter().find(|f| f.name == variant_field_name) {
342343
Ok((ty_res, field.did))
343344
} else {
344345
Err(UnresolvedPath {
@@ -1768,15 +1769,35 @@ fn resolution_failure(
17681769

17691770
// Otherwise, it must be an associated item or variant
17701771
let res = partial_res.expect("None case was handled by `last_found_module`");
1771-
let kind = match res {
1772-
Res::Def(kind, _) => Some(kind),
1772+
let kind_did = match res {
1773+
Res::Def(kind, did) => Some((kind, did)),
17731774
Res::Primitive(_) => None,
17741775
};
1775-
let path_description = if let Some(kind) = kind {
1776+
let is_struct_variant = |did| {
1777+
if let ty::Adt(def, _) = tcx.type_of(did).kind()
1778+
&& def.is_enum()
1779+
&& let Some(variant) = def.variants().iter().find(|v| v.name == res.name(tcx)) {
1780+
// ctor is `None` if variant is a struct
1781+
variant.ctor.is_none()
1782+
} else {
1783+
false
1784+
}
1785+
};
1786+
let path_description = if let Some((kind, did)) = kind_did {
17761787
match kind {
17771788
Mod | ForeignMod => "inner item",
17781789
Struct => "field or associated item",
17791790
Enum | Union => "variant or associated item",
1791+
Variant if is_struct_variant(did) => {
1792+
let variant = res.name(tcx);
1793+
let note = format!("variant `{variant}` has no such field");
1794+
if let Some(span) = sp {
1795+
diag.span_label(span, &note);
1796+
} else {
1797+
diag.note(&note);
1798+
}
1799+
return;
1800+
}
17801801
Variant
17811802
| Field
17821803
| Closure

tests/rustdoc-ui/intra-doc/errors.rs

+16
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,19 @@ pub trait T {
103103
macro_rules! m {
104104
() => {};
105105
}
106+
107+
///[`TestEnum::Variant1::field_name`]
108+
//~^ ERROR unresolved link
109+
//~| NOTE variant `Variant1` has no such field
110+
pub enum TestEnum {
111+
Variant1 {},
112+
Variant2 { field_name: u64 },
113+
}
114+
115+
///[`TestEnumNoFields::Variant1::field_name`]
116+
//~^ ERROR unresolved link
117+
//~| NOTE `Variant1` is a variant, not a module or type, and cannot have associated items
118+
pub enum TestEnumNoFields {
119+
Variant1 (),
120+
Variant2 {},
121+
}

tests/rustdoc-ui/intra-doc/errors.stderr

+13-1
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,18 @@ error: unresolved link to `T::h`
142142
LL | /// [T::h!]
143143
| ^^^^^ the trait `T` has no macro named `h`
144144

145+
error: unresolved link to `TestEnum::Variant1::field_name`
146+
--> $DIR/errors.rs:107:6
147+
|
148+
LL | ///[`TestEnum::Variant1::field_name`]
149+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variant `Variant1` has no such field
150+
151+
error: unresolved link to `TestEnumNoFields::Variant1::field_name`
152+
--> $DIR/errors.rs:115:6
153+
|
154+
LL | ///[`TestEnumNoFields::Variant1::field_name`]
155+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Variant1` is a variant, not a module or type, and cannot have associated items
156+
145157
error: unresolved link to `m`
146158
--> $DIR/errors.rs:98:6
147159
|
@@ -153,5 +165,5 @@ help: to link to the macro, add an exclamation mark
153165
LL | /// [m!()]
154166
| +
155167

156-
error: aborting due to 20 previous errors
168+
error: aborting due to 22 previous errors
157169

0 commit comments

Comments
 (0)