Skip to content

Commit

Permalink
rustdoc: Fix issues with cross-crate inlined associated items
Browse files Browse the repository at this point in the history
* Visibility was missing from impl items.
* Attributes and docs were missing from consts and types in impls.
* Const default values were missing from traits.

This unifies the code that handles associated items from impls and traits.
  • Loading branch information
ollie27 committed Nov 29, 2017
1 parent 0a2e9ad commit b444843
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 96 deletions.
72 changes: 4 additions & 68 deletions src/librustdoc/clean/inline.rs
Expand Up @@ -332,74 +332,10 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {

let predicates = tcx.predicates_of(did);
let trait_items = tcx.associated_items(did).filter_map(|item| {
match item.kind {
ty::AssociatedKind::Const => {
let default = if item.defaultness.has_value() {
Some(print_inlined_const(cx, item.def_id))
} else {
None
};
Some(clean::Item {
name: Some(item.name.clean(cx)),
inner: clean::AssociatedConstItem(
tcx.type_of(item.def_id).clean(cx),
default,
),
source: tcx.def_span(item.def_id).clean(cx),
attrs: clean::Attributes::default(),
visibility: None,
stability: tcx.lookup_stability(item.def_id).clean(cx),
deprecation: tcx.lookup_deprecation(item.def_id).clean(cx),
def_id: item.def_id
})
}
ty::AssociatedKind::Method => {
if item.vis != ty::Visibility::Public && associated_trait.is_none() {
return None
}
let mut cleaned = item.clean(cx);
cleaned.inner = match cleaned.inner.clone() {
clean::TyMethodItem(clean::TyMethod {
unsafety, decl, generics, abi
}) => {
let constness = if tcx.is_const_fn(item.def_id) {
hir::Constness::Const
} else {
hir::Constness::NotConst
};

clean::MethodItem(clean::Method {
unsafety,
constness,
decl,
generics,
abi,
})
}
ref r => panic!("not a tymethod: {:?}", r),
};
Some(cleaned)
}
ty::AssociatedKind::Type => {
let typedef = clean::Typedef {
type_: tcx.type_of(item.def_id).clean(cx),
generics: clean::Generics {
lifetimes: vec![],
type_params: vec![],
where_predicates: vec![]
}
};
Some(clean::Item {
name: Some(item.name.clean(cx)),
inner: clean::TypedefItem(typedef, true),
source: tcx.def_span(item.def_id).clean(cx),
attrs: clean::Attributes::default(),
visibility: None,
stability: tcx.lookup_stability(item.def_id).clean(cx),
deprecation: tcx.lookup_deprecation(item.def_id).clean(cx),
def_id: item.def_id
})
}
if associated_trait.is_some() || item.vis == ty::Visibility::Public {
Some(item.clean(cx))
} else {
None
}
}).collect::<Vec<_>>();
let polarity = tcx.impl_polarity(did);
Expand Down
73 changes: 46 additions & 27 deletions src/librustdoc/clean/mod.rs
Expand Up @@ -1595,7 +1595,12 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
let inner = match self.kind {
ty::AssociatedKind::Const => {
let ty = cx.tcx.type_of(self.def_id);
AssociatedConstItem(ty.clean(cx), None)
let default = if self.defaultness.has_value() {
Some(inline::print_inlined_const(cx, self.def_id))
} else {
None
};
AssociatedConstItem(ty.clean(cx), default)
}
ty::AssociatedKind::Method => {
let generics = (cx.tcx.generics_of(self.def_id),
Expand Down Expand Up @@ -1626,18 +1631,21 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
}

let provided = match self.container {
ty::ImplContainer(_) => false,
ty::ImplContainer(_) => true,
ty::TraitContainer(_) => self.defaultness.has_value()
};
if provided {
let constness = if cx.tcx.is_const_fn(self.def_id) {
hir::Constness::Const
} else {
hir::Constness::NotConst
};
MethodItem(Method {
unsafety: sig.unsafety(),
generics,
decl,
abi: sig.abi(),

// trait methods cannot (currently, at least) be const
constness: hir::Constness::NotConst,
constness,
})
} else {
TyMethodItem(TyMethod {
Expand All @@ -1651,14 +1659,14 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
ty::AssociatedKind::Type => {
let my_name = self.name.clean(cx);

let mut bounds = if let ty::TraitContainer(did) = self.container {
if let ty::TraitContainer(did) = self.container {
// When loading a cross-crate associated type, the bounds for this type
// are actually located on the trait/impl itself, so we need to load
// all of the generics from there and then look for bounds that are
// applied to this associated type in question.
let predicates = cx.tcx.predicates_of(did);
let generics = (cx.tcx.generics_of(did), &predicates).clean(cx);
generics.where_predicates.iter().filter_map(|pred| {
let mut bounds = generics.where_predicates.iter().filter_map(|pred| {
let (name, self_type, trait_, bounds) = match *pred {
WherePredicate::BoundPredicate {
ty: QPath { ref name, ref self_type, ref trait_ },
Expand All @@ -1676,34 +1684,45 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
_ => return None,
}
Some(bounds)
}).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>()
} else {
vec![]
};
}).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>();
// Our Sized/?Sized bound didn't get handled when creating the generics
// because we didn't actually get our whole set of bounds until just now
// (some of them may have come from the trait). If we do have a sized
// bound, we remove it, and if we don't then we add the `?Sized` bound
// at the end.
match bounds.iter().position(|b| b.is_sized_bound(cx)) {
Some(i) => { bounds.remove(i); }
None => bounds.push(TyParamBound::maybe_sized(cx)),
}

// Our Sized/?Sized bound didn't get handled when creating the generics
// because we didn't actually get our whole set of bounds until just now
// (some of them may have come from the trait). If we do have a sized
// bound, we remove it, and if we don't then we add the `?Sized` bound
// at the end.
match bounds.iter().position(|b| b.is_sized_bound(cx)) {
Some(i) => { bounds.remove(i); }
None => bounds.push(TyParamBound::maybe_sized(cx)),
}
let ty = if self.defaultness.has_value() {
Some(cx.tcx.type_of(self.def_id))
} else {
None
};

let ty = if self.defaultness.has_value() {
Some(cx.tcx.type_of(self.def_id))
AssociatedTypeItem(bounds, ty.clean(cx))
} else {
None
};

AssociatedTypeItem(bounds, ty.clean(cx))
TypedefItem(Typedef {
type_: cx.tcx.type_of(self.def_id).clean(cx),
generics: Generics {
lifetimes: Vec::new(),
type_params: Vec::new(),
where_predicates: Vec::new(),
},
}, true)
}
}
};

let visibility = match self.container {
ty::ImplContainer(_) => self.vis.clean(cx),
ty::TraitContainer(_) => None,
};

Item {
name: Some(self.name.clean(cx)),
visibility: Some(Inherited),
visibility,
stability: get_stability(cx, self.def_id),
deprecation: get_deprecation(cx, self.def_id),
def_id: self.def_id,
Expand Down
3 changes: 2 additions & 1 deletion src/librustdoc/html/render.rs
Expand Up @@ -2621,7 +2621,8 @@ fn assoc_const(w: &mut fmt::Formatter,
ty: &clean::Type,
_default: Option<&String>,
link: AssocItemLink) -> fmt::Result {
write!(w, "const <a href='{}' class=\"constant\"><b>{}</b></a>: {}",
write!(w, "{}const <a href='{}' class=\"constant\"><b>{}</b></a>: {}",
VisSpace(&it.visibility),
naive_assoc_href(it, link),
it.name.as_ref().unwrap(),
ty)?;
Expand Down
57 changes: 57 additions & 0 deletions src/test/rustdoc/inline_cross/assoc-items.rs
@@ -0,0 +1,57 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// aux-build:assoc-items.rs
// build-aux-docs
// ignore-cross-compile

#![crate_name = "foo"]

extern crate assoc_items;

// @has foo/struct.MyStruct.html
// @!has - 'PrivateConst'
// @has - '//*[@id="associatedconstant.PublicConst"]' 'pub const PublicConst: u8'
// @has - '//*[@class="docblock"]' 'PublicConst: u8 = 123'
// @has - '//*[@class="docblock"]' 'docs for PublicConst'
// @!has - 'private_method'
// @has - '//*[@id="method.public_method"]' 'pub fn public_method()'
// @has - '//*[@class="docblock"]' 'docs for public_method'
// @has - '//*[@id="associatedconstant.ConstNoDefault"]' 'const ConstNoDefault: i16'
// @has - '//*[@class="docblock"]' 'ConstNoDefault: i16 = -123'
// @has - '//*[@class="docblock"]' 'dox for ConstNoDefault'
// @has - '//*[@id="associatedconstant.ConstWithDefault"]' 'const ConstWithDefault: u16'
// @has - '//*[@class="docblock"]' 'ConstWithDefault: u16 = 12345'
// @has - '//*[@class="docblock"]' 'docs for ConstWithDefault'
// @has - '//*[@id="associatedtype.TypeNoDefault"]' 'type TypeNoDefault = i32'
// @has - '//*[@class="docblock"]' 'dox for TypeNoDefault'
// @has - '//*[@id="associatedtype.TypeWithDefault"]' 'type TypeWithDefault = u32'
// @has - '//*[@class="docblock"]' 'docs for TypeWithDefault'
// @has - '//*[@id="method.method_no_default"]' 'fn method_no_default()'
// @has - '//*[@class="docblock"]' 'dox for method_no_default'
// @has - '//*[@id="method.method_with_default"]' 'fn method_with_default()'
// @has - '//*[@class="docblock"]' 'docs for method_with_default'
pub use assoc_items::MyStruct;

// @has foo/trait.MyTrait.html
// @has - '//*[@id="associatedconstant.ConstNoDefault"]' 'const ConstNoDefault: i16'
// @has - '//*[@class="docblock"]' 'docs for ConstNoDefault'
// @has - '//*[@id="associatedconstant.ConstWithDefault"]' 'const ConstWithDefault: u16'
// @has - '//*[@class="docblock"]' 'ConstWithDefault: u16 = 12345'
// @has - '//*[@class="docblock"]' 'docs for ConstWithDefault'
// @has - '//*[@id="associatedtype.TypeNoDefault"]' 'type TypeNoDefault'
// @has - '//*[@class="docblock"]' 'docs for TypeNoDefault'
// @has - '//*[@id="associatedtype.TypeWithDefault"]' 'type TypeWithDefault = u32'
// @has - '//*[@class="docblock"]' 'docs for TypeWithDefault'
// @has - '//*[@id="tymethod.method_no_default"]' 'fn method_no_default()'
// @has - '//*[@class="docblock"]' 'docs for method_no_default'
// @has - '//*[@id="method.method_with_default"]' 'fn method_with_default()'
// @has - '//*[@class="docblock"]' 'docs for method_with_default'
pub use assoc_items::MyTrait;
48 changes: 48 additions & 0 deletions src/test/rustdoc/inline_cross/auxiliary/assoc-items.rs
@@ -0,0 +1,48 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(associated_type_defaults)]

pub struct MyStruct;

impl MyStruct {
/// docs for PrivateConst
const PrivateConst: i8 = -123;
/// docs for PublicConst
pub const PublicConst: u8 = 123;
/// docs for private_method
fn private_method() {}
/// docs for public_method
pub fn public_method() {}
}

pub trait MyTrait {
/// docs for ConstNoDefault
const ConstNoDefault: i16;
/// docs for ConstWithDefault
const ConstWithDefault: u16 = 12345;
/// docs for TypeNoDefault
type TypeNoDefault;
/// docs for TypeWithDefault
type TypeWithDefault = u32;
/// docs for method_no_default
fn method_no_default();
/// docs for method_with_default
fn method_with_default() {}
}

impl MyTrait for MyStruct {
/// dox for ConstNoDefault
const ConstNoDefault: i16 = -12345;
/// dox for TypeNoDefault
type TypeNoDefault = i32;
/// dox for method_no_default
fn method_no_default() {}
}

0 comments on commit b444843

Please sign in to comment.