提交 77b409a6 编写于 作者: M mitaa

Reachability check cross-crate links

上级 cfad7ad9
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
use rustc_const_eval::lookup_const_by_id; use rustc_const_eval::lookup_const_by_id;
use core::DocContext; use core::{DocContext, DocAccessLevels};
use doctree; use doctree;
use clean::{self, GetDefId}; use clean::{self, GetDefId};
...@@ -227,15 +227,6 @@ fn build_type(cx: &DocContext, tcx: &TyCtxt, did: DefId) -> clean::ItemEnum { ...@@ -227,15 +227,6 @@ fn build_type(cx: &DocContext, tcx: &TyCtxt, did: DefId) -> clean::ItemEnum {
}, false) }, false)
} }
fn is_item_doc_reachable(cx: &DocContext, did: DefId) -> bool {
use ::visit_lib::LibEmbargoVisitor;
if cx.analyzed_crates.borrow_mut().insert(did.krate) {
LibEmbargoVisitor::new(cx).visit_lib(did.krate);
}
cx.access_levels.borrow().is_public(did)
}
pub fn build_impls(cx: &DocContext, pub fn build_impls(cx: &DocContext,
tcx: &TyCtxt, tcx: &TyCtxt,
did: DefId) -> Vec<clean::Item> { did: DefId) -> Vec<clean::Item> {
...@@ -309,7 +300,7 @@ pub fn build_impl(cx: &DocContext, ...@@ -309,7 +300,7 @@ pub fn build_impl(cx: &DocContext,
// Only inline impl if the implemented trait is // Only inline impl if the implemented trait is
// reachable in rustdoc generated documentation // reachable in rustdoc generated documentation
if let Some(traitref) = associated_trait { if let Some(traitref) = associated_trait {
if !is_item_doc_reachable(cx, traitref.def_id) { if !cx.access_levels.borrow().is_doc_reachable(traitref.def_id) {
return return
} }
} }
...@@ -341,7 +332,7 @@ pub fn build_impl(cx: &DocContext, ...@@ -341,7 +332,7 @@ pub fn build_impl(cx: &DocContext,
// Only inline impl if the implementing type is // Only inline impl if the implementing type is
// reachable in rustdoc generated documentation // reachable in rustdoc generated documentation
if let Some(did) = for_.def_id() { if let Some(did) = for_.def_id() {
if !is_item_doc_reachable(cx, did) { if !cx.access_levels.borrow().is_doc_reachable(did) {
return return
} }
} }
......
...@@ -133,6 +133,7 @@ pub struct Crate { ...@@ -133,6 +133,7 @@ pub struct Crate {
impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> { impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
fn clean(&self, cx: &DocContext) -> Crate { fn clean(&self, cx: &DocContext) -> Crate {
use rustc::session::config::Input; use rustc::session::config::Input;
use ::visit_lib::LibEmbargoVisitor;
if let Some(t) = cx.tcx_opt() { if let Some(t) = cx.tcx_opt() {
cx.deref_trait_did.set(t.lang_items.deref_trait()); cx.deref_trait_did.set(t.lang_items.deref_trait());
...@@ -142,6 +143,10 @@ fn clean(&self, cx: &DocContext) -> Crate { ...@@ -142,6 +143,10 @@ fn clean(&self, cx: &DocContext) -> Crate {
let mut externs = Vec::new(); let mut externs = Vec::new();
for cnum in cx.sess().cstore.crates() { for cnum in cx.sess().cstore.crates() {
externs.push((cnum, CrateNum(cnum).clean(cx))); 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)); externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
use rustc::dep_graph::DepGraph; use rustc::dep_graph::DepGraph;
use rustc::session::{self, config}; use rustc::session::{self, config};
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc::middle::cstore::LOCAL_CRATE;
use rustc::middle::privacy::AccessLevels; use rustc::middle::privacy::AccessLevels;
use rustc::ty::{self, TyCtxt}; use rustc::ty::{self, TyCtxt};
use rustc::hir::map as hir_map; use rustc::hir::map as hir_map;
...@@ -30,7 +29,7 @@ ...@@ -30,7 +29,7 @@
use syntax::parse::token; use syntax::parse::token;
use std::cell::{RefCell, Cell}; use std::cell::{RefCell, Cell};
use std::collections::{HashMap, HashSet}; use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use visit_ast::RustdocVisitor; use visit_ast::RustdocVisitor;
...@@ -47,6 +46,7 @@ pub enum MaybeTyped<'a, 'tcx: 'a> { ...@@ -47,6 +46,7 @@ pub enum MaybeTyped<'a, 'tcx: 'a> {
NotTyped(&'a session::Session) NotTyped(&'a session::Session)
} }
pub type Externs = HashMap<String, Vec<String>>;
pub type ExternalPaths = HashMap<DefId, (Vec<String>, clean::TypeKind)>; pub type ExternalPaths = HashMap<DefId, (Vec<String>, clean::TypeKind)>;
pub struct DocContext<'a, 'tcx: 'a> { pub struct DocContext<'a, 'tcx: 'a> {
...@@ -55,8 +55,6 @@ pub struct DocContext<'a, 'tcx: 'a> { ...@@ -55,8 +55,6 @@ pub struct DocContext<'a, 'tcx: 'a> {
pub input: Input, pub input: Input,
pub all_crate_impls: RefCell<HashMap<ast::CrateNum, Vec<clean::Item>>>, pub all_crate_impls: RefCell<HashMap<ast::CrateNum, Vec<clean::Item>>>,
pub deref_trait_did: Cell<Option<DefId>>, pub deref_trait_did: Cell<Option<DefId>>,
/// Crates which have already been processed for `Self.access_levels`
pub analyzed_crates: RefCell<HashSet<ast::CrateNum>>,
// Note that external items for which `doc(hidden)` applies to are shown as // 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 // non-reachable while local items aren't. This is because we're reusing
// the access levels from crateanalysis. // the access levels from crateanalysis.
...@@ -89,7 +87,16 @@ pub fn tcx<'a>(&'a self) -> &'a TyCtxt<'tcx> { ...@@ -89,7 +87,16 @@ pub fn tcx<'a>(&'a self) -> &'a TyCtxt<'tcx> {
} }
} }
pub type Externs = HashMap<String, Vec<String>>; pub trait DocAccessLevels {
fn is_doc_reachable(&self, DefId) -> bool;
}
impl DocAccessLevels for AccessLevels<DefId> {
fn is_doc_reachable(&self, did: DefId) -> bool {
self.is_public(did)
}
}
pub fn run_core(search_paths: SearchPaths, pub fn run_core(search_paths: SearchPaths,
cfgs: Vec<String>, cfgs: Vec<String>,
...@@ -172,8 +179,6 @@ pub fn run_core(search_paths: SearchPaths, ...@@ -172,8 +179,6 @@ pub fn run_core(search_paths: SearchPaths,
.map(|(k, v)| (tcx.map.local_def_id(k), v)) .map(|(k, v)| (tcx.map.local_def_id(k), v))
.collect() .collect()
}; };
let mut analyzed_crates = HashSet::new();
analyzed_crates.insert(LOCAL_CRATE);
let ctxt = DocContext { let ctxt = DocContext {
map: &tcx.map, map: &tcx.map,
...@@ -181,7 +186,6 @@ pub fn run_core(search_paths: SearchPaths, ...@@ -181,7 +186,6 @@ pub fn run_core(search_paths: SearchPaths,
input: input, input: input,
all_crate_impls: RefCell::new(HashMap::new()), all_crate_impls: RefCell::new(HashMap::new()),
deref_trait_did: Cell::new(None), deref_trait_did: Cell::new(None),
analyzed_crates: RefCell::new(analyzed_crates),
access_levels: RefCell::new(access_levels), access_levels: RefCell::new(access_levels),
external_traits: RefCell::new(HashMap::new()), external_traits: RefCell::new(HashMap::new()),
renderinfo: RefCell::new(Default::default()), renderinfo: RefCell::new(Default::default()),
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
use rustc::hir; use rustc::hir;
use clean; use clean;
use core::DocAccessLevels;
use html::item_type::ItemType; use html::item_type::ItemType;
use html::render; use html::render;
use html::render::{cache, CURRENT_LOCATION_KEY}; use html::render::{cache, CURRENT_LOCATION_KEY};
...@@ -298,6 +299,9 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> { ...@@ -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) { let mut url = if did.is_local() || cache.inlined.contains(&did) {
repeat("../").take(loc.len()).collect::<String>() repeat("../").take(loc.len()).collect::<String>()
} else { } else {
if !cache.access_levels.is_doc_reachable(did) {
return None
}
match cache.extern_locations[&did.krate] { match cache.extern_locations[&did.krate] {
(_, render::Remote(ref s)) => s.to_string(), (_, render::Remote(ref s)) => s.to_string(),
(_, render::Local) => repeat("../").take(loc.len()).collect(), (_, render::Local) => repeat("../").take(loc.len()).collect(),
......
...@@ -246,6 +246,11 @@ pub struct Cache { ...@@ -246,6 +246,11 @@ pub struct Cache {
/// Set of definitions which have been inlined from external crates. /// Set of definitions which have been inlined from external crates.
pub inlined: HashSet<DefId>, 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 // Private fields only used when initially crawling a crate to build a cache
stack: Vec<String>, stack: Vec<String>,
...@@ -253,10 +258,6 @@ pub struct Cache { ...@@ -253,10 +258,6 @@ pub struct Cache {
parent_is_trait_impl: bool, parent_is_trait_impl: bool,
search_index: Vec<IndexItem>, search_index: Vec<IndexItem>,
stripped_mod: bool, stripped_mod: bool,
// 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.
access_levels: Arc<AccessLevels<DefId>>,
deref_trait_did: Option<DefId>, deref_trait_did: Option<DefId>,
// In rare case where a structure is defined in one module but implemented // In rare case where a structure is defined in one module but implemented
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
// except according to those terms. // except according to those terms.
use std::cell::{RefCell, Cell}; use std::cell::{RefCell, Cell};
use std::collections::{HashMap, HashSet}; use std::collections::HashMap;
use std::env; use std::env;
use std::ffi::OsString; use std::ffi::OsString;
use std::io::prelude::*; use std::io::prelude::*;
...@@ -111,7 +111,6 @@ pub fn run(input: &str, ...@@ -111,7 +111,6 @@ pub fn run(input: &str,
external_traits: RefCell::new(HashMap::new()), external_traits: RefCell::new(HashMap::new()),
all_crate_impls: RefCell::new(HashMap::new()), all_crate_impls: RefCell::new(HashMap::new()),
deref_trait_did: Cell::new(None), deref_trait_did: Cell::new(None),
analyzed_crates: RefCell::new(HashSet::new()),
access_levels: Default::default(), access_levels: Default::default(),
renderinfo: Default::default(), renderinfo: Default::default(),
}; };
......
...@@ -19,8 +19,7 @@ ...@@ -19,8 +19,7 @@
use clean::{Attributes, Clean}; use clean::{Attributes, Clean};
// FIXME: since this is only used for cross-crate impl inlining this only // FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses
// handles traits and items for which traits can be implemented
/// Similar to `librustc_privacy::EmbargoVisitor`, but also takes /// Similar to `librustc_privacy::EmbargoVisitor`, but also takes
/// specific rustdoc annotations into account (i.e. `doc(hidden)`) /// specific rustdoc annotations into account (i.e. `doc(hidden)`)
...@@ -69,11 +68,16 @@ pub fn visit_mod(&mut self, did: DefId) { ...@@ -69,11 +68,16 @@ pub fn visit_mod(&mut self, did: DefId) {
for item in self.cstore.item_children(did) { for item in self.cstore.item_children(did) {
if let DefLike::DlDef(def) = item.def { if let DefLike::DlDef(def) = item.def {
match def { match def {
Def::Mod(did) |
Def::ForeignMod(did) |
Def::Trait(did) | Def::Trait(did) |
Def::Struct(did) | Def::Struct(did) |
Def::Mod(did) |
Def::Enum(did) | Def::Enum(did) |
Def::TyAlias(did) => self.visit_item(did, item), Def::TyAlias(did) |
Def::Fn(did) |
Def::Method(did) |
Def::Static(did, _) |
Def::Const(did) => self.visit_item(did, item),
_ => {} _ => {}
} }
} }
......
// 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;
}
// 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;
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册