mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Auto merge of #33002 - mitaa:rdoc-cross-impls, r=alexcrichton
rustdoc: refine cross-crate impl inlining This changes the current rule that impls within `doc(hidden)` modules aren't inlined, to only inlining impls where the implemented trait and type are reachable in documentation. fixes #14586 fixes #31948 .. and also applies the reachability checking to cross-crate links. fixes #28480 r? @alexcrichton
This commit is contained in:
commit
478a33dabc
@ -113,6 +113,7 @@ pub enum InlinedItemRef<'a> {
|
||||
/// LOCAL_CRATE in their DefId.
|
||||
pub const LOCAL_CRATE: ast::CrateNum = 0;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ChildItem {
|
||||
pub def: DefLike,
|
||||
pub name: ast::Name,
|
||||
|
@ -15,10 +15,11 @@
|
||||
use util::nodemap::{DefIdSet, FnvHashMap};
|
||||
|
||||
use std::hash::Hash;
|
||||
use std::fmt;
|
||||
use syntax::ast::NodeId;
|
||||
|
||||
// Accessibility levels, sorted in ascending order
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum AccessLevel {
|
||||
// Exported items + items participating in various kinds of public interfaces,
|
||||
// but not directly nameable. For example, if function `fn f() -> T {...}` is
|
||||
@ -56,6 +57,12 @@ impl<Id: Hash + Eq> Default for AccessLevels<Id> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Id: Hash + Eq + fmt::Debug> fmt::Debug for AccessLevels<Id> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.map, f)
|
||||
}
|
||||
}
|
||||
|
||||
/// A set containing all exported definitions from external crates.
|
||||
/// The set does not contain any entries from local crates.
|
||||
pub type ExternalExports = DefIdSet;
|
||||
|
@ -26,9 +26,9 @@ use rustc::middle::stability;
|
||||
|
||||
use rustc_const_eval::lookup_const_by_id;
|
||||
|
||||
use core::DocContext;
|
||||
use core::{DocContext, DocAccessLevels};
|
||||
use doctree;
|
||||
use clean::{self, Attributes, GetDefId};
|
||||
use clean::{self, GetDefId};
|
||||
|
||||
use super::{Clean, ToSource};
|
||||
|
||||
@ -116,7 +116,7 @@ fn try_inline_def(cx: &DocContext, tcx: &TyCtxt,
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
cx.inlined.borrow_mut().as_mut().unwrap().insert(did);
|
||||
cx.renderinfo.borrow_mut().inlined.insert(did);
|
||||
ret.push(clean::Item {
|
||||
source: clean::Span::empty(),
|
||||
name: Some(tcx.item_name(did).to_string()),
|
||||
@ -146,7 +146,7 @@ pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) {
|
||||
elem.data.to_string()
|
||||
});
|
||||
let fqn = once(crate_name).chain(relative).collect();
|
||||
cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, kind));
|
||||
cx.renderinfo.borrow_mut().external_paths.insert(did, (fqn, kind));
|
||||
}
|
||||
}
|
||||
|
||||
@ -260,11 +260,6 @@ pub fn build_impls(cx: &DocContext,
|
||||
match def {
|
||||
cstore::DlImpl(did) => build_impl(cx, tcx, did, impls),
|
||||
cstore::DlDef(Def::Mod(did)) => {
|
||||
// Don't recurse if this is a #[doc(hidden)] module
|
||||
if load_attrs(cx, tcx, did).list("doc").has_word("hidden") {
|
||||
return;
|
||||
}
|
||||
|
||||
for item in tcx.sess.cstore.item_children(did) {
|
||||
populate_impls(cx, tcx, item.def, impls)
|
||||
}
|
||||
@ -295,16 +290,17 @@ pub fn build_impl(cx: &DocContext,
|
||||
tcx: &TyCtxt,
|
||||
did: DefId,
|
||||
ret: &mut Vec<clean::Item>) {
|
||||
if !cx.inlined.borrow_mut().as_mut().unwrap().insert(did) {
|
||||
if !cx.renderinfo.borrow_mut().inlined.insert(did) {
|
||||
return
|
||||
}
|
||||
|
||||
let attrs = load_attrs(cx, tcx, did);
|
||||
let associated_trait = tcx.impl_trait_ref(did);
|
||||
if let Some(ref t) = associated_trait {
|
||||
// If this is an impl for a #[doc(hidden)] trait, be sure to not inline
|
||||
let trait_attrs = load_attrs(cx, tcx, t.def_id);
|
||||
if trait_attrs.list("doc").has_word("hidden") {
|
||||
|
||||
// Only inline impl if the implemented trait is
|
||||
// reachable in rustdoc generated documentation
|
||||
if let Some(traitref) = associated_trait {
|
||||
if !cx.access_levels.borrow().is_doc_reachable(traitref.def_id) {
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -330,6 +326,17 @@ pub fn build_impl(cx: &DocContext,
|
||||
});
|
||||
}
|
||||
|
||||
let ty = tcx.lookup_item_type(did);
|
||||
let for_ = ty.ty.clean(cx);
|
||||
|
||||
// Only inline impl if the implementing type is
|
||||
// reachable in rustdoc generated documentation
|
||||
if let Some(did) = for_.def_id() {
|
||||
if !cx.access_levels.borrow().is_doc_reachable(did) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
let predicates = tcx.lookup_predicates(did);
|
||||
let trait_items = tcx.sess.cstore.impl_items(did)
|
||||
.iter()
|
||||
@ -412,7 +419,6 @@ pub fn build_impl(cx: &DocContext,
|
||||
}
|
||||
}).collect::<Vec<_>>();
|
||||
let polarity = tcx.trait_impl_polarity(did);
|
||||
let ty = tcx.lookup_item_type(did);
|
||||
let trait_ = associated_trait.clean(cx).map(|bound| {
|
||||
match bound {
|
||||
clean::TraitBound(polyt, _) => polyt.trait_,
|
||||
@ -436,7 +442,7 @@ pub fn build_impl(cx: &DocContext,
|
||||
derived: clean::detect_derived(&attrs),
|
||||
provided_trait_methods: provided,
|
||||
trait_: trait_,
|
||||
for_: ty.ty.clean(cx),
|
||||
for_: for_,
|
||||
generics: (&ty.generics, &predicates, subst::TypeSpace).clean(cx),
|
||||
items: trait_items,
|
||||
polarity: polarity.map(|p| { p.clean(cx) }),
|
||||
|
@ -36,6 +36,7 @@ use syntax::ptr::P;
|
||||
|
||||
use rustc_trans::back::link;
|
||||
use rustc::middle::cstore::{self, CrateStore};
|
||||
use rustc::middle::privacy::AccessLevels;
|
||||
use rustc::hir::def::Def;
|
||||
use rustc::hir::def_id::{DefId, DefIndex};
|
||||
use rustc::ty::subst::{self, ParamSpace, VecPerParamSpace};
|
||||
@ -47,15 +48,17 @@ use rustc::hir;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::u32;
|
||||
use std::env::current_dir;
|
||||
use std::mem;
|
||||
|
||||
use core::DocContext;
|
||||
use doctree;
|
||||
use visit_ast;
|
||||
use html::item_type::ItemType;
|
||||
|
||||
mod inline;
|
||||
pub mod inline;
|
||||
mod simplify;
|
||||
|
||||
// extract the stability index for a node from tcx, if possible
|
||||
@ -113,13 +116,16 @@ impl<T: Clean<U>, U> Clean<Vec<U>> for P<[T]> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Crate {
|
||||
pub name: String,
|
||||
pub src: PathBuf,
|
||||
pub module: Option<Item>,
|
||||
pub externs: Vec<(ast::CrateNum, ExternalCrate)>,
|
||||
pub primitives: Vec<PrimitiveType>,
|
||||
pub access_levels: Arc<AccessLevels<DefId>>,
|
||||
// These are later on moved into `CACHEKEY`, leaving the map empty.
|
||||
// Only here so that they can be filtered through the rustdoc passes.
|
||||
pub external_traits: HashMap<DefId, Trait>,
|
||||
}
|
||||
|
||||
@ -128,14 +134,20 @@ struct CrateNum(ast::CrateNum);
|
||||
impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
|
||||
fn clean(&self, cx: &DocContext) -> Crate {
|
||||
use rustc::session::config::Input;
|
||||
use ::visit_lib::LibEmbargoVisitor;
|
||||
|
||||
if let Some(t) = cx.tcx_opt() {
|
||||
cx.deref_trait_did.set(t.lang_items.deref_trait());
|
||||
cx.renderinfo.borrow_mut().deref_trait_did = cx.deref_trait_did.get();
|
||||
}
|
||||
|
||||
let mut externs = Vec::new();
|
||||
for cnum in cx.sess().cstore.crates() {
|
||||
externs.push((cnum, CrateNum(cnum).clean(cx)));
|
||||
if cx.tcx_opt().is_some() {
|
||||
// Analyze doc-reachability for extern items
|
||||
LibEmbargoVisitor::new(cx).visit_lib(cnum);
|
||||
}
|
||||
}
|
||||
externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
|
||||
|
||||
@ -205,14 +217,17 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
|
||||
Input::Str { ref name, .. } => PathBuf::from(name.clone()),
|
||||
};
|
||||
|
||||
let mut access_levels = cx.access_levels.borrow_mut();
|
||||
let mut external_traits = cx.external_traits.borrow_mut();
|
||||
|
||||
Crate {
|
||||
name: name.to_string(),
|
||||
src: src,
|
||||
module: Some(module),
|
||||
externs: externs,
|
||||
primitives: primitives,
|
||||
external_traits: cx.external_traits.borrow_mut().take()
|
||||
.unwrap_or(HashMap::new()),
|
||||
access_levels: Arc::new(mem::replace(&mut access_levels, Default::default())),
|
||||
external_traits: mem::replace(&mut external_traits, Default::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -541,8 +556,7 @@ impl Clean<TyParam> for hir::TyParam {
|
||||
|
||||
impl<'tcx> Clean<TyParam> for ty::TypeParameterDef<'tcx> {
|
||||
fn clean(&self, cx: &DocContext) -> TyParam {
|
||||
cx.external_typarams.borrow_mut().as_mut().unwrap()
|
||||
.insert(self.def_id, self.name.clean(cx));
|
||||
cx.renderinfo.borrow_mut().external_typarams.insert(self.def_id, self.name.clean(cx));
|
||||
TyParam {
|
||||
name: self.name.clean(cx),
|
||||
did: self.def_id,
|
||||
@ -2685,7 +2699,7 @@ fn register_def(cx: &DocContext, def: Def) -> DefId {
|
||||
inline::record_extern_fqn(cx, did, kind);
|
||||
if let TypeTrait = kind {
|
||||
let t = inline::build_external_trait(cx, tcx, did);
|
||||
cx.external_traits.borrow_mut().as_mut().unwrap().insert(did, t);
|
||||
cx.external_traits.borrow_mut().insert(did, t);
|
||||
}
|
||||
did
|
||||
}
|
||||
|
@ -29,12 +29,13 @@ use syntax::feature_gate::UnstableFeatures;
|
||||
use syntax::parse::token;
|
||||
|
||||
use std::cell::{RefCell, Cell};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
use visit_ast::RustdocVisitor;
|
||||
use clean;
|
||||
use clean::Clean;
|
||||
use html::render::RenderInfo;
|
||||
|
||||
pub use rustc::session::config::Input;
|
||||
pub use rustc::session::search_paths::SearchPaths;
|
||||
@ -45,19 +46,24 @@ pub enum MaybeTyped<'a, 'tcx: 'a> {
|
||||
NotTyped(&'a session::Session)
|
||||
}
|
||||
|
||||
pub type ExternalPaths = RefCell<Option<HashMap<DefId,
|
||||
(Vec<String>, clean::TypeKind)>>>;
|
||||
pub type Externs = HashMap<String, Vec<String>>;
|
||||
pub type ExternalPaths = HashMap<DefId, (Vec<String>, clean::TypeKind)>;
|
||||
|
||||
pub struct DocContext<'a, 'tcx: 'a> {
|
||||
pub map: &'a hir_map::Map<'tcx>,
|
||||
pub maybe_typed: MaybeTyped<'a, 'tcx>,
|
||||
pub input: Input,
|
||||
pub external_paths: ExternalPaths,
|
||||
pub external_traits: RefCell<Option<HashMap<DefId, clean::Trait>>>,
|
||||
pub external_typarams: RefCell<Option<HashMap<DefId, String>>>,
|
||||
pub inlined: RefCell<Option<HashSet<DefId>>>,
|
||||
pub all_crate_impls: RefCell<HashMap<ast::CrateNum, Vec<clean::Item>>>,
|
||||
pub deref_trait_did: Cell<Option<DefId>>,
|
||||
// Note that external items for which `doc(hidden)` applies to are shown as
|
||||
// non-reachable while local items aren't. This is because we're reusing
|
||||
// the access levels from crateanalysis.
|
||||
/// Later on moved into `clean::Crate`
|
||||
pub access_levels: RefCell<AccessLevels<DefId>>,
|
||||
/// Later on moved into `html::render::CACHE_KEY`
|
||||
pub renderinfo: RefCell<RenderInfo>,
|
||||
/// Later on moved through `clean::Crate` into `html::render::CACHE_KEY`
|
||||
pub external_traits: RefCell<HashMap<DefId, clean::Trait>>,
|
||||
}
|
||||
|
||||
impl<'b, 'tcx> DocContext<'b, 'tcx> {
|
||||
@ -81,20 +87,23 @@ impl<'b, 'tcx> DocContext<'b, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CrateAnalysis {
|
||||
pub access_levels: AccessLevels<DefId>,
|
||||
pub external_paths: ExternalPaths,
|
||||
pub external_typarams: RefCell<Option<HashMap<DefId, String>>>,
|
||||
pub inlined: RefCell<Option<HashSet<DefId>>>,
|
||||
pub deref_trait_did: Option<DefId>,
|
||||
pub trait DocAccessLevels {
|
||||
fn is_doc_reachable(&self, DefId) -> bool;
|
||||
}
|
||||
|
||||
pub type Externs = HashMap<String, Vec<String>>;
|
||||
impl DocAccessLevels for AccessLevels<DefId> {
|
||||
fn is_doc_reachable(&self, did: DefId) -> bool {
|
||||
self.is_public(did)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
|
||||
input: Input, triple: Option<String>)
|
||||
-> (clean::Crate, CrateAnalysis) {
|
||||
|
||||
pub fn run_core(search_paths: SearchPaths,
|
||||
cfgs: Vec<String>,
|
||||
externs: Externs,
|
||||
input: Input,
|
||||
triple: Option<String>) -> (clean::Crate, RenderInfo)
|
||||
{
|
||||
// Parse, resolve, and typecheck the given crate.
|
||||
|
||||
let cpath = match input {
|
||||
@ -148,7 +157,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
|
||||
let arenas = ty::CtxtArenas::new();
|
||||
let hir_map = driver::make_map(&sess, &mut hir_forest);
|
||||
|
||||
let krate_and_analysis = abort_on_err(driver::phase_3_run_analysis_passes(&sess,
|
||||
abort_on_err(driver::phase_3_run_analysis_passes(&sess,
|
||||
&cstore,
|
||||
hir_map,
|
||||
&arenas,
|
||||
@ -175,42 +184,20 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
|
||||
map: &tcx.map,
|
||||
maybe_typed: Typed(tcx),
|
||||
input: input,
|
||||
external_traits: RefCell::new(Some(HashMap::new())),
|
||||
external_typarams: RefCell::new(Some(HashMap::new())),
|
||||
external_paths: RefCell::new(Some(HashMap::new())),
|
||||
inlined: RefCell::new(Some(HashSet::new())),
|
||||
all_crate_impls: RefCell::new(HashMap::new()),
|
||||
deref_trait_did: Cell::new(None),
|
||||
access_levels: RefCell::new(access_levels),
|
||||
external_traits: RefCell::new(HashMap::new()),
|
||||
renderinfo: RefCell::new(Default::default()),
|
||||
};
|
||||
debug!("crate: {:?}", ctxt.map.krate());
|
||||
|
||||
let mut analysis = CrateAnalysis {
|
||||
access_levels: access_levels,
|
||||
external_paths: RefCell::new(None),
|
||||
external_typarams: RefCell::new(None),
|
||||
inlined: RefCell::new(None),
|
||||
deref_trait_did: None,
|
||||
};
|
||||
|
||||
let krate = {
|
||||
let mut v = RustdocVisitor::new(&ctxt, Some(&analysis));
|
||||
let mut v = RustdocVisitor::new(&ctxt);
|
||||
v.visit(ctxt.map.krate());
|
||||
v.clean(&ctxt)
|
||||
};
|
||||
|
||||
let external_paths = ctxt.external_paths.borrow_mut().take();
|
||||
*analysis.external_paths.borrow_mut() = external_paths;
|
||||
|
||||
let map = ctxt.external_typarams.borrow_mut().take();
|
||||
*analysis.external_typarams.borrow_mut() = map;
|
||||
|
||||
let map = ctxt.inlined.borrow_mut().take();
|
||||
*analysis.inlined.borrow_mut() = map;
|
||||
|
||||
analysis.deref_trait_did = ctxt.deref_trait_did.get();
|
||||
|
||||
Some((krate, analysis))
|
||||
}), &sess);
|
||||
|
||||
krate_and_analysis.unwrap()
|
||||
Some((krate, ctxt.renderinfo.into_inner()))
|
||||
}), &sess).unwrap()
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ use syntax::abi::Abi;
|
||||
use rustc::hir;
|
||||
|
||||
use clean;
|
||||
use core::DocAccessLevels;
|
||||
use html::item_type::ItemType;
|
||||
use html::render;
|
||||
use html::render::{cache, CURRENT_LOCATION_KEY};
|
||||
@ -298,6 +299,9 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> {
|
||||
let mut url = if did.is_local() || cache.inlined.contains(&did) {
|
||||
repeat("../").take(loc.len()).collect::<String>()
|
||||
} else {
|
||||
if !cache.access_levels.is_doc_reachable(did) {
|
||||
return None
|
||||
}
|
||||
match cache.extern_locations[&did.krate] {
|
||||
(_, render::Remote(ref s)) => s.to_string(),
|
||||
(_, render::Local) => repeat("../").take(loc.len()).collect(),
|
||||
|
@ -247,6 +247,11 @@ pub struct Cache {
|
||||
/// Set of definitions which have been inlined from external crates.
|
||||
pub inlined: HashSet<DefId>,
|
||||
|
||||
// Note that external items for which `doc(hidden)` applies to are shown as
|
||||
// non-reachable while local items aren't. This is because we're reusing
|
||||
// the access levels from crateanalysis.
|
||||
pub access_levels: Arc<AccessLevels<DefId>>,
|
||||
|
||||
// Private fields only used when initially crawling a crate to build a cache
|
||||
|
||||
stack: Vec<String>,
|
||||
@ -254,7 +259,6 @@ pub struct Cache {
|
||||
parent_is_trait_impl: bool,
|
||||
search_index: Vec<IndexItem>,
|
||||
stripped_mod: bool,
|
||||
access_levels: AccessLevels<DefId>,
|
||||
deref_trait_did: Option<DefId>,
|
||||
|
||||
// In rare case where a structure is defined in one module but implemented
|
||||
@ -265,6 +269,16 @@ pub struct Cache {
|
||||
orphan_methods: Vec<(DefId, clean::Item)>,
|
||||
}
|
||||
|
||||
/// Temporary storage for data obtained during `RustdocVisitor::clean()`.
|
||||
/// Later on moved into `CACHE_KEY`.
|
||||
#[derive(Default)]
|
||||
pub struct RenderInfo {
|
||||
pub inlined: HashSet<DefId>,
|
||||
pub external_paths: ::core::ExternalPaths,
|
||||
pub external_typarams: HashMap<DefId, String>,
|
||||
pub deref_trait_did: Option<DefId>,
|
||||
}
|
||||
|
||||
/// Helper struct to render all source code to HTML pages
|
||||
struct SourceCollector<'a> {
|
||||
scx: &'a mut SharedContext,
|
||||
@ -416,7 +430,8 @@ pub fn run(mut krate: clean::Crate,
|
||||
external_html: &ExternalHtml,
|
||||
dst: PathBuf,
|
||||
passes: HashSet<String>,
|
||||
css_file_extension: Option<PathBuf>) -> Result<(), Error> {
|
||||
css_file_extension: Option<PathBuf>,
|
||||
renderinfo: RenderInfo) -> Result<(), Error> {
|
||||
let src_root = match krate.src.parent() {
|
||||
Some(p) => p.to_path_buf(),
|
||||
None => PathBuf::new(),
|
||||
@ -483,19 +498,20 @@ pub fn run(mut krate: clean::Crate,
|
||||
};
|
||||
|
||||
// Crawl the crate to build various caches used for the output
|
||||
let analysis = ::ANALYSISKEY.with(|a| a.clone());
|
||||
let analysis = analysis.borrow();
|
||||
let access_levels = analysis.as_ref().map(|a| a.access_levels.clone());
|
||||
let access_levels = access_levels.unwrap_or(Default::default());
|
||||
let paths: HashMap<DefId, (Vec<String>, ItemType)> =
|
||||
analysis.as_ref().map(|a| {
|
||||
let paths = a.external_paths.borrow_mut().take().unwrap();
|
||||
paths.into_iter().map(|(k, (v, t))| (k, (v, ItemType::from_type_kind(t)))).collect()
|
||||
}).unwrap_or(HashMap::new());
|
||||
let RenderInfo {
|
||||
inlined,
|
||||
external_paths,
|
||||
external_typarams,
|
||||
deref_trait_did,
|
||||
} = renderinfo;
|
||||
|
||||
let paths = external_paths.into_iter()
|
||||
.map(|(k, (v, t))| (k, (v, ItemType::from_type_kind(t))))
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
let mut cache = Cache {
|
||||
impls: HashMap::new(),
|
||||
external_paths: paths.iter().map(|(&k, v)| (k, v.0.clone()))
|
||||
.collect(),
|
||||
external_paths: paths.iter().map(|(&k, v)| (k, v.0.clone())).collect(),
|
||||
paths: paths,
|
||||
implementors: HashMap::new(),
|
||||
stack: Vec::new(),
|
||||
@ -505,16 +521,12 @@ pub fn run(mut krate: clean::Crate,
|
||||
extern_locations: HashMap::new(),
|
||||
primitive_locations: HashMap::new(),
|
||||
stripped_mod: false,
|
||||
access_levels: access_levels,
|
||||
access_levels: krate.access_levels.clone(),
|
||||
orphan_methods: Vec::new(),
|
||||
traits: mem::replace(&mut krate.external_traits, HashMap::new()),
|
||||
deref_trait_did: analysis.as_ref().and_then(|a| a.deref_trait_did),
|
||||
typarams: analysis.as_ref().map(|a| {
|
||||
a.external_typarams.borrow_mut().take().unwrap()
|
||||
}).unwrap_or(HashMap::new()),
|
||||
inlined: analysis.as_ref().map(|a| {
|
||||
a.inlined.borrow_mut().take().unwrap()
|
||||
}).unwrap_or(HashSet::new()),
|
||||
deref_trait_did: deref_trait_did,
|
||||
typarams: external_typarams,
|
||||
inlined: inlined,
|
||||
};
|
||||
|
||||
// Cache where all our extern crates are located
|
||||
|
@ -48,14 +48,11 @@ extern crate rustc_unicode;
|
||||
|
||||
extern crate serialize as rustc_serialize; // used by deriving
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::default::Default;
|
||||
use std::env;
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
use std::rc::Rc;
|
||||
use std::sync::mpsc::channel;
|
||||
|
||||
use externalfiles::ExternalHtml;
|
||||
@ -83,6 +80,7 @@ pub mod markdown;
|
||||
pub mod passes;
|
||||
pub mod plugins;
|
||||
pub mod visit_ast;
|
||||
pub mod visit_lib;
|
||||
pub mod test;
|
||||
mod flock;
|
||||
|
||||
@ -113,12 +111,9 @@ const DEFAULT_PASSES: &'static [&'static str] = &[
|
||||
"unindent-comments",
|
||||
];
|
||||
|
||||
thread_local!(pub static ANALYSISKEY: Rc<RefCell<Option<core::CrateAnalysis>>> = {
|
||||
Rc::new(RefCell::new(None))
|
||||
});
|
||||
|
||||
struct Output {
|
||||
krate: clean::Crate,
|
||||
renderinfo: html::render::RenderInfo,
|
||||
passes: Vec<String>,
|
||||
}
|
||||
|
||||
@ -302,14 +297,15 @@ pub fn main_args(args: &[String]) -> isize {
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
let Output { krate, passes, } = out;
|
||||
let Output { krate, passes, renderinfo } = out;
|
||||
info!("going to format");
|
||||
match matches.opt_str("w").as_ref().map(|s| &**s) {
|
||||
Some("html") | None => {
|
||||
html::render::run(krate, &external_html,
|
||||
output.unwrap_or(PathBuf::from("doc")),
|
||||
passes.into_iter().collect(),
|
||||
css_file_extension)
|
||||
css_file_extension,
|
||||
renderinfo)
|
||||
.expect("failed to generate documentation")
|
||||
}
|
||||
Some(s) => {
|
||||
@ -380,12 +376,8 @@ fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matche
|
||||
tx.send(core::run_core(paths, cfgs, externs, Input::File(cr),
|
||||
triple)).unwrap();
|
||||
});
|
||||
let (mut krate, analysis) = rx.recv().unwrap();
|
||||
let (mut krate, renderinfo) = rx.recv().unwrap();
|
||||
info!("finished with rustc");
|
||||
let mut analysis = Some(analysis);
|
||||
ANALYSISKEY.with(|s| {
|
||||
*s.borrow_mut() = analysis.take();
|
||||
});
|
||||
|
||||
if let Some(name) = matches.opt_str("crate-name") {
|
||||
krate.name = name
|
||||
@ -443,5 +435,5 @@ fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matche
|
||||
// Run everything!
|
||||
info!("Executing passes/plugins");
|
||||
let krate = pm.run_plugins(krate);
|
||||
Output { krate: krate, passes: passes }
|
||||
Output { krate: krate, renderinfo: renderinfo, passes: passes }
|
||||
}
|
||||
|
@ -87,10 +87,7 @@ pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult {
|
||||
pub fn strip_private(mut krate: clean::Crate) -> plugins::PluginResult {
|
||||
// This stripper collects all *retained* nodes.
|
||||
let mut retained = DefIdSet();
|
||||
let analysis = super::ANALYSISKEY.with(|a| a.clone());
|
||||
let analysis = analysis.borrow();
|
||||
let analysis = analysis.as_ref().unwrap();
|
||||
let access_levels = analysis.access_levels.clone();
|
||||
let access_levels = krate.access_levels.clone();
|
||||
|
||||
// strip all private items
|
||||
{
|
||||
|
@ -108,15 +108,14 @@ pub fn run(input: &str,
|
||||
map: &map,
|
||||
maybe_typed: core::NotTyped(&sess),
|
||||
input: input,
|
||||
external_paths: RefCell::new(Some(HashMap::new())),
|
||||
external_traits: RefCell::new(None),
|
||||
external_typarams: RefCell::new(None),
|
||||
inlined: RefCell::new(None),
|
||||
external_traits: RefCell::new(HashMap::new()),
|
||||
all_crate_impls: RefCell::new(HashMap::new()),
|
||||
deref_trait_did: Cell::new(None),
|
||||
access_levels: Default::default(),
|
||||
renderinfo: Default::default(),
|
||||
};
|
||||
|
||||
let mut v = RustdocVisitor::new(&ctx, None);
|
||||
let mut v = RustdocVisitor::new(&ctx);
|
||||
v.visit(ctx.map.krate());
|
||||
let mut krate = v.clean(&ctx);
|
||||
if let Some(name) = crate_name {
|
||||
|
@ -21,12 +21,14 @@ use syntax::attr::AttrMetaMethods;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
use rustc::hir::map as hir_map;
|
||||
use rustc::hir::def::Def;
|
||||
use rustc::middle::stability;
|
||||
use rustc::middle::privacy::AccessLevel;
|
||||
|
||||
use rustc::hir;
|
||||
|
||||
use core;
|
||||
use clean::{Clean, Attributes};
|
||||
use clean::{self, Clean, Attributes};
|
||||
use doctree::*;
|
||||
|
||||
// looks to me like the first two of these are actually
|
||||
@ -41,14 +43,12 @@ pub struct RustdocVisitor<'a, 'tcx: 'a> {
|
||||
pub module: Module,
|
||||
pub attrs: hir::HirVec<ast::Attribute>,
|
||||
pub cx: &'a core::DocContext<'a, 'tcx>,
|
||||
pub analysis: Option<&'a core::CrateAnalysis>,
|
||||
view_item_stack: HashSet<ast::NodeId>,
|
||||
inlining_from_glob: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
pub fn new(cx: &'a core::DocContext<'a, 'tcx>,
|
||||
analysis: Option<&'a core::CrateAnalysis>) -> RustdocVisitor<'a, 'tcx> {
|
||||
pub fn new(cx: &'a core::DocContext<'a, 'tcx>) -> RustdocVisitor<'a, 'tcx> {
|
||||
// If the root is reexported, terminate all recursion.
|
||||
let mut stack = HashSet::new();
|
||||
stack.insert(ast::CRATE_NODE_ID);
|
||||
@ -56,7 +56,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
module: Module::new(None),
|
||||
attrs: hir::HirVec::new(),
|
||||
cx: cx,
|
||||
analysis: analysis,
|
||||
view_item_stack: stack,
|
||||
inlining_from_glob: false,
|
||||
}
|
||||
@ -243,20 +242,41 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
Some(tcx) => tcx,
|
||||
None => return false
|
||||
};
|
||||
let def = tcx.def_map.borrow()[&id].def_id();
|
||||
let def_node_id = match tcx.map.as_local_node_id(def) {
|
||||
Some(n) => n, None => return false
|
||||
};
|
||||
let analysis = match self.analysis {
|
||||
Some(analysis) => analysis, None => return false
|
||||
};
|
||||
let def = tcx.def_map.borrow()[&id];
|
||||
let def_did = def.def_id();
|
||||
|
||||
let use_attrs = tcx.map.attrs(id).clean(self.cx);
|
||||
|
||||
let is_private = !analysis.access_levels.is_public(def);
|
||||
let is_hidden = inherits_doc_hidden(self.cx, def_node_id);
|
||||
let is_no_inline = use_attrs.list("doc").has_word("no_inline");
|
||||
|
||||
// For cross-crate impl inlining we need to know whether items are
|
||||
// reachable in documentation - a previously nonreachable item can be
|
||||
// made reachable by cross-crate inlining which we're checking here.
|
||||
// (this is done here because we need to know this upfront)
|
||||
if !def.def_id().is_local() && !is_no_inline {
|
||||
let attrs = clean::inline::load_attrs(self.cx, tcx, def_did);
|
||||
let self_is_hidden = attrs.list("doc").has_word("hidden");
|
||||
match def.base_def {
|
||||
Def::Trait(did) |
|
||||
Def::Struct(did) |
|
||||
Def::Enum(did) |
|
||||
Def::TyAlias(did) if !self_is_hidden => {
|
||||
self.cx.access_levels.borrow_mut().map.insert(did, AccessLevel::Public);
|
||||
},
|
||||
Def::Mod(did) => if !self_is_hidden {
|
||||
::visit_lib::LibEmbargoVisitor::new(self.cx).visit_mod(did);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
let def_node_id = match tcx.map.as_local_node_id(def_did) {
|
||||
Some(n) => n, None => return false
|
||||
};
|
||||
|
||||
let is_private = !self.cx.access_levels.borrow().is_public(def_did);
|
||||
let is_hidden = inherits_doc_hidden(self.cx, def_node_id);
|
||||
|
||||
// Only inline if requested or if the item would otherwise be stripped
|
||||
if (!please_inline && !is_private && !is_hidden) || is_no_inline {
|
||||
return false
|
||||
|
108
src/librustdoc/visit_lib.rs
Normal file
108
src/librustdoc/visit_lib.rs
Normal file
@ -0,0 +1,108 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
use rustc::middle::cstore::{CrateStore, ChildItem, DefLike};
|
||||
use rustc::middle::privacy::{AccessLevels, AccessLevel};
|
||||
use rustc::hir::def::Def;
|
||||
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
|
||||
use rustc::ty::Visibility;
|
||||
use syntax::ast;
|
||||
|
||||
use std::cell::RefMut;
|
||||
|
||||
use clean::{Attributes, Clean};
|
||||
|
||||
// FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses
|
||||
|
||||
/// Similar to `librustc_privacy::EmbargoVisitor`, but also takes
|
||||
/// specific rustdoc annotations into account (i.e. `doc(hidden)`)
|
||||
pub struct LibEmbargoVisitor<'a, 'b: 'a, 'tcx: 'b> {
|
||||
cx: &'a ::core::DocContext<'b, 'tcx>,
|
||||
cstore: &'a CrateStore<'tcx>,
|
||||
// Accessibility levels for reachable nodes
|
||||
access_levels: RefMut<'a, AccessLevels<DefId>>,
|
||||
// Previous accessibility level, None means unreachable
|
||||
prev_level: Option<AccessLevel>,
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> {
|
||||
pub fn new(cx: &'a ::core::DocContext<'b, 'tcx>) -> LibEmbargoVisitor<'a, 'b, 'tcx> {
|
||||
LibEmbargoVisitor {
|
||||
cx: cx,
|
||||
cstore: &*cx.sess().cstore,
|
||||
access_levels: cx.access_levels.borrow_mut(),
|
||||
prev_level: Some(AccessLevel::Public),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_lib(&mut self, cnum: ast::CrateNum) {
|
||||
let did = DefId { krate: cnum, index: CRATE_DEF_INDEX };
|
||||
self.visit_mod(did);
|
||||
}
|
||||
|
||||
// Updates node level and returns the updated level
|
||||
fn update(&mut self, did: DefId, level: Option<AccessLevel>) -> Option<AccessLevel> {
|
||||
let attrs: Vec<_> = self.cx.tcx().get_attrs(did).iter()
|
||||
.map(|a| a.clean(self.cx))
|
||||
.collect();
|
||||
let is_hidden = attrs.list("doc").has_word("hidden");
|
||||
|
||||
let old_level = self.access_levels.map.get(&did).cloned();
|
||||
// Accessibility levels can only grow
|
||||
if level > old_level && !is_hidden {
|
||||
self.access_levels.map.insert(did, level.unwrap());
|
||||
level
|
||||
} else {
|
||||
old_level
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_mod(&mut self, did: DefId) {
|
||||
for item in self.cstore.item_children(did) {
|
||||
if let DefLike::DlDef(def) = item.def {
|
||||
match def {
|
||||
Def::Mod(did) |
|
||||
Def::ForeignMod(did) |
|
||||
Def::Trait(did) |
|
||||
Def::Struct(did) |
|
||||
Def::Enum(did) |
|
||||
Def::TyAlias(did) |
|
||||
Def::Fn(did) |
|
||||
Def::Method(did) |
|
||||
Def::Static(did, _) |
|
||||
Def::Const(did) => self.visit_item(did, item),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, did: DefId, item: ChildItem) {
|
||||
let inherited_item_level = match item.def {
|
||||
DefLike::DlImpl(..) | DefLike::DlField => unreachable!(),
|
||||
DefLike::DlDef(def) => {
|
||||
match def {
|
||||
Def::ForeignMod(..) => self.prev_level,
|
||||
_ => if item.vis == Visibility::Public { self.prev_level } else { None }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let item_level = self.update(did, inherited_item_level);
|
||||
|
||||
if let DefLike::DlDef(Def::Mod(did)) = item.def {
|
||||
let orig_level = self.prev_level;
|
||||
|
||||
self.prev_level = item_level;
|
||||
self.visit_mod(did);
|
||||
self.prev_level = orig_level;
|
||||
}
|
||||
}
|
||||
}
|
22
src/test/auxiliary/rustdoc-hidden-sig.rs
Normal file
22
src/test/auxiliary/rustdoc-hidden-sig.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
pub struct Bar;
|
||||
|
||||
impl Bar {
|
||||
pub fn bar(_: u8) -> hidden::Hidden {
|
||||
hidden::Hidden
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod hidden {
|
||||
pub struct Hidden;
|
||||
}
|
44
src/test/auxiliary/rustdoc-nonreachable-impls.rs
Normal file
44
src/test/auxiliary/rustdoc-nonreachable-impls.rs
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
pub struct Foo;
|
||||
|
||||
pub trait Woof {}
|
||||
pub trait Bark {}
|
||||
|
||||
mod private {
|
||||
// should be shown
|
||||
impl ::Woof for ::Foo {}
|
||||
|
||||
pub trait Bar {}
|
||||
pub struct Wibble;
|
||||
|
||||
// these should not be shown
|
||||
impl Bar for ::Foo {}
|
||||
impl Bar for Wibble {}
|
||||
impl ::Bark for Wibble {}
|
||||
impl ::Woof for Wibble {}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod hidden {
|
||||
// should be shown
|
||||
impl ::Bark for ::Foo {}
|
||||
|
||||
pub trait Qux {}
|
||||
pub struct Wobble;
|
||||
|
||||
|
||||
// these should only be shown if they're reexported correctly
|
||||
impl Qux for ::Foo {}
|
||||
impl Qux for Wobble {}
|
||||
impl ::Bark for Wobble {}
|
||||
impl ::Woof for Wobble {}
|
||||
}
|
23
src/test/rustdoc/inline_cross/issue-28480.rs
Normal file
23
src/test/rustdoc/inline_cross/issue-28480.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2016 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:rustdoc-hidden-sig.rs
|
||||
// build-aux-docs
|
||||
// ignore-cross-compile
|
||||
|
||||
// @has rustdoc_hidden_sig/struct.Bar.html
|
||||
// @!has - '//a/@title' 'Hidden'
|
||||
// @has - '//a' 'u8'
|
||||
extern crate rustdoc_hidden_sig;
|
||||
|
||||
// @has issue_28480/struct.Bar.html
|
||||
// @!has - '//a/@title' 'Hidden'
|
||||
// @has - '//a' 'u8'
|
||||
pub use rustdoc_hidden_sig::Bar;
|
37
src/test/rustdoc/inline_cross/issue-31948-1.rs
Normal file
37
src/test/rustdoc/inline_cross/issue-31948-1.rs
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright 2016 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:rustdoc-nonreachable-impls.rs
|
||||
// build-aux-docs
|
||||
// ignore-cross-compile
|
||||
|
||||
extern crate rustdoc_nonreachable_impls;
|
||||
|
||||
// @has issue_31948_1/struct.Wobble.html
|
||||
// @has - '//*[@class="impl"]//code' 'Bark for'
|
||||
// @has - '//*[@class="impl"]//code' 'Woof for'
|
||||
// @!has - '//*[@class="impl"]//code' 'Bar for'
|
||||
// @!has - '//*[@class="impl"]//code' 'Qux for'
|
||||
pub use rustdoc_nonreachable_impls::hidden::Wobble;
|
||||
|
||||
// @has issue_31948_1/trait.Bark.html
|
||||
// FIXME(33025): has - '//code' 'for Foo'
|
||||
// @has - '//code' 'for Wobble'
|
||||
// @!has - '//code' 'for Wibble'
|
||||
pub use rustdoc_nonreachable_impls::Bark;
|
||||
|
||||
// @has issue_31948_1/trait.Woof.html
|
||||
// FIXME(33025): has - '//code' 'for Foo'
|
||||
// @has - '//code' 'for Wobble'
|
||||
// @!has - '//code' 'for Wibble'
|
||||
pub use rustdoc_nonreachable_impls::Woof;
|
||||
|
||||
// @!has issue_31948_1/trait.Bar.html
|
||||
// @!has issue_31948_1/trait.Qux.html
|
31
src/test/rustdoc/inline_cross/issue-31948-2.rs
Normal file
31
src/test/rustdoc/inline_cross/issue-31948-2.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2016 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:rustdoc-nonreachable-impls.rs
|
||||
// build-aux-docs
|
||||
// ignore-cross-compile
|
||||
|
||||
extern crate rustdoc_nonreachable_impls;
|
||||
|
||||
// @has issue_31948_2/struct.Wobble.html
|
||||
// @has - '//*[@class="impl"]//code' 'Qux for'
|
||||
// @has - '//*[@class="impl"]//code' 'Bark for'
|
||||
// @has - '//*[@class="impl"]//code' 'Woof for'
|
||||
// @!has - '//*[@class="impl"]//code' 'Bar for'
|
||||
pub use rustdoc_nonreachable_impls::hidden::Wobble;
|
||||
|
||||
// @has issue_31948_2/trait.Qux.html
|
||||
// FIXME(33025): has - '//code' 'for Foo'
|
||||
// @has - '//code' 'for Wobble'
|
||||
pub use rustdoc_nonreachable_impls::hidden::Qux;
|
||||
|
||||
// @!has issue_31948_2/trait.Bar.html
|
||||
// @!has issue_31948_2/trait.Woof.html
|
||||
// @!has issue_31948_2/trait.Bark.html
|
39
src/test/rustdoc/inline_cross/issue-31948.rs
Normal file
39
src/test/rustdoc/inline_cross/issue-31948.rs
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2016 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:rustdoc-nonreachable-impls.rs
|
||||
// build-aux-docs
|
||||
// ignore-cross-compile
|
||||
|
||||
extern crate rustdoc_nonreachable_impls;
|
||||
|
||||
// @has issue_31948/struct.Foo.html
|
||||
// @has - '//*[@class="impl"]//code' 'Bark for'
|
||||
// @has - '//*[@class="impl"]//code' 'Woof for'
|
||||
// @!has - '//*[@class="impl"]//code' 'Bar for'
|
||||
// @!has - '//*[@class="impl"]//code' 'Qux for'
|
||||
pub use rustdoc_nonreachable_impls::Foo;
|
||||
|
||||
// @has issue_31948/trait.Bark.html
|
||||
// @has - '//code' 'for Foo'
|
||||
// @!has - '//code' 'for Wibble'
|
||||
// @!has - '//code' 'for Wobble'
|
||||
pub use rustdoc_nonreachable_impls::Bark;
|
||||
|
||||
// @has issue_31948/trait.Woof.html
|
||||
// @has - '//code' 'for Foo'
|
||||
// @!has - '//code' 'for Wibble'
|
||||
// @!has - '//code' 'for Wobble'
|
||||
pub use rustdoc_nonreachable_impls::Woof;
|
||||
|
||||
// @!has issue_31948/trait.Bar.html
|
||||
// @!has issue_31948/trait.Qux.html
|
||||
// @!has issue_31948/struct.Wibble.html
|
||||
// @!has issue_31948/struct.Wobble.html
|
Loading…
Reference in New Issue
Block a user