Skip to content

Commit 9627e9e

Browse files
authored
Auto merge of #36266 - Sawyer47:issue-35169, r=alexcrichton
rustdoc: Filter more incorrect methods inherited through Deref Old code filtered out only static methods. This code also excludes &mut self methods if there is no DerefMut implementation. Fixes #35169
2 parents cf0cdc4 + 915bbda commit 9627e9e

File tree

6 files changed

+154
-27
lines changed

6 files changed

+154
-27
lines changed

src/librustdoc/clean/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
134134
if let Some(t) = cx.tcx_opt() {
135135
cx.deref_trait_did.set(t.lang_items.deref_trait());
136136
cx.renderinfo.borrow_mut().deref_trait_did = cx.deref_trait_did.get();
137+
cx.deref_mut_trait_did.set(t.lang_items.deref_mut_trait());
138+
cx.renderinfo.borrow_mut().deref_mut_trait_did = cx.deref_mut_trait_did.get();
137139
}
138140

139141
let mut externs = Vec::new();
@@ -1117,6 +1119,10 @@ impl FnDecl {
11171119
pub fn has_self(&self) -> bool {
11181120
return self.inputs.values.len() > 0 && self.inputs.values[0].name == "self";
11191121
}
1122+
1123+
pub fn self_type(&self) -> Option<SelfTy> {
1124+
self.inputs.values.get(0).and_then(|v| v.to_self())
1125+
}
11201126
}
11211127

11221128
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]

src/librustdoc/core.rs

+2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ pub struct DocContext<'a, 'tcx: 'a> {
5353
pub input: Input,
5454
pub populated_crate_impls: RefCell<FnvHashSet<ast::CrateNum>>,
5555
pub deref_trait_did: Cell<Option<DefId>>,
56+
pub deref_mut_trait_did: Cell<Option<DefId>>,
5657
// Note that external items for which `doc(hidden)` applies to are shown as
5758
// non-reachable while local items aren't. This is because we're reusing
5859
// the access levels from crateanalysis.
@@ -180,6 +181,7 @@ pub fn run_core(search_paths: SearchPaths,
180181
input: input,
181182
populated_crate_impls: RefCell::new(FnvHashSet()),
182183
deref_trait_did: Cell::new(None),
184+
deref_mut_trait_did: Cell::new(None),
183185
access_levels: RefCell::new(access_levels),
184186
external_traits: RefCell::new(FnvHashMap()),
185187
renderinfo: RefCell::new(Default::default()),

src/librustdoc/html/render.rs

+60-27
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ use rustc::hir;
6464
use rustc::util::nodemap::{FnvHashMap, FnvHashSet};
6565
use rustc_data_structures::flock;
6666

67-
use clean::{self, Attributes, GetDefId};
67+
use clean::{self, Attributes, GetDefId, SelfTy, Mutability};
6868
use doctree;
6969
use fold::DocFolder;
7070
use html::escape::Escape;
@@ -266,6 +266,7 @@ pub struct Cache {
266266
seen_mod: bool,
267267
stripped_mod: bool,
268268
deref_trait_did: Option<DefId>,
269+
deref_mut_trait_did: Option<DefId>,
269270

270271
// In rare case where a structure is defined in one module but implemented
271272
// in another, if the implementing module is parsed before defining module,
@@ -283,6 +284,7 @@ pub struct RenderInfo {
283284
pub external_paths: ::core::ExternalPaths,
284285
pub external_typarams: FnvHashMap<DefId, String>,
285286
pub deref_trait_did: Option<DefId>,
287+
pub deref_mut_trait_did: Option<DefId>,
286288
}
287289

288290
/// Helper struct to render all source code to HTML pages
@@ -508,6 +510,7 @@ pub fn run(mut krate: clean::Crate,
508510
external_paths,
509511
external_typarams,
510512
deref_trait_did,
513+
deref_mut_trait_did,
511514
} = renderinfo;
512515

513516
let external_paths = external_paths.into_iter()
@@ -532,6 +535,7 @@ pub fn run(mut krate: clean::Crate,
532535
orphan_impl_items: Vec::new(),
533536
traits: mem::replace(&mut krate.external_traits, FnvHashMap()),
534537
deref_trait_did: deref_trait_did,
538+
deref_mut_trait_did: deref_mut_trait_did,
535539
typarams: external_typarams,
536540
};
537541

@@ -2603,7 +2607,13 @@ impl<'a> AssocItemLink<'a> {
26032607

26042608
enum AssocItemRender<'a> {
26052609
All,
2606-
DerefFor { trait_: &'a clean::Type, type_: &'a clean::Type },
2610+
DerefFor { trait_: &'a clean::Type, type_: &'a clean::Type, deref_mut_: bool }
2611+
}
2612+
2613+
#[derive(Copy, Clone, PartialEq)]
2614+
enum RenderMode {
2615+
Normal,
2616+
ForDeref { mut_: bool },
26072617
}
26082618

26092619
fn render_assoc_items(w: &mut fmt::Formatter,
@@ -2620,19 +2630,19 @@ fn render_assoc_items(w: &mut fmt::Formatter,
26202630
i.inner_impl().trait_.is_none()
26212631
});
26222632
if !non_trait.is_empty() {
2623-
let render_header = match what {
2633+
let render_mode = match what {
26242634
AssocItemRender::All => {
26252635
write!(w, "<h2 id='methods'>Methods</h2>")?;
2626-
true
2636+
RenderMode::Normal
26272637
}
2628-
AssocItemRender::DerefFor { trait_, type_ } => {
2638+
AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
26292639
write!(w, "<h2 id='deref-methods'>Methods from \
26302640
{}&lt;Target={}&gt;</h2>", trait_, type_)?;
2631-
false
2641+
RenderMode::ForDeref { mut_: deref_mut_ }
26322642
}
26332643
};
26342644
for i in &non_trait {
2635-
render_impl(w, cx, i, AssocItemLink::Anchor(None), render_header,
2645+
render_impl(w, cx, i, AssocItemLink::Anchor(None), render_mode,
26362646
containing_item.stable_since())?;
26372647
}
26382648
}
@@ -2644,29 +2654,34 @@ fn render_assoc_items(w: &mut fmt::Formatter,
26442654
t.inner_impl().trait_.def_id() == c.deref_trait_did
26452655
});
26462656
if let Some(impl_) = deref_impl {
2647-
render_deref_methods(w, cx, impl_, containing_item)?;
2657+
let has_deref_mut = traits.iter().find(|t| {
2658+
t.inner_impl().trait_.def_id() == c.deref_mut_trait_did
2659+
}).is_some();
2660+
render_deref_methods(w, cx, impl_, containing_item, has_deref_mut)?;
26482661
}
26492662
write!(w, "<h2 id='implementations'>Trait \
26502663
Implementations</h2>")?;
26512664
for i in &traits {
26522665
let did = i.trait_did().unwrap();
26532666
let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods);
2654-
render_impl(w, cx, i, assoc_link, true, containing_item.stable_since())?;
2667+
render_impl(w, cx, i, assoc_link,
2668+
RenderMode::Normal, containing_item.stable_since())?;
26552669
}
26562670
}
26572671
Ok(())
26582672
}
26592673

26602674
fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl,
2661-
container_item: &clean::Item) -> fmt::Result {
2675+
container_item: &clean::Item, deref_mut: bool) -> fmt::Result {
26622676
let deref_type = impl_.inner_impl().trait_.as_ref().unwrap();
26632677
let target = impl_.inner_impl().items.iter().filter_map(|item| {
26642678
match item.inner {
26652679
clean::TypedefItem(ref t, true) => Some(&t.type_),
26662680
_ => None,
26672681
}
26682682
}).next().expect("Expected associated type binding");
2669-
let what = AssocItemRender::DerefFor { trait_: deref_type, type_: target };
2683+
let what = AssocItemRender::DerefFor { trait_: deref_type, type_: target,
2684+
deref_mut_: deref_mut };
26702685
if let Some(did) = target.def_id() {
26712686
render_assoc_items(w, cx, container_item, did, what)
26722687
} else {
@@ -2680,12 +2695,9 @@ fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl,
26802695
}
26812696
}
26822697

2683-
// Render_header is false when we are rendering a `Deref` impl and true
2684-
// otherwise. If render_header is false, we will avoid rendering static
2685-
// methods, since they are not accessible for the type implementing `Deref`
26862698
fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLink,
2687-
render_header: bool, outer_version: Option<&str>) -> fmt::Result {
2688-
if render_header {
2699+
render_mode: RenderMode, outer_version: Option<&str>) -> fmt::Result {
2700+
if render_mode == RenderMode::Normal {
26892701
write!(w, "<h3 class='impl'><span class='in-band'><code>{}</code>", i.inner_impl())?;
26902702
write!(w, "</span><span class='out-of-band'>")?;
26912703
let since = i.impl_item.stability.as_ref().map(|s| &s.since[..]);
@@ -2706,22 +2718,43 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
27062718
}
27072719

27082720
fn doc_impl_item(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
2709-
link: AssocItemLink, render_static: bool,
2721+
link: AssocItemLink, render_mode: RenderMode,
27102722
is_default_item: bool, outer_version: Option<&str>,
27112723
trait_: Option<&clean::Trait>) -> fmt::Result {
27122724
let item_type = item_type(item);
27132725
let name = item.name.as_ref().unwrap();
27142726

2715-
let is_static = match item.inner {
2716-
clean::MethodItem(ref method) => !method.decl.has_self(),
2717-
clean::TyMethodItem(ref method) => !method.decl.has_self(),
2718-
_ => false
2727+
let render_method_item: bool = match render_mode {
2728+
RenderMode::Normal => true,
2729+
RenderMode::ForDeref { mut_: deref_mut_ } => {
2730+
let self_type_opt = match item.inner {
2731+
clean::MethodItem(ref method) => method.decl.self_type(),
2732+
clean::TyMethodItem(ref method) => method.decl.self_type(),
2733+
_ => None
2734+
};
2735+
2736+
if let Some(self_ty) = self_type_opt {
2737+
let by_mut_ref = match self_ty {
2738+
SelfTy::SelfBorrowed(_lifetime, mutability) => {
2739+
mutability == Mutability::Mutable
2740+
},
2741+
SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => {
2742+
mutability == Mutability::Mutable
2743+
},
2744+
_ => false,
2745+
};
2746+
2747+
deref_mut_ || !by_mut_ref
2748+
} else {
2749+
false
2750+
}
2751+
},
27192752
};
27202753

27212754
match item.inner {
27222755
clean::MethodItem(..) | clean::TyMethodItem(..) => {
27232756
// Only render when the method is not static or we allow static methods
2724-
if !is_static || render_static {
2757+
if render_method_item {
27252758
let id = derive_id(format!("{}.{}", item_type, name));
27262759
let ns_id = derive_id(format!("{}.{}", name, item_type.name_space()));
27272760
write!(w, "<h4 id='{}' class='{}'>", id, item_type)?;
@@ -2769,7 +2802,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
27692802
_ => panic!("can't make docs for trait item with name {:?}", item.name)
27702803
}
27712804

2772-
if !is_static || render_static {
2805+
if render_method_item || render_mode == RenderMode::Normal {
27732806
if !is_default_item {
27742807
if let Some(t) = trait_ {
27752808
// The trait item may have been stripped so we might not
@@ -2802,15 +2835,15 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
28022835

28032836
write!(w, "<div class='impl-items'>")?;
28042837
for trait_item in &i.inner_impl().items {
2805-
doc_impl_item(w, cx, trait_item, link, render_header,
2838+
doc_impl_item(w, cx, trait_item, link, render_mode,
28062839
false, outer_version, trait_)?;
28072840
}
28082841

28092842
fn render_default_items(w: &mut fmt::Formatter,
28102843
cx: &Context,
28112844
t: &clean::Trait,
28122845
i: &clean::Impl,
2813-
render_static: bool,
2846+
render_mode: RenderMode,
28142847
outer_version: Option<&str>) -> fmt::Result {
28152848
for trait_item in &t.items {
28162849
let n = trait_item.name.clone();
@@ -2820,7 +2853,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
28202853
let did = i.trait_.as_ref().unwrap().def_id().unwrap();
28212854
let assoc_link = AssocItemLink::GotoSource(did, &i.provided_trait_methods);
28222855

2823-
doc_impl_item(w, cx, trait_item, assoc_link, render_static, true,
2856+
doc_impl_item(w, cx, trait_item, assoc_link, render_mode, true,
28242857
outer_version, None)?;
28252858
}
28262859
Ok(())
@@ -2829,7 +2862,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
28292862
// If we've implemented a trait, then also emit documentation for all
28302863
// default items which weren't overridden in the implementation block.
28312864
if let Some(t) = trait_ {
2832-
render_default_items(w, cx, t, &i.inner_impl(), render_header, outer_version)?;
2865+
render_default_items(w, cx, t, &i.inner_impl(), render_mode, outer_version)?;
28332866
}
28342867
write!(w, "</div>")?;
28352868
Ok(())

src/librustdoc/test.rs

+1
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ pub fn run(input: &str,
110110
external_traits: RefCell::new(FnvHashMap()),
111111
populated_crate_impls: RefCell::new(FnvHashSet()),
112112
deref_trait_did: Cell::new(None),
113+
deref_mut_trait_did: Cell::new(None),
113114
access_levels: Default::default(),
114115
renderinfo: Default::default(),
115116
};

src/test/rustdoc/issue-35169-2.rs

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::ops::Deref;
12+
use std::ops::DerefMut;
13+
14+
pub struct Foo;
15+
pub struct Bar;
16+
17+
impl Foo {
18+
pub fn by_ref(&self) {}
19+
pub fn by_explicit_ref(self: &Foo) {}
20+
pub fn by_mut_ref(&mut self) {}
21+
pub fn by_explicit_mut_ref(self: &mut Foo) {}
22+
pub fn static_foo() {}
23+
}
24+
25+
impl Deref for Bar {
26+
type Target = Foo;
27+
fn deref(&self) -> &Foo { loop {} }
28+
}
29+
30+
impl DerefMut for Bar {
31+
fn deref_mut(&mut self) -> &mut Foo { loop {} }
32+
}
33+
34+
// @has issue_35169_2/Bar.t.html
35+
// @has issue_35169_2/struct.Bar.html
36+
// @has - '//*[@id="by_ref.v"]' 'fn by_ref(&self)'
37+
// @has - '//*[@id="method.by_ref"]' 'fn by_ref(&self)'
38+
// @has - '//*[@id="by_explicit_ref.v"]' 'fn by_explicit_ref(self: &Foo)'
39+
// @has - '//*[@id="method.by_explicit_ref"]' 'fn by_explicit_ref(self: &Foo)'
40+
// @has - '//*[@id="by_mut_ref.v"]' 'fn by_mut_ref(&mut self)'
41+
// @has - '//*[@id="method.by_mut_ref"]' 'fn by_mut_ref(&mut self)'
42+
// @has - '//*[@id="by_explicit_mut_ref.v"]' 'fn by_explicit_mut_ref(self: &mut Foo)'
43+
// @has - '//*[@id="method.by_explicit_mut_ref"]' 'fn by_explicit_mut_ref(self: &mut Foo)'
44+
// @!has - '//*[@id="static_foo.v"]' 'fn static_foo()'
45+
// @!has - '//*[@id="method.static_foo"]' 'fn static_foo()'

src/test/rustdoc/issue-35169.rs

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::ops::Deref;
12+
13+
pub struct Foo;
14+
pub struct Bar;
15+
16+
impl Foo {
17+
pub fn by_ref(&self) {}
18+
pub fn by_explicit_ref(self: &Foo) {}
19+
pub fn by_mut_ref(&mut self) {}
20+
pub fn by_explicit_mut_ref(self: &mut Foo) {}
21+
pub fn static_foo() {}
22+
}
23+
24+
impl Deref for Bar {
25+
type Target = Foo;
26+
fn deref(&self) -> &Foo { loop {} }
27+
}
28+
29+
// @has issue_35169/Bar.t.html
30+
// @has issue_35169/struct.Bar.html
31+
// @has - '//*[@id="by_ref.v"]' 'fn by_ref(&self)'
32+
// @has - '//*[@id="method.by_ref"]' 'fn by_ref(&self)'
33+
// @has - '//*[@id="by_explicit_ref.v"]' 'fn by_explicit_ref(self: &Foo)'
34+
// @has - '//*[@id="method.by_explicit_ref"]' 'fn by_explicit_ref(self: &Foo)'
35+
// @!has - '//*[@id="by_mut_ref.v"]' 'fn by_mut_ref(&mut self)'
36+
// @!has - '//*[@id="method.by_mut_ref"]' 'fn by_mut_ref(&mut self)'
37+
// @!has - '//*[@id="by_explicit_mut_ref.v"]' 'fn by_explicit_mut_ref(self: &mut Foo)'
38+
// @!has - '//*[@id="method.by_explicit_mut_ref"]' 'fn by_explicit_mut_ref(self: &mut Foo)'
39+
// @!has - '//*[@id="static_foo.v"]' 'fn static_foo()'
40+
// @!has - '//*[@id="method.static_foo"]' 'fn static_foo()'

0 commit comments

Comments
 (0)