Skip to content

Commit b203b0d

Browse files
committed
Auto merge of #83068 - mockersf:method-trait-foreign-impl, r=GuillaumeGomez
rustdoc: links from items in a trait impl are inconsistent Depending on where the struct implementing a trait is coming from, or the current page, the items in a trait impl are not linking to the same thing: |item| trait page, implementors| trait page, implementations on Foreign Types|struct page, trait implementations| |-|-|-|-| |function| link to current impl|link to first impl in the list|link to trait def |default function | not present |not present |link to trait def |default function with custom impl|link to current impl|link to trait def |link to trait def |constant| link to current impl|link to trait def |link to trait def |associated type| link to current impl|link to trait def |link to trait def ||*missing link to trait def*|*function link wrong + missing link to current impl*|*missing link to current impl*| <details> <summary>rust code with those cases</summary> ```rust pub trait MyTrait { type Assoc; const VALUE: u32; fn trait_function(&self); fn defaulted(&self) {} fn defaulted_override(&self) {} } impl MyTrait for String { /// will link to trait def type Assoc = (); /// will link to trait def const VALUE: u32 = 5; /// will link to first foreign implementor fn trait_function(&self) {} /// will link to trait def fn defaulted_override(&self) {} } impl MyTrait for Vec<u8> { /// will link to trait def type Assoc = (); /// will link to trait def const VALUE: u32 = 5; /// will link to first foreign implementor fn trait_function(&self) {} /// will link to trait def fn defaulted_override(&self) {} } impl MyTrait for MyStruct { /// in trait page, will link to current impl /// /// in struct page, will link to trait def type Assoc = bool; /// in trait page, will link to current impl /// /// in struct page, will link to trait def const VALUE: u32 = 20; /// in trait page, will link to current impl /// /// in struct page, will link to trait def fn trait_function(&self) {} /// in trait page, will link to current impl /// /// in struct page, will link to trait def fn defaulted_override(&self) {} } pub struct MyStruct; ``` </details> In this PR, I fixed all links to target the trait definition, and added an anchor-link to the current implementation appearing on mouse hover.
2 parents d408fdd + e36ca09 commit b203b0d

File tree

3 files changed

+134
-19
lines changed

3 files changed

+134
-19
lines changed

src/librustdoc/html/render/mod.rs

+65-17
Original file line numberDiff line numberDiff line change
@@ -912,10 +912,9 @@ fn render_assoc_item(
912912
let cache = cx.cache();
913913
let tcx = cx.tcx();
914914
let name = meth.name.as_ref().unwrap();
915-
let anchor = format!("#{}.{}", meth.type_(), name);
916915
let href = match link {
917916
AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id),
918-
AssocItemLink::Anchor(None) => anchor,
917+
AssocItemLink::Anchor(None) => format!("#{}.{}", meth.type_(), name),
919918
AssocItemLink::GotoSource(did, provided_methods) => {
920919
// We're creating a link from an impl-item to the corresponding
921920
// trait-item and need to map the anchored type accordingly.
@@ -925,7 +924,9 @@ fn render_assoc_item(
925924
ItemType::TyMethod
926925
};
927926

928-
href(did, cache).map(|p| format!("{}#{}.{}", p.0, ty, name)).unwrap_or(anchor)
927+
href(did, cache)
928+
.map(|p| format!("{}#{}.{}", p.0, ty, name))
929+
.unwrap_or_else(|| format!("#{}.{}", ty, name))
929930
}
930931
};
931932
let vis = meth.visibility.print_with_space(tcx, meth.def_id, cache).to_string();
@@ -1452,14 +1453,32 @@ fn render_impl(
14521453
} else {
14531454
(true, " hidden")
14541455
};
1456+
let in_trait_class = if trait_.is_some() { " trait-impl" } else { "" };
14551457
match *item.kind {
14561458
clean::MethodItem(..) | clean::TyMethodItem(_) => {
14571459
// Only render when the method is not static or we allow static methods
14581460
if render_method_item {
14591461
let id = cx.derive_id(format!("{}.{}", item_type, name));
1460-
write!(w, "<h4 id=\"{}\" class=\"{}{}\">", id, item_type, extra_class);
1462+
let source_id = trait_
1463+
.and_then(|trait_| {
1464+
trait_.items.iter().find(|item| {
1465+
item.name.map(|n| n.as_str().eq(&name.as_str())).unwrap_or(false)
1466+
})
1467+
})
1468+
.map(|item| format!("{}.{}", item.type_(), name));
1469+
write!(
1470+
w,
1471+
"<h4 id=\"{}\" class=\"{}{}{}\">",
1472+
id, item_type, extra_class, in_trait_class,
1473+
);
14611474
w.write_str("<code>");
1462-
render_assoc_item(w, item, link.anchor(&id), ItemType::Impl, cx);
1475+
render_assoc_item(
1476+
w,
1477+
item,
1478+
link.anchor(source_id.as_ref().unwrap_or(&id)),
1479+
ItemType::Impl,
1480+
cx,
1481+
);
14631482
w.write_str("</code>");
14641483
render_stability_since_raw(
14651484
w,
@@ -1468,29 +1487,50 @@ fn render_impl(
14681487
outer_version,
14691488
outer_const_version,
14701489
);
1490+
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
14711491
write_srclink(cx, item, w);
14721492
w.write_str("</h4>");
14731493
}
14741494
}
14751495
clean::TypedefItem(ref tydef, _) => {
1476-
let id = cx.derive_id(format!("{}.{}", ItemType::AssocType, name));
1477-
write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, extra_class);
1496+
let source_id = format!("{}.{}", ItemType::AssocType, name);
1497+
let id = cx.derive_id(source_id.clone());
1498+
write!(
1499+
w,
1500+
"<h4 id=\"{}\" class=\"{}{}{}\"><code>",
1501+
id, item_type, extra_class, in_trait_class
1502+
);
14781503
assoc_type(
14791504
w,
14801505
item,
14811506
&Vec::new(),
14821507
Some(&tydef.type_),
1483-
link.anchor(&id),
1508+
link.anchor(if trait_.is_some() { &source_id } else { &id }),
14841509
"",
14851510
cx.cache(),
14861511
tcx,
14871512
);
1488-
w.write_str("</code></h4>");
1513+
w.write_str("</code>");
1514+
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
1515+
w.write_str("</h4>");
14891516
}
14901517
clean::AssocConstItem(ref ty, ref default) => {
1491-
let id = cx.derive_id(format!("{}.{}", item_type, name));
1492-
write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, extra_class);
1493-
assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), "", cx);
1518+
let source_id = format!("{}.{}", item_type, name);
1519+
let id = cx.derive_id(source_id.clone());
1520+
write!(
1521+
w,
1522+
"<h4 id=\"{}\" class=\"{}{}{}\"><code>",
1523+
id, item_type, extra_class, in_trait_class
1524+
);
1525+
assoc_const(
1526+
w,
1527+
item,
1528+
ty,
1529+
default.as_ref(),
1530+
link.anchor(if trait_.is_some() { &source_id } else { &id }),
1531+
"",
1532+
cx,
1533+
);
14941534
w.write_str("</code>");
14951535
render_stability_since_raw(
14961536
w,
@@ -1499,23 +1539,31 @@ fn render_impl(
14991539
outer_version,
15001540
outer_const_version,
15011541
);
1542+
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
15021543
write_srclink(cx, item, w);
15031544
w.write_str("</h4>");
15041545
}
15051546
clean::AssocTypeItem(ref bounds, ref default) => {
1506-
let id = cx.derive_id(format!("{}.{}", item_type, name));
1507-
write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, extra_class);
1547+
let source_id = format!("{}.{}", item_type, name);
1548+
let id = cx.derive_id(source_id.clone());
1549+
write!(
1550+
w,
1551+
"<h4 id=\"{}\" class=\"{}{}{}\"><code>",
1552+
id, item_type, extra_class, in_trait_class
1553+
);
15081554
assoc_type(
15091555
w,
15101556
item,
15111557
bounds,
15121558
default.as_ref(),
1513-
link.anchor(&id),
1559+
link.anchor(if trait_.is_some() { &source_id } else { &id }),
15141560
"",
15151561
cx.cache(),
15161562
tcx,
15171563
);
1518-
w.write_str("</code></h4>");
1564+
w.write_str("</code>");
1565+
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
1566+
w.write_str("</h4>");
15191567
}
15201568
clean::StrippedItem(..) => return,
15211569
_ => panic!("can't make docs for trait item with name {:?}", item.name),
@@ -1605,7 +1653,7 @@ fn render_impl(
16051653
true,
16061654
outer_version,
16071655
outer_const_version,
1608-
None,
1656+
Some(t),
16091657
show_def_docs,
16101658
);
16111659
}

src/librustdoc/html/static/rustdoc.css

+4-2
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ h3.impl, h3.method, h4.method, h3.type, h4.type, h4.associatedconstant {
133133
margin-bottom: 10px;
134134
position: relative;
135135
}
136-
h3.impl, h3.method, h3.type {
136+
h3.impl, h3.method, h4.method.trait-impl, h3.type,
137+
h4.type.trait-impl, h4.associatedconstant.trait-impl {
137138
padding-left: 15px;
138139
}
139140

@@ -655,7 +656,8 @@ a {
655656
display: initial;
656657
}
657658

658-
.in-band:hover > .anchor, .impl:hover > .anchor {
659+
.in-band:hover > .anchor, .impl:hover > .anchor, .method.trait-impl:hover > .anchor,
660+
.type.trait-impl:hover > .anchor, .associatedconstant.trait-impl:hover > .anchor {
659661
display: inline-block;
660662
position: absolute;
661663
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
pub trait MyTrait {
2+
type Assoc;
3+
const VALUE: u32;
4+
fn trait_function(&self);
5+
fn defaulted(&self) {}
6+
fn defaulted_override(&self) {}
7+
}
8+
9+
10+
impl MyTrait for String {
11+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-1"]//a[@class="type"]/@href' #associatedtype.Assoc
12+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-1"]//a[@class="anchor"]/@href' #associatedtype.Assoc-1
13+
type Assoc = ();
14+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-1"]//a[@class="constant"]/@href' #associatedconstant.VALUE
15+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-1"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-1
16+
const VALUE: u32 = 5;
17+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
18+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
19+
fn trait_function(&self) {}
20+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-1"]//a[@class="fnname"]/@href' #method.defaulted_override
21+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-1"]//a[@class="anchor"]/@href' #method.defaulted_override-1
22+
fn defaulted_override(&self) {}
23+
}
24+
25+
impl MyTrait for Vec<u8> {
26+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-2"]//a[@class="type"]/@href' #associatedtype.Assoc
27+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-2"]//a[@class="anchor"]/@href' #associatedtype.Assoc-2
28+
type Assoc = ();
29+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-2"]//a[@class="constant"]/@href' #associatedconstant.VALUE
30+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-2"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-2
31+
const VALUE: u32 = 5;
32+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
33+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-1"]//a[@class="anchor"]/@href' #method.trait_function-1
34+
fn trait_function(&self) {}
35+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-2"]//a[@class="fnname"]/@href' #method.defaulted_override
36+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-2"]//a[@class="anchor"]/@href' #method.defaulted_override-2
37+
fn defaulted_override(&self) {}
38+
}
39+
40+
impl MyTrait for MyStruct {
41+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-3"]//a[@class="type"]/@href' #associatedtype.Assoc
42+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-3"]//a[@class="anchor"]/@href' #associatedtype.Assoc-3
43+
// @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedtype.Assoc"]//a[@class="type"]/@href' ../trait_impl_items_links_and_anchors/trait.MyTrait.html#associatedtype.Assoc
44+
// @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedtype.Assoc"]//a[@class="anchor"]/@href' #associatedtype.Assoc
45+
type Assoc = bool;
46+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-3"]//a[@class="constant"]/@href' #associatedconstant.VALUE
47+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-3"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-3
48+
// @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedconstant.VALUE"]//a[@class="constant"]/@href' ../trait_impl_items_links_and_anchors/trait.MyTrait.html#associatedconstant.VALUE
49+
// @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedconstant.VALUE"]//a[@class="anchor"]/@href' #associatedconstant.VALUE
50+
const VALUE: u32 = 20;
51+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-2"]//a[@class="fnname"]/@href' #tymethod.trait_function
52+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-2"]//a[@class="anchor"]/@href' #method.trait_function-2
53+
// @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.trait_function"]//a[@class="fnname"]/@href' ../trait_impl_items_links_and_anchors/trait.MyTrait.html#tymethod.trait_function
54+
// @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
55+
fn trait_function(&self) {}
56+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-3"]//a[@class="fnname"]/@href' #method.defaulted_override
57+
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-3"]//a[@class="anchor"]/@href' #method.defaulted_override-3
58+
// @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted_override"]//a[@class="fnname"]/@href' ../trait_impl_items_links_and_anchors/trait.MyTrait.html#method.defaulted_override
59+
// @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted_override"]//a[@class="anchor"]/@href' #method.defaulted_override
60+
fn defaulted_override(&self) {}
61+
// @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted"]//a[@class="fnname"]/@href' ../trait_impl_items_links_and_anchors/trait.MyTrait.html#method.defaulted
62+
// @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted"]//a[@class="anchor"]/@href' #method.defaulted
63+
}
64+
65+
pub struct MyStruct;

0 commit comments

Comments
 (0)