Skip to content

Commit 9001918

Browse files
committed
rustdoc: link to cross-crate sources directly.
1 parent 177913b commit 9001918

File tree

8 files changed

+173
-218
lines changed

8 files changed

+173
-218
lines changed

src/librustdoc/clean/inline.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ fn try_inline_def(cx: &DocContext, def: Def) -> Option<Vec<clean::Item>> {
115115
let did = def.def_id();
116116
cx.renderinfo.borrow_mut().inlined.insert(did);
117117
ret.push(clean::Item {
118-
source: clean::Span::empty(),
118+
source: tcx.def_span(did).clean(cx),
119119
name: Some(tcx.item_name(did).to_string()),
120120
attrs: load_attrs(cx, did),
121121
inner: inner,
@@ -321,7 +321,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
321321
clean::RegionBound(..) => unreachable!(),
322322
},
323323
}),
324-
source: clean::Span::empty(),
324+
source: tcx.def_span(did).clean(cx),
325325
name: None,
326326
attrs: attrs,
327327
visibility: Some(clean::Inherited),
@@ -357,7 +357,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
357357
tcx.item_type(item.def_id).clean(cx),
358358
default,
359359
),
360-
source: clean::Span::empty(),
360+
source: tcx.def_span(item.def_id).clean(cx),
361361
attrs: clean::Attributes::default(),
362362
visibility: None,
363363
stability: tcx.lookup_stability(item.def_id).clean(cx),
@@ -404,7 +404,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
404404
Some(clean::Item {
405405
name: Some(item.name.clean(cx)),
406406
inner: clean::TypedefItem(typedef, true),
407-
source: clean::Span::empty(),
407+
source: tcx.def_span(item.def_id).clean(cx),
408408
attrs: clean::Attributes::default(),
409409
visibility: None,
410410
stability: tcx.lookup_stability(item.def_id).clean(cx),
@@ -442,7 +442,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
442442
items: trait_items,
443443
polarity: Some(polarity.clean(cx)),
444444
}),
445-
source: clean::Span::empty(),
445+
source: tcx.def_span(did).clean(cx),
446446
name: None,
447447
attrs: attrs,
448448
visibility: Some(clean::Inherited),

src/librustdoc/clean/mod.rs

+82-93
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,10 @@ use syntax::ptr::P;
2727
use syntax::symbol::keywords;
2828
use syntax_pos::{self, DUMMY_SP, Pos};
2929

30-
use rustc_trans::back::link;
3130
use rustc::middle::privacy::AccessLevels;
3231
use rustc::middle::resolve_lifetime::DefRegion::*;
3332
use rustc::hir::def::{Def, CtorKind};
34-
use rustc::hir::def_id::{self, DefId, DefIndex, CRATE_DEF_INDEX};
33+
use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
3534
use rustc::hir::print as pprust;
3635
use rustc::ty::subst::Substs;
3736
use rustc::ty::{self, AdtKind};
@@ -45,7 +44,6 @@ use std::rc::Rc;
4544
use std::slice;
4645
use std::sync::Arc;
4746
use std::u32;
48-
use std::env::current_dir;
4947
use std::mem;
5048

5149
use core::DocContext;
@@ -110,19 +108,16 @@ pub struct Crate {
110108
pub name: String,
111109
pub src: PathBuf,
112110
pub module: Option<Item>,
113-
pub externs: Vec<(def_id::CrateNum, ExternalCrate)>,
114-
pub primitives: Vec<PrimitiveType>,
111+
pub externs: Vec<(CrateNum, ExternalCrate)>,
112+
pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
115113
pub access_levels: Arc<AccessLevels<DefId>>,
116114
// These are later on moved into `CACHEKEY`, leaving the map empty.
117115
// Only here so that they can be filtered through the rustdoc passes.
118116
pub external_traits: FxHashMap<DefId, Trait>,
119117
}
120118

121-
struct CrateNum(def_id::CrateNum);
122-
123119
impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
124120
fn clean(&self, cx: &DocContext) -> Crate {
125-
use rustc::session::config::Input;
126121
use ::visit_lib::LibEmbargoVisitor;
127122

128123
{
@@ -133,83 +128,41 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
133128

134129
let mut externs = Vec::new();
135130
for cnum in cx.sess().cstore.crates() {
136-
externs.push((cnum, CrateNum(cnum).clean(cx)));
131+
externs.push((cnum, cnum.clean(cx)));
137132
// Analyze doc-reachability for extern items
138133
LibEmbargoVisitor::new(cx).visit_lib(cnum);
139134
}
140135
externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
141136

142-
// Figure out the name of this crate
143-
let input = &cx.input;
144-
let name = link::find_crate_name(None, &self.attrs, input);
145-
146137
// Clean the crate, translating the entire libsyntax AST to one that is
147138
// understood by rustdoc.
148139
let mut module = self.module.clean(cx);
149140

150-
// Collect all inner modules which are tagged as implementations of
151-
// primitives.
152-
//
153-
// Note that this loop only searches the top-level items of the crate,
154-
// and this is intentional. If we were to search the entire crate for an
155-
// item tagged with `#[doc(primitive)]` then we would also have to
156-
// search the entirety of external modules for items tagged
157-
// `#[doc(primitive)]`, which is a pretty inefficient process (decoding
158-
// all that metadata unconditionally).
159-
//
160-
// In order to keep the metadata load under control, the
161-
// `#[doc(primitive)]` feature is explicitly designed to only allow the
162-
// primitive tags to show up as the top level items in a crate.
163-
//
164-
// Also note that this does not attempt to deal with modules tagged
165-
// duplicately for the same primitive. This is handled later on when
166-
// rendering by delegating everything to a hash map.
167-
let mut primitives = Vec::new();
141+
let ExternalCrate { name, src, primitives, .. } = LOCAL_CRATE.clean(cx);
168142
{
169143
let m = match module.inner {
170144
ModuleItem(ref mut m) => m,
171145
_ => unreachable!(),
172146
};
173-
let mut tmp = Vec::new();
174-
for child in &mut m.items {
175-
if !child.is_mod() {
176-
continue;
177-
}
178-
let prim = match PrimitiveType::find(&child.attrs) {
179-
Some(prim) => prim,
180-
None => continue,
181-
};
182-
primitives.push(prim);
183-
tmp.push(Item {
147+
m.items.extend(primitives.iter().map(|&(def_id, prim, ref attrs)| {
148+
Item {
184149
source: Span::empty(),
185150
name: Some(prim.to_url_str().to_string()),
186-
attrs: child.attrs.clone(),
151+
attrs: attrs.clone(),
187152
visibility: Some(Public),
188153
stability: None,
189154
deprecation: None,
190-
def_id: DefId::local(prim.to_def_index()),
155+
def_id: def_id,
191156
inner: PrimitiveItem(prim),
192-
});
193-
}
194-
m.items.extend(tmp);
195-
}
196-
197-
let src = match cx.input {
198-
Input::File(ref path) => {
199-
if path.is_absolute() {
200-
path.clone()
201-
} else {
202-
current_dir().unwrap().join(path)
203157
}
204-
},
205-
Input::Str { ref name, .. } => PathBuf::from(name.clone()),
206-
};
158+
}));
159+
}
207160

208161
let mut access_levels = cx.access_levels.borrow_mut();
209162
let mut external_traits = cx.external_traits.borrow_mut();
210163

211164
Crate {
212-
name: name.to_string(),
165+
name: name,
213166
src: src,
214167
module: Some(module),
215168
externs: externs,
@@ -223,21 +176,78 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
223176
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
224177
pub struct ExternalCrate {
225178
pub name: String,
179+
pub src: PathBuf,
226180
pub attrs: Attributes,
227-
pub primitives: Vec<PrimitiveType>,
181+
pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
228182
}
229183

230184
impl Clean<ExternalCrate> for CrateNum {
231185
fn clean(&self, cx: &DocContext) -> ExternalCrate {
232-
let mut primitives = Vec::new();
233-
let root = DefId { krate: self.0, index: CRATE_DEF_INDEX };
234-
for item in cx.tcx.sess.cstore.item_children(root) {
235-
let attrs = inline::load_attrs(cx, item.def.def_id());
236-
PrimitiveType::find(&attrs).map(|prim| primitives.push(prim));
237-
}
186+
let root = DefId { krate: *self, index: CRATE_DEF_INDEX };
187+
let krate_span = cx.tcx.def_span(root);
188+
let krate_src = cx.sess().codemap().span_to_filename(krate_span);
189+
190+
// Collect all inner modules which are tagged as implementations of
191+
// primitives.
192+
//
193+
// Note that this loop only searches the top-level items of the crate,
194+
// and this is intentional. If we were to search the entire crate for an
195+
// item tagged with `#[doc(primitive)]` then we would also have to
196+
// search the entirety of external modules for items tagged
197+
// `#[doc(primitive)]`, which is a pretty inefficient process (decoding
198+
// all that metadata unconditionally).
199+
//
200+
// In order to keep the metadata load under control, the
201+
// `#[doc(primitive)]` feature is explicitly designed to only allow the
202+
// primitive tags to show up as the top level items in a crate.
203+
//
204+
// Also note that this does not attempt to deal with modules tagged
205+
// duplicately for the same primitive. This is handled later on when
206+
// rendering by delegating everything to a hash map.
207+
let as_primitive = |def: Def| {
208+
if let Def::Mod(def_id) = def {
209+
let attrs = cx.tcx.get_attrs(def_id).clean(cx);
210+
let mut prim = None;
211+
for attr in attrs.lists("doc") {
212+
if let Some(v) = attr.value_str() {
213+
if attr.check_name("primitive") {
214+
prim = PrimitiveType::from_str(&v.as_str());
215+
if prim.is_some() {
216+
break;
217+
}
218+
}
219+
}
220+
}
221+
return prim.map(|p| (def_id, p, attrs));
222+
}
223+
None
224+
};
225+
let primitives = if root.is_local() {
226+
cx.tcx.map.krate().module.item_ids.iter().filter_map(|&id| {
227+
let item = cx.tcx.map.expect_item(id.id);
228+
match item.node {
229+
hir::ItemMod(_) => {
230+
as_primitive(Def::Mod(cx.tcx.map.local_def_id(id.id)))
231+
}
232+
hir::ItemUse(ref path, hir::UseKind::Single)
233+
if item.vis == hir::Visibility::Public => {
234+
as_primitive(path.def).map(|(_, prim, attrs)| {
235+
// Pretend the primitive is local.
236+
(cx.tcx.map.local_def_id(id.id), prim, attrs)
237+
})
238+
}
239+
_ => None
240+
}
241+
}).collect()
242+
} else {
243+
cx.tcx.sess.cstore.item_children(root).iter().map(|item| item.def)
244+
.filter_map(as_primitive).collect()
245+
};
246+
238247
ExternalCrate {
239-
name: cx.sess().cstore.crate_name(self.0).to_string(),
240-
attrs: cx.sess().cstore.item_attrs(root).clean(cx),
248+
name: cx.tcx.crate_name(*self).to_string(),
249+
src: PathBuf::from(krate_src),
250+
attrs: cx.tcx.get_attrs(root).clean(cx),
241251
primitives: primitives,
242252
}
243253
}
@@ -1460,7 +1470,7 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
14601470
deprecation: get_deprecation(cx, self.def_id),
14611471
def_id: self.def_id,
14621472
attrs: inline::load_attrs(cx, self.def_id),
1463-
source: Span::empty(),
1473+
source: cx.tcx.def_span(self.def_id).clean(cx),
14641474
inner: inner,
14651475
}
14661476
}
@@ -1618,19 +1628,6 @@ impl PrimitiveType {
16181628
}
16191629
}
16201630

1621-
fn find(attrs: &Attributes) -> Option<PrimitiveType> {
1622-
for attr in attrs.lists("doc") {
1623-
if let Some(v) = attr.value_str() {
1624-
if attr.check_name("primitive") {
1625-
if let ret@Some(..) = PrimitiveType::from_str(&v.as_str()) {
1626-
return ret;
1627-
}
1628-
}
1629-
}
1630-
}
1631-
None
1632-
}
1633-
16341631
pub fn as_str(&self) -> &'static str {
16351632
match *self {
16361633
PrimitiveType::Isize => "isize",
@@ -1658,14 +1655,6 @@ impl PrimitiveType {
16581655
pub fn to_url_str(&self) -> &'static str {
16591656
self.as_str()
16601657
}
1661-
1662-
/// Creates a rustdoc-specific node id for primitive types.
1663-
///
1664-
/// These node ids are generally never used by the AST itself.
1665-
pub fn to_def_index(&self) -> DefIndex {
1666-
let x = u32::MAX - 1 - (*self as u32);
1667-
DefIndex::new(x as usize)
1668-
}
16691658
}
16701659

16711660
impl From<ast::IntTy> for PrimitiveType {
@@ -1948,7 +1937,7 @@ impl<'tcx> Clean<Item> for ty::FieldDefData<'tcx, 'static> {
19481937
Item {
19491938
name: Some(self.name).clean(cx),
19501939
attrs: cx.tcx.get_attrs(self.did).clean(cx),
1951-
source: Span::empty(),
1940+
source: cx.tcx.def_span(self.did).clean(cx),
19521941
visibility: self.vis.clean(cx),
19531942
stability: get_stability(cx, self.did),
19541943
deprecation: get_deprecation(cx, self.did),
@@ -2115,7 +2104,7 @@ impl<'tcx> Clean<Item> for ty::VariantDefData<'tcx, 'static> {
21152104
fields_stripped: false,
21162105
fields: self.fields.iter().map(|field| {
21172106
Item {
2118-
source: Span::empty(),
2107+
source: cx.tcx.def_span(field.did).clean(cx),
21192108
name: Some(field.name.clean(cx)),
21202109
attrs: cx.tcx.get_attrs(field.did).clean(cx),
21212110
visibility: field.vis.clean(cx),
@@ -2131,7 +2120,7 @@ impl<'tcx> Clean<Item> for ty::VariantDefData<'tcx, 'static> {
21312120
Item {
21322121
name: Some(self.name.clean(cx)),
21332122
attrs: inline::load_attrs(cx, self.did),
2134-
source: Span::empty(),
2123+
source: cx.tcx.def_span(self.did).clean(cx),
21352124
visibility: Some(Inherited),
21362125
def_id: self.did,
21372126
inner: VariantItem(Variant { kind: kind }),

src/librustdoc/core.rs

-2
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ pub type ExternalPaths = FxHashMap<DefId, (Vec<String>, clean::TypeKind)>;
4545

4646
pub struct DocContext<'a, 'tcx: 'a> {
4747
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
48-
pub input: Input,
4948
pub populated_all_crate_impls: Cell<bool>,
5049
// Note that external items for which `doc(hidden)` applies to are shown as
5150
// non-reachable while local items aren't. This is because we're reusing
@@ -187,7 +186,6 @@ pub fn run_core(search_paths: SearchPaths,
187186

188187
let ctxt = DocContext {
189188
tcx: tcx,
190-
input: input,
191189
populated_all_crate_impls: Cell::new(false),
192190
access_levels: RefCell::new(access_levels),
193191
external_traits: Default::default(),

0 commit comments

Comments
 (0)