Skip to content

Commit 77b409a

Browse files
committed
Reachability check cross-crate links
1 parent cfad7ad commit 77b409a

File tree

9 files changed

+83
-30
lines changed

9 files changed

+83
-30
lines changed

src/librustdoc/clean/inline.rs

+3-12
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use rustc::middle::stability;
2626

2727
use rustc_const_eval::lookup_const_by_id;
2828

29-
use core::DocContext;
29+
use core::{DocContext, DocAccessLevels};
3030
use doctree;
3131
use clean::{self, GetDefId};
3232

@@ -227,15 +227,6 @@ fn build_type(cx: &DocContext, tcx: &TyCtxt, did: DefId) -> clean::ItemEnum {
227227
}, false)
228228
}
229229

230-
fn is_item_doc_reachable(cx: &DocContext, did: DefId) -> bool {
231-
use ::visit_lib::LibEmbargoVisitor;
232-
233-
if cx.analyzed_crates.borrow_mut().insert(did.krate) {
234-
LibEmbargoVisitor::new(cx).visit_lib(did.krate);
235-
}
236-
cx.access_levels.borrow().is_public(did)
237-
}
238-
239230
pub fn build_impls(cx: &DocContext,
240231
tcx: &TyCtxt,
241232
did: DefId) -> Vec<clean::Item> {
@@ -309,7 +300,7 @@ pub fn build_impl(cx: &DocContext,
309300
// Only inline impl if the implemented trait is
310301
// reachable in rustdoc generated documentation
311302
if let Some(traitref) = associated_trait {
312-
if !is_item_doc_reachable(cx, traitref.def_id) {
303+
if !cx.access_levels.borrow().is_doc_reachable(traitref.def_id) {
313304
return
314305
}
315306
}
@@ -341,7 +332,7 @@ pub fn build_impl(cx: &DocContext,
341332
// Only inline impl if the implementing type is
342333
// reachable in rustdoc generated documentation
343334
if let Some(did) = for_.def_id() {
344-
if !is_item_doc_reachable(cx, did) {
335+
if !cx.access_levels.borrow().is_doc_reachable(did) {
345336
return
346337
}
347338
}

src/librustdoc/clean/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ struct CrateNum(ast::CrateNum);
133133
impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
134134
fn clean(&self, cx: &DocContext) -> Crate {
135135
use rustc::session::config::Input;
136+
use ::visit_lib::LibEmbargoVisitor;
136137

137138
if let Some(t) = cx.tcx_opt() {
138139
cx.deref_trait_did.set(t.lang_items.deref_trait());
@@ -142,6 +143,10 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
142143
let mut externs = Vec::new();
143144
for cnum in cx.sess().cstore.crates() {
144145
externs.push((cnum, CrateNum(cnum).clean(cx)));
146+
if cx.tcx_opt().is_some() {
147+
// Analyze doc-reachability for extern items
148+
LibEmbargoVisitor::new(cx).visit_lib(cnum);
149+
}
145150
}
146151
externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
147152

src/librustdoc/core.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use rustc_driver::{driver, target_features, abort_on_err};
1414
use rustc::dep_graph::DepGraph;
1515
use rustc::session::{self, config};
1616
use rustc::hir::def_id::DefId;
17-
use rustc::middle::cstore::LOCAL_CRATE;
1817
use rustc::middle::privacy::AccessLevels;
1918
use rustc::ty::{self, TyCtxt};
2019
use rustc::hir::map as hir_map;
@@ -30,7 +29,7 @@ use syntax::feature_gate::UnstableFeatures;
3029
use syntax::parse::token;
3130

3231
use std::cell::{RefCell, Cell};
33-
use std::collections::{HashMap, HashSet};
32+
use std::collections::HashMap;
3433
use std::rc::Rc;
3534

3635
use visit_ast::RustdocVisitor;
@@ -47,6 +46,7 @@ pub enum MaybeTyped<'a, 'tcx: 'a> {
4746
NotTyped(&'a session::Session)
4847
}
4948

49+
pub type Externs = HashMap<String, Vec<String>>;
5050
pub type ExternalPaths = HashMap<DefId, (Vec<String>, clean::TypeKind)>;
5151

5252
pub struct DocContext<'a, 'tcx: 'a> {
@@ -55,8 +55,6 @@ pub struct DocContext<'a, 'tcx: 'a> {
5555
pub input: Input,
5656
pub all_crate_impls: RefCell<HashMap<ast::CrateNum, Vec<clean::Item>>>,
5757
pub deref_trait_did: Cell<Option<DefId>>,
58-
/// Crates which have already been processed for `Self.access_levels`
59-
pub analyzed_crates: RefCell<HashSet<ast::CrateNum>>,
6058
// Note that external items for which `doc(hidden)` applies to are shown as
6159
// non-reachable while local items aren't. This is because we're reusing
6260
// the access levels from crateanalysis.
@@ -89,7 +87,16 @@ impl<'b, 'tcx> DocContext<'b, 'tcx> {
8987
}
9088
}
9189

92-
pub type Externs = HashMap<String, Vec<String>>;
90+
pub trait DocAccessLevels {
91+
fn is_doc_reachable(&self, DefId) -> bool;
92+
}
93+
94+
impl DocAccessLevels for AccessLevels<DefId> {
95+
fn is_doc_reachable(&self, did: DefId) -> bool {
96+
self.is_public(did)
97+
}
98+
}
99+
93100

94101
pub fn run_core(search_paths: SearchPaths,
95102
cfgs: Vec<String>,
@@ -172,16 +179,13 @@ pub fn run_core(search_paths: SearchPaths,
172179
.map(|(k, v)| (tcx.map.local_def_id(k), v))
173180
.collect()
174181
};
175-
let mut analyzed_crates = HashSet::new();
176-
analyzed_crates.insert(LOCAL_CRATE);
177182

178183
let ctxt = DocContext {
179184
map: &tcx.map,
180185
maybe_typed: Typed(tcx),
181186
input: input,
182187
all_crate_impls: RefCell::new(HashMap::new()),
183188
deref_trait_did: Cell::new(None),
184-
analyzed_crates: RefCell::new(analyzed_crates),
185189
access_levels: RefCell::new(access_levels),
186190
external_traits: RefCell::new(HashMap::new()),
187191
renderinfo: RefCell::new(Default::default()),

src/librustdoc/html/format.rs

+4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use syntax::abi::Abi;
2424
use rustc::hir;
2525

2626
use clean;
27+
use core::DocAccessLevels;
2728
use html::item_type::ItemType;
2829
use html::render;
2930
use html::render::{cache, CURRENT_LOCATION_KEY};
@@ -298,6 +299,9 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> {
298299
let mut url = if did.is_local() || cache.inlined.contains(&did) {
299300
repeat("../").take(loc.len()).collect::<String>()
300301
} else {
302+
if !cache.access_levels.is_doc_reachable(did) {
303+
return None
304+
}
301305
match cache.extern_locations[&did.krate] {
302306
(_, render::Remote(ref s)) => s.to_string(),
303307
(_, render::Local) => repeat("../").take(loc.len()).collect(),

src/librustdoc/html/render.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -246,17 +246,18 @@ pub struct Cache {
246246
/// Set of definitions which have been inlined from external crates.
247247
pub inlined: HashSet<DefId>,
248248

249+
// Note that external items for which `doc(hidden)` applies to are shown as
250+
// non-reachable while local items aren't. This is because we're reusing
251+
// the access levels from crateanalysis.
252+
pub access_levels: Arc<AccessLevels<DefId>>,
253+
249254
// Private fields only used when initially crawling a crate to build a cache
250255

251256
stack: Vec<String>,
252257
parent_stack: Vec<DefId>,
253258
parent_is_trait_impl: bool,
254259
search_index: Vec<IndexItem>,
255260
stripped_mod: bool,
256-
// Note that external items for which `doc(hidden)` applies to are shown as
257-
// non-reachable while local items aren't. This is because we're reusing
258-
// the access levels from crateanalysis.
259-
access_levels: Arc<AccessLevels<DefId>>,
260261
deref_trait_did: Option<DefId>,
261262

262263
// In rare case where a structure is defined in one module but implemented

src/librustdoc/test.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// except according to those terms.
1010

1111
use std::cell::{RefCell, Cell};
12-
use std::collections::{HashMap, HashSet};
12+
use std::collections::HashMap;
1313
use std::env;
1414
use std::ffi::OsString;
1515
use std::io::prelude::*;
@@ -111,7 +111,6 @@ pub fn run(input: &str,
111111
external_traits: RefCell::new(HashMap::new()),
112112
all_crate_impls: RefCell::new(HashMap::new()),
113113
deref_trait_did: Cell::new(None),
114-
analyzed_crates: RefCell::new(HashSet::new()),
115114
access_levels: Default::default(),
116115
renderinfo: Default::default(),
117116
};

src/librustdoc/visit_lib.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ use std::cell::RefMut;
1919

2020
use clean::{Attributes, Clean};
2121

22-
// FIXME: since this is only used for cross-crate impl inlining this only
23-
// handles traits and items for which traits can be implemented
22+
// FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses
2423

2524
/// Similar to `librustc_privacy::EmbargoVisitor`, but also takes
2625
/// specific rustdoc annotations into account (i.e. `doc(hidden)`)
@@ -69,11 +68,16 @@ impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> {
6968
for item in self.cstore.item_children(did) {
7069
if let DefLike::DlDef(def) = item.def {
7170
match def {
71+
Def::Mod(did) |
72+
Def::ForeignMod(did) |
7273
Def::Trait(did) |
7374
Def::Struct(did) |
74-
Def::Mod(did) |
7575
Def::Enum(did) |
76-
Def::TyAlias(did) => self.visit_item(did, item),
76+
Def::TyAlias(did) |
77+
Def::Fn(did) |
78+
Def::Method(did) |
79+
Def::Static(did, _) |
80+
Def::Const(did) => self.visit_item(did, item),
7781
_ => {}
7882
}
7983
}
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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+
pub struct Bar;
12+
13+
impl Bar {
14+
pub fn bar(_: u8) -> hidden::Hidden {
15+
hidden::Hidden
16+
}
17+
}
18+
19+
#[doc(hidden)]
20+
pub mod hidden {
21+
pub struct Hidden;
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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+
// aux-build:rustdoc-hidden-sig.rs
12+
// build-aux-docs
13+
// ignore-cross-compile
14+
15+
// @has rustdoc_hidden_sig/struct.Bar.html
16+
// @!has - '//a/@title' 'Hidden'
17+
// @has - '//a' 'u8'
18+
extern crate rustdoc_hidden_sig;
19+
20+
// @has issue_28480/struct.Bar.html
21+
// @!has - '//a/@title' 'Hidden'
22+
// @has - '//a' 'u8'
23+
pub use rustdoc_hidden_sig::Bar;

0 commit comments

Comments
 (0)