]> git.proxmox.com Git - rustc.git/blame - src/librustdoc/clean/mod.rs
Imported Upstream version 1.3.0+dfsg1
[rustc.git] / src / librustdoc / clean / mod.rs
CommitLineData
1a4d82fc
JJ
1// Copyright 2012-2013 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//! This module contains the "cleaned" pieces of the AST, and the functions
12//! that clean them.
13
1a4d82fc
JJ
14pub use self::Type::*;
15pub use self::PrimitiveType::*;
16pub use self::TypeKind::*;
17pub use self::StructField::*;
18pub use self::VariantKind::*;
19pub use self::Mutability::*;
85aaf69f 20pub use self::Import::*;
1a4d82fc
JJ
21pub use self::ItemEnum::*;
22pub use self::Attribute::*;
23pub use self::TyParamBound::*;
24pub use self::SelfTy::*;
25pub use self::FunctionRetTy::*;
1a4d82fc
JJ
26
27use syntax;
85aaf69f 28use syntax::abi;
1a4d82fc
JJ
29use syntax::ast;
30use syntax::ast_util;
1a4d82fc
JJ
31use syntax::attr;
32use syntax::attr::{AttributeMethods, AttrMetaMethods};
85aaf69f 33use syntax::codemap;
1a4d82fc
JJ
34use syntax::codemap::{DUMMY_SP, Pos, Spanned};
35use syntax::parse::token::{self, InternedString, special_idents};
36use syntax::ptr::P;
37
38use rustc_trans::back::link;
39use rustc::metadata::cstore;
40use rustc::metadata::csearch;
41use rustc::metadata::decoder;
42use rustc::middle::def;
43use rustc::middle::subst::{self, ParamSpace, VecPerParamSpace};
44use rustc::middle::ty;
45use rustc::middle::stability;
1a4d82fc 46
9346a6ac
AL
47use std::collections::HashMap;
48use std::path::PathBuf;
1a4d82fc
JJ
49use std::rc::Rc;
50use std::u32;
1a4d82fc
JJ
51
52use core::DocContext;
53use doctree;
54use visit_ast;
55
56/// A stable identifier to the particular version of JSON output.
57/// Increment this when the `Crate` and related structures change.
62682a34 58pub const SCHEMA_VERSION: &'static str = "0.8.3";
1a4d82fc
JJ
59
60mod inline;
9346a6ac 61mod simplify;
1a4d82fc
JJ
62
63// extract the stability index for a node from tcx, if possible
64fn get_stability(cx: &DocContext, def_id: ast::DefId) -> Option<Stability> {
65 cx.tcx_opt().and_then(|tcx| stability::lookup(tcx, def_id)).clean(cx)
66}
67
68pub trait Clean<T> {
69 fn clean(&self, cx: &DocContext) -> T;
70}
71
c34b1796 72impl<T: Clean<U>, U> Clean<Vec<U>> for [T] {
1a4d82fc
JJ
73 fn clean(&self, cx: &DocContext) -> Vec<U> {
74 self.iter().map(|x| x.clean(cx)).collect()
75 }
76}
77
78impl<T: Clean<U>, U> Clean<VecPerParamSpace<U>> for VecPerParamSpace<T> {
79 fn clean(&self, cx: &DocContext) -> VecPerParamSpace<U> {
80 self.map(|x| x.clean(cx))
81 }
82}
83
84impl<T: Clean<U>, U> Clean<U> for P<T> {
85 fn clean(&self, cx: &DocContext) -> U {
86 (**self).clean(cx)
87 }
88}
89
90impl<T: Clean<U>, U> Clean<U> for Rc<T> {
91 fn clean(&self, cx: &DocContext) -> U {
92 (**self).clean(cx)
93 }
94}
95
96impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
97 fn clean(&self, cx: &DocContext) -> Option<U> {
98 match self {
99 &None => None,
100 &Some(ref v) => Some(v.clean(cx))
101 }
102 }
103}
104
85aaf69f
SL
105impl<T, U> Clean<U> for ty::Binder<T> where T: Clean<U> {
106 fn clean(&self, cx: &DocContext) -> U {
107 self.0.clean(cx)
108 }
109}
110
1a4d82fc
JJ
111impl<T: Clean<U>, U> Clean<Vec<U>> for syntax::owned_slice::OwnedSlice<T> {
112 fn clean(&self, cx: &DocContext) -> Vec<U> {
113 self.iter().map(|x| x.clean(cx)).collect()
114 }
115}
116
85aaf69f 117#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
118pub struct Crate {
119 pub name: String,
c34b1796 120 pub src: PathBuf,
1a4d82fc
JJ
121 pub module: Option<Item>,
122 pub externs: Vec<(ast::CrateNum, ExternalCrate)>,
123 pub primitives: Vec<PrimitiveType>,
9346a6ac 124 pub external_traits: HashMap<ast::DefId, Trait>,
1a4d82fc
JJ
125}
126
127impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
128 fn clean(&self, cx: &DocContext) -> Crate {
85aaf69f
SL
129 use rustc::session::config::Input;
130
d9579d0f
AL
131 if let Some(t) = cx.tcx_opt() {
132 cx.deref_trait_did.set(t.lang_items.deref_trait());
133 }
134
1a4d82fc
JJ
135 let mut externs = Vec::new();
136 cx.sess().cstore.iter_crate_data(|n, meta| {
137 externs.push((n, meta.clean(cx)));
138 });
139 externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
140
141 // Figure out the name of this crate
85aaf69f
SL
142 let input = &cx.input;
143 let name = link::find_crate_name(None, &self.attrs, input);
1a4d82fc
JJ
144
145 // Clean the crate, translating the entire libsyntax AST to one that is
146 // understood by rustdoc.
147 let mut module = self.module.clean(cx);
148
149 // Collect all inner modules which are tagged as implementations of
150 // primitives.
151 //
152 // Note that this loop only searches the top-level items of the crate,
153 // and this is intentional. If we were to search the entire crate for an
154 // item tagged with `#[doc(primitive)]` then we we would also have to
155 // search the entirety of external modules for items tagged
156 // `#[doc(primitive)]`, which is a pretty inefficient process (decoding
157 // all that metadata unconditionally).
158 //
159 // In order to keep the metadata load under control, the
160 // `#[doc(primitive)]` feature is explicitly designed to only allow the
161 // primitive tags to show up as the top level items in a crate.
162 //
163 // Also note that this does not attempt to deal with modules tagged
164 // duplicately for the same primitive. This is handled later on when
165 // rendering by delegating everything to a hash map.
166 let mut primitives = Vec::new();
167 {
168 let m = match module.inner {
169 ModuleItem(ref mut m) => m,
170 _ => unreachable!(),
171 };
172 let mut tmp = Vec::new();
85aaf69f 173 for child in &mut m.items {
1a4d82fc
JJ
174 match child.inner {
175 ModuleItem(..) => {}
176 _ => continue,
177 }
85aaf69f 178 let prim = match PrimitiveType::find(&child.attrs) {
1a4d82fc
JJ
179 Some(prim) => prim,
180 None => continue,
181 };
182 primitives.push(prim);
183 tmp.push(Item {
184 source: Span::empty(),
185 name: Some(prim.to_url_str().to_string()),
186 attrs: child.attrs.clone(),
187 visibility: Some(ast::Public),
188 stability: None,
189 def_id: ast_util::local_def(prim.to_node_id()),
190 inner: PrimitiveItem(prim),
191 });
192 }
62682a34 193 m.items.extend(tmp);
1a4d82fc
JJ
194 }
195
85aaf69f
SL
196 let src = match cx.input {
197 Input::File(ref path) => path.clone(),
c34b1796 198 Input::Str(_) => PathBuf::new() // FIXME: this is wrong
85aaf69f
SL
199 };
200
1a4d82fc
JJ
201 Crate {
202 name: name.to_string(),
85aaf69f 203 src: src,
1a4d82fc
JJ
204 module: Some(module),
205 externs: externs,
206 primitives: primitives,
9346a6ac
AL
207 external_traits: cx.external_traits.borrow_mut().take()
208 .unwrap_or(HashMap::new()),
1a4d82fc
JJ
209 }
210 }
211}
212
85aaf69f 213#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
214pub struct ExternalCrate {
215 pub name: String,
216 pub attrs: Vec<Attribute>,
217 pub primitives: Vec<PrimitiveType>,
218}
219
220impl Clean<ExternalCrate> for cstore::crate_metadata {
221 fn clean(&self, cx: &DocContext) -> ExternalCrate {
222 let mut primitives = Vec::new();
223 cx.tcx_opt().map(|tcx| {
224 csearch::each_top_level_item_of_crate(&tcx.sess.cstore,
225 self.cnum,
226 |def, _, _| {
227 let did = match def {
228 decoder::DlDef(def::DefMod(did)) => did,
229 _ => return
230 };
231 let attrs = inline::load_attrs(cx, tcx, did);
85aaf69f 232 PrimitiveType::find(&attrs).map(|prim| primitives.push(prim));
1a4d82fc
JJ
233 })
234 });
235 ExternalCrate {
236 name: self.name.to_string(),
237 attrs: decoder::get_crate_attributes(self.data()).clean(cx),
238 primitives: primitives,
239 }
240 }
241}
242
243/// Anything with a source location and set of attributes and, optionally, a
244/// name. That is, anything that can be documented. This doesn't correspond
245/// directly to the AST's concept of an item; it's a strict superset.
85aaf69f 246#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
247pub struct Item {
248 /// Stringified span
249 pub source: Span,
250 /// Not everything has a name. E.g., impls
251 pub name: Option<String>,
252 pub attrs: Vec<Attribute> ,
253 pub inner: ItemEnum,
254 pub visibility: Option<Visibility>,
255 pub def_id: ast::DefId,
256 pub stability: Option<Stability>,
257}
258
259impl Item {
260 /// Finds the `doc` attribute as a List and returns the list of attributes
261 /// nested inside.
262 pub fn doc_list<'a>(&'a self) -> Option<&'a [Attribute]> {
85aaf69f 263 for attr in &self.attrs {
1a4d82fc
JJ
264 match *attr {
265 List(ref x, ref list) if "doc" == *x => {
85aaf69f 266 return Some(list);
1a4d82fc
JJ
267 }
268 _ => {}
269 }
270 }
271 return None;
272 }
273
274 /// Finds the `doc` attribute as a NameValue and returns the corresponding
275 /// value found.
276 pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
85aaf69f 277 for attr in &self.attrs {
1a4d82fc
JJ
278 match *attr {
279 NameValue(ref x, ref v) if "doc" == *x => {
85aaf69f 280 return Some(v);
1a4d82fc
JJ
281 }
282 _ => {}
283 }
284 }
285 return None;
286 }
287
288 pub fn is_hidden_from_doc(&self) -> bool {
289 match self.doc_list() {
85aaf69f
SL
290 Some(l) => {
291 for innerattr in l {
1a4d82fc
JJ
292 match *innerattr {
293 Word(ref s) if "hidden" == *s => {
294 return true
295 }
296 _ => (),
297 }
298 }
299 },
300 None => ()
301 }
302 return false;
303 }
304
305 pub fn is_mod(&self) -> bool {
306 match self.inner { ModuleItem(..) => true, _ => false }
307 }
308 pub fn is_trait(&self) -> bool {
309 match self.inner { TraitItem(..) => true, _ => false }
310 }
311 pub fn is_struct(&self) -> bool {
312 match self.inner { StructItem(..) => true, _ => false }
313 }
314 pub fn is_enum(&self) -> bool {
315 match self.inner { EnumItem(..) => true, _ => false }
316 }
317 pub fn is_fn(&self) -> bool {
318 match self.inner { FunctionItem(..) => true, _ => false }
319 }
d9579d0f
AL
320
321 pub fn stability_class(&self) -> String {
322 match self.stability {
323 Some(ref s) => {
324 let mut base = match s.level {
325 attr::Unstable => "unstable".to_string(),
326 attr::Stable => String::new(),
327 };
328 if !s.deprecated_since.is_empty() {
329 base.push_str(" deprecated");
330 }
331 base
332 }
333 _ => String::new(),
334 }
335 }
1a4d82fc
JJ
336}
337
85aaf69f 338#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc 339pub enum ItemEnum {
85aaf69f
SL
340 ExternCrateItem(String, Option<String>),
341 ImportItem(Import),
1a4d82fc
JJ
342 StructItem(Struct),
343 EnumItem(Enum),
344 FunctionItem(Function),
345 ModuleItem(Module),
62682a34 346 TypedefItem(Typedef, bool /* is associated type */),
1a4d82fc
JJ
347 StaticItem(Static),
348 ConstantItem(Constant),
349 TraitItem(Trait),
350 ImplItem(Impl),
1a4d82fc
JJ
351 /// A method signature only. Used for required methods in traits (ie,
352 /// non-default-methods).
353 TyMethodItem(TyMethod),
354 /// A method with a body.
355 MethodItem(Method),
356 StructFieldItem(StructField),
357 VariantItem(Variant),
358 /// `fn`s from an extern block
359 ForeignFunctionItem(Function),
360 /// `static`s from an extern block
361 ForeignStaticItem(Static),
362 MacroItem(Macro),
363 PrimitiveItem(PrimitiveType),
d9579d0f 364 AssociatedConstItem(Type, Option<String>),
c34b1796
AL
365 AssociatedTypeItem(Vec<TyParamBound>, Option<Type>),
366 DefaultImplItem(DefaultImpl),
1a4d82fc
JJ
367}
368
85aaf69f 369#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
370pub struct Module {
371 pub items: Vec<Item>,
372 pub is_crate: bool,
373}
374
375impl Clean<Item> for doctree::Module {
376 fn clean(&self, cx: &DocContext) -> Item {
377 let name = if self.name.is_some() {
378 self.name.unwrap().clean(cx)
379 } else {
380 "".to_string()
381 };
85aaf69f
SL
382
383 let mut items: Vec<Item> = vec![];
384 items.extend(self.extern_crates.iter().map(|x| x.clean(cx)));
62682a34 385 items.extend(self.imports.iter().flat_map(|x| x.clean(cx)));
85aaf69f
SL
386 items.extend(self.structs.iter().map(|x| x.clean(cx)));
387 items.extend(self.enums.iter().map(|x| x.clean(cx)));
388 items.extend(self.fns.iter().map(|x| x.clean(cx)));
62682a34 389 items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx)));
85aaf69f
SL
390 items.extend(self.mods.iter().map(|x| x.clean(cx)));
391 items.extend(self.typedefs.iter().map(|x| x.clean(cx)));
392 items.extend(self.statics.iter().map(|x| x.clean(cx)));
393 items.extend(self.constants.iter().map(|x| x.clean(cx)));
394 items.extend(self.traits.iter().map(|x| x.clean(cx)));
62682a34 395 items.extend(self.impls.iter().flat_map(|x| x.clean(cx)));
85aaf69f 396 items.extend(self.macros.iter().map(|x| x.clean(cx)));
c34b1796 397 items.extend(self.def_traits.iter().map(|x| x.clean(cx)));
1a4d82fc
JJ
398
399 // determine if we should display the inner contents or
400 // the outer `mod` item for the source code.
401 let whence = {
402 let cm = cx.sess().codemap();
403 let outer = cm.lookup_char_pos(self.where_outer.lo);
404 let inner = cm.lookup_char_pos(self.where_inner.lo);
405 if outer.file.start_pos == inner.file.start_pos {
406 // mod foo { ... }
407 self.where_outer
408 } else {
409 // mod foo; (and a separate FileMap for the contents)
410 self.where_inner
411 }
412 };
413
414 Item {
415 name: Some(name),
416 attrs: self.attrs.clean(cx),
417 source: whence.clean(cx),
418 visibility: self.vis.clean(cx),
419 stability: self.stab.clean(cx),
420 def_id: ast_util::local_def(self.id),
421 inner: ModuleItem(Module {
422 is_crate: self.is_crate,
85aaf69f 423 items: items
1a4d82fc
JJ
424 })
425 }
426 }
427}
428
85aaf69f 429#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
430pub enum Attribute {
431 Word(String),
432 List(String, Vec<Attribute> ),
433 NameValue(String, String)
434}
435
436impl Clean<Attribute> for ast::MetaItem {
437 fn clean(&self, cx: &DocContext) -> Attribute {
438 match self.node {
85aaf69f 439 ast::MetaWord(ref s) => Word(s.to_string()),
1a4d82fc 440 ast::MetaList(ref s, ref l) => {
85aaf69f 441 List(s.to_string(), l.clean(cx))
1a4d82fc
JJ
442 }
443 ast::MetaNameValue(ref s, ref v) => {
85aaf69f 444 NameValue(s.to_string(), lit_to_string(v))
1a4d82fc
JJ
445 }
446 }
447 }
448}
449
450impl Clean<Attribute> for ast::Attribute {
451 fn clean(&self, cx: &DocContext) -> Attribute {
452 self.with_desugared_doc(|a| a.node.value.clean(cx))
453 }
454}
455
456// This is a rough approximation that gets us what we want.
457impl attr::AttrMetaMethods for Attribute {
458 fn name(&self) -> InternedString {
459 match *self {
460 Word(ref n) | List(ref n, _) | NameValue(ref n, _) => {
85aaf69f 461 token::intern_and_get_ident(n)
1a4d82fc
JJ
462 }
463 }
464 }
465
466 fn value_str(&self) -> Option<InternedString> {
467 match *self {
468 NameValue(_, ref v) => {
85aaf69f 469 Some(token::intern_and_get_ident(v))
1a4d82fc
JJ
470 }
471 _ => None,
472 }
473 }
474 fn meta_item_list<'a>(&'a self) -> Option<&'a [P<ast::MetaItem>]> { None }
85aaf69f 475 fn span(&self) -> codemap::Span { unimplemented!() }
1a4d82fc
JJ
476}
477impl<'a> attr::AttrMetaMethods for &'a Attribute {
478 fn name(&self) -> InternedString { (**self).name() }
479 fn value_str(&self) -> Option<InternedString> { (**self).value_str() }
480 fn meta_item_list(&self) -> Option<&[P<ast::MetaItem>]> { None }
85aaf69f 481 fn span(&self) -> codemap::Span { unimplemented!() }
1a4d82fc
JJ
482}
483
85aaf69f 484#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
485pub struct TyParam {
486 pub name: String,
487 pub did: ast::DefId,
488 pub bounds: Vec<TyParamBound>,
489 pub default: Option<Type>,
490}
491
492impl Clean<TyParam> for ast::TyParam {
493 fn clean(&self, cx: &DocContext) -> TyParam {
494 TyParam {
495 name: self.ident.clean(cx),
496 did: ast::DefId { krate: ast::LOCAL_CRATE, node: self.id },
497 bounds: self.bounds.clean(cx),
498 default: self.default.clean(cx),
499 }
500 }
501}
502
503impl<'tcx> Clean<TyParam> for ty::TypeParameterDef<'tcx> {
504 fn clean(&self, cx: &DocContext) -> TyParam {
505 cx.external_typarams.borrow_mut().as_mut().unwrap()
506 .insert(self.def_id, self.name.clean(cx));
1a4d82fc
JJ
507 TyParam {
508 name: self.name.clean(cx),
509 did: self.def_id,
c34b1796 510 bounds: vec![], // these are filled in from the where-clauses
1a4d82fc
JJ
511 default: self.default.clean(cx),
512 }
513 }
514}
515
85aaf69f 516#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
517pub enum TyParamBound {
518 RegionBound(Lifetime),
519 TraitBound(PolyTrait, ast::TraitBoundModifier)
520}
521
9346a6ac
AL
522impl TyParamBound {
523 fn maybe_sized(cx: &DocContext) -> TyParamBound {
524 use syntax::ast::TraitBoundModifier as TBM;
62682a34 525 let mut sized_bound = ty::BoundSized.clean(cx);
9346a6ac
AL
526 if let TyParamBound::TraitBound(_, ref mut tbm) = sized_bound {
527 *tbm = TBM::Maybe
528 };
529 sized_bound
530 }
531
532 fn is_sized_bound(&self, cx: &DocContext) -> bool {
533 use syntax::ast::TraitBoundModifier as TBM;
534 if let Some(tcx) = cx.tcx_opt() {
535 let sized_did = match tcx.lang_items.sized_trait() {
536 Some(did) => did,
537 None => return false
538 };
539 if let TyParamBound::TraitBound(PolyTrait {
540 trait_: Type::ResolvedPath { did, .. }, ..
541 }, TBM::None) = *self {
542 if did == sized_did {
543 return true
544 }
545 }
546 }
547 false
548 }
549}
550
1a4d82fc
JJ
551impl Clean<TyParamBound> for ast::TyParamBound {
552 fn clean(&self, cx: &DocContext) -> TyParamBound {
553 match *self {
554 ast::RegionTyParamBound(lt) => RegionBound(lt.clean(cx)),
555 ast::TraitTyParamBound(ref t, modifier) => TraitBound(t.clean(cx), modifier),
556 }
557 }
558}
559
85aaf69f
SL
560impl<'tcx> Clean<(Vec<TyParamBound>, Vec<TypeBinding>)> for ty::ExistentialBounds<'tcx> {
561 fn clean(&self, cx: &DocContext) -> (Vec<TyParamBound>, Vec<TypeBinding>) {
562 let mut tp_bounds = vec![];
563 self.region_bound.clean(cx).map(|b| tp_bounds.push(RegionBound(b)));
564 for bb in &self.builtin_bounds {
565 tp_bounds.push(bb.clean(cx));
1a4d82fc
JJ
566 }
567
85aaf69f
SL
568 let mut bindings = vec![];
569 for &ty::Binder(ref pb) in &self.projection_bounds {
570 bindings.push(TypeBinding {
571 name: pb.projection_ty.item_name.clean(cx),
572 ty: pb.ty.clean(cx)
573 });
574 }
1a4d82fc 575
85aaf69f 576 (tp_bounds, bindings)
1a4d82fc
JJ
577 }
578}
579
580fn external_path_params(cx: &DocContext, trait_did: Option<ast::DefId>,
85aaf69f 581 bindings: Vec<TypeBinding>, substs: &subst::Substs) -> PathParameters {
1a4d82fc
JJ
582 let lifetimes = substs.regions().get_slice(subst::TypeSpace)
583 .iter()
584 .filter_map(|v| v.clean(cx))
585 .collect();
586 let types = substs.types.get_slice(subst::TypeSpace).to_vec();
587
588 match (trait_did, cx.tcx_opt()) {
589 // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C
590 (Some(did), Some(ref tcx)) if tcx.lang_items.fn_trait_kind(did).is_some() => {
85aaf69f 591 assert_eq!(types.len(), 1);
1a4d82fc 592 let inputs = match types[0].sty {
62682a34 593 ty::TyTuple(ref tys) => tys.iter().map(|t| t.clean(cx)).collect(),
1a4d82fc
JJ
594 _ => {
595 return PathParameters::AngleBracketed {
596 lifetimes: lifetimes,
597 types: types.clean(cx),
85aaf69f 598 bindings: bindings
1a4d82fc
JJ
599 }
600 }
601 };
85aaf69f
SL
602 let output = None;
603 // FIXME(#20299) return type comes from a projection now
604 // match types[1].sty {
62682a34 605 // ty::TyTuple(ref v) if v.is_empty() => None, // -> ()
85aaf69f
SL
606 // _ => Some(types[1].clean(cx))
607 // };
1a4d82fc
JJ
608 PathParameters::Parenthesized {
609 inputs: inputs,
610 output: output
611 }
612 },
613 (_, _) => {
614 PathParameters::AngleBracketed {
615 lifetimes: lifetimes,
616 types: types.clean(cx),
85aaf69f 617 bindings: bindings
1a4d82fc
JJ
618 }
619 }
620 }
621}
622
623// trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
624// from Fn<(A, B,), C> to Fn(A, B) -> C
625fn external_path(cx: &DocContext, name: &str, trait_did: Option<ast::DefId>,
85aaf69f 626 bindings: Vec<TypeBinding>, substs: &subst::Substs) -> Path {
1a4d82fc
JJ
627 Path {
628 global: false,
629 segments: vec![PathSegment {
630 name: name.to_string(),
85aaf69f 631 params: external_path_params(cx, trait_did, bindings, substs)
1a4d82fc
JJ
632 }],
633 }
634}
635
636impl Clean<TyParamBound> for ty::BuiltinBound {
637 fn clean(&self, cx: &DocContext) -> TyParamBound {
638 let tcx = match cx.tcx_opt() {
639 Some(tcx) => tcx,
640 None => return RegionBound(Lifetime::statik())
641 };
642 let empty = subst::Substs::empty();
643 let (did, path) = match *self {
644 ty::BoundSend =>
645 (tcx.lang_items.send_trait().unwrap(),
85aaf69f 646 external_path(cx, "Send", None, vec![], &empty)),
1a4d82fc
JJ
647 ty::BoundSized =>
648 (tcx.lang_items.sized_trait().unwrap(),
85aaf69f 649 external_path(cx, "Sized", None, vec![], &empty)),
1a4d82fc
JJ
650 ty::BoundCopy =>
651 (tcx.lang_items.copy_trait().unwrap(),
85aaf69f 652 external_path(cx, "Copy", None, vec![], &empty)),
1a4d82fc
JJ
653 ty::BoundSync =>
654 (tcx.lang_items.sync_trait().unwrap(),
85aaf69f 655 external_path(cx, "Sync", None, vec![], &empty)),
1a4d82fc
JJ
656 };
657 let fqn = csearch::get_item_path(tcx, did);
658 let fqn = fqn.into_iter().map(|i| i.to_string()).collect();
659 cx.external_paths.borrow_mut().as_mut().unwrap().insert(did,
660 (fqn, TypeTrait));
661 TraitBound(PolyTrait {
662 trait_: ResolvedPath {
663 path: path,
664 typarams: None,
665 did: did,
62682a34 666 is_generic: false,
1a4d82fc
JJ
667 },
668 lifetimes: vec![]
669 }, ast::TraitBoundModifier::None)
670 }
671}
672
1a4d82fc
JJ
673impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
674 fn clean(&self, cx: &DocContext) -> TyParamBound {
675 let tcx = match cx.tcx_opt() {
676 Some(tcx) => tcx,
677 None => return RegionBound(Lifetime::statik())
678 };
679 let fqn = csearch::get_item_path(tcx, self.def_id);
680 let fqn = fqn.into_iter().map(|i| i.to_string())
681 .collect::<Vec<String>>();
85aaf69f
SL
682 let path = external_path(cx, fqn.last().unwrap(),
683 Some(self.def_id), vec![], self.substs);
1a4d82fc
JJ
684 cx.external_paths.borrow_mut().as_mut().unwrap().insert(self.def_id,
685 (fqn, TypeTrait));
686
687 debug!("ty::TraitRef\n substs.types(TypeSpace): {:?}\n",
688 self.substs.types.get_slice(ParamSpace::TypeSpace));
689
690 // collect any late bound regions
691 let mut late_bounds = vec![];
85aaf69f 692 for &ty_s in self.substs.types.get_slice(ParamSpace::TypeSpace) {
62682a34 693 if let ty::TyTuple(ref ts) = ty_s.sty {
85aaf69f 694 for &ty_s in ts {
62682a34
SL
695 if let ty::TyRef(ref reg, _) = ty_s.sty {
696 if let &ty::Region::ReLateBound(_, _) = *reg {
1a4d82fc
JJ
697 debug!(" hit an ReLateBound {:?}", reg);
698 if let Some(lt) = reg.clean(cx) {
699 late_bounds.push(lt)
700 }
701 }
702 }
703 }
704 }
705 }
706
707 TraitBound(PolyTrait {
62682a34
SL
708 trait_: ResolvedPath {
709 path: path,
710 typarams: None,
711 did: self.def_id,
712 is_generic: false,
713 },
1a4d82fc
JJ
714 lifetimes: late_bounds
715 }, ast::TraitBoundModifier::None)
716 }
717}
718
1a4d82fc
JJ
719impl<'tcx> Clean<Option<Vec<TyParamBound>>> for subst::Substs<'tcx> {
720 fn clean(&self, cx: &DocContext) -> Option<Vec<TyParamBound>> {
721 let mut v = Vec::new();
722 v.extend(self.regions().iter().filter_map(|r| r.clean(cx)).map(RegionBound));
723 v.extend(self.types.iter().map(|t| TraitBound(PolyTrait {
724 trait_: t.clean(cx),
725 lifetimes: vec![]
726 }, ast::TraitBoundModifier::None)));
9346a6ac 727 if !v.is_empty() {Some(v)} else {None}
1a4d82fc
JJ
728 }
729}
730
85aaf69f 731#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
732pub struct Lifetime(String);
733
734impl Lifetime {
735 pub fn get_ref<'a>(&'a self) -> &'a str {
736 let Lifetime(ref s) = *self;
85aaf69f 737 let s: &'a str = s;
1a4d82fc
JJ
738 return s;
739 }
740
741 pub fn statik() -> Lifetime {
742 Lifetime("'static".to_string())
743 }
744}
745
746impl Clean<Lifetime> for ast::Lifetime {
747 fn clean(&self, _: &DocContext) -> Lifetime {
c1a9b12d 748 Lifetime(self.name.to_string())
1a4d82fc
JJ
749 }
750}
751
752impl Clean<Lifetime> for ast::LifetimeDef {
753 fn clean(&self, _: &DocContext) -> Lifetime {
c1a9b12d 754 Lifetime(self.lifetime.name.to_string())
1a4d82fc
JJ
755 }
756}
757
758impl Clean<Lifetime> for ty::RegionParameterDef {
759 fn clean(&self, _: &DocContext) -> Lifetime {
c1a9b12d 760 Lifetime(self.name.to_string())
1a4d82fc
JJ
761 }
762}
763
764impl Clean<Option<Lifetime>> for ty::Region {
765 fn clean(&self, cx: &DocContext) -> Option<Lifetime> {
766 match *self {
767 ty::ReStatic => Some(Lifetime::statik()),
768 ty::ReLateBound(_, ty::BrNamed(_, name)) =>
c1a9b12d 769 Some(Lifetime(name.to_string())),
9346a6ac 770 ty::ReEarlyBound(ref data) => Some(Lifetime(data.name.clean(cx))),
1a4d82fc
JJ
771
772 ty::ReLateBound(..) |
773 ty::ReFree(..) |
774 ty::ReScope(..) |
775 ty::ReInfer(..) |
776 ty::ReEmpty(..) => None
777 }
778 }
779}
780
85aaf69f 781#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
782pub enum WherePredicate {
783 BoundPredicate { ty: Type, bounds: Vec<TyParamBound> },
784 RegionPredicate { lifetime: Lifetime, bounds: Vec<Lifetime>},
85aaf69f 785 EqPredicate { lhs: Type, rhs: Type }
1a4d82fc
JJ
786}
787
788impl Clean<WherePredicate> for ast::WherePredicate {
789 fn clean(&self, cx: &DocContext) -> WherePredicate {
790 match *self {
791 ast::WherePredicate::BoundPredicate(ref wbp) => {
792 WherePredicate::BoundPredicate {
793 ty: wbp.bounded_ty.clean(cx),
794 bounds: wbp.bounds.clean(cx)
795 }
796 }
797
798 ast::WherePredicate::RegionPredicate(ref wrp) => {
799 WherePredicate::RegionPredicate {
800 lifetime: wrp.lifetime.clean(cx),
801 bounds: wrp.bounds.clean(cx)
802 }
803 }
804
805 ast::WherePredicate::EqPredicate(_) => {
85aaf69f 806 unimplemented!() // FIXME(#20041)
1a4d82fc
JJ
807 }
808 }
809 }
810}
811
85aaf69f
SL
812impl<'a> Clean<WherePredicate> for ty::Predicate<'a> {
813 fn clean(&self, cx: &DocContext) -> WherePredicate {
814 use rustc::middle::ty::Predicate;
815
816 match *self {
817 Predicate::Trait(ref pred) => pred.clean(cx),
818 Predicate::Equate(ref pred) => pred.clean(cx),
819 Predicate::RegionOutlives(ref pred) => pred.clean(cx),
820 Predicate::TypeOutlives(ref pred) => pred.clean(cx),
821 Predicate::Projection(ref pred) => pred.clean(cx)
822 }
823 }
824}
825
826impl<'a> Clean<WherePredicate> for ty::TraitPredicate<'a> {
827 fn clean(&self, cx: &DocContext) -> WherePredicate {
828 WherePredicate::BoundPredicate {
829 ty: self.trait_ref.substs.self_ty().clean(cx).unwrap(),
830 bounds: vec![self.trait_ref.clean(cx)]
831 }
832 }
833}
834
835impl<'tcx> Clean<WherePredicate> for ty::EquatePredicate<'tcx> {
836 fn clean(&self, cx: &DocContext) -> WherePredicate {
837 let ty::EquatePredicate(ref lhs, ref rhs) = *self;
838 WherePredicate::EqPredicate {
839 lhs: lhs.clean(cx),
840 rhs: rhs.clean(cx)
841 }
842 }
843}
844
845impl Clean<WherePredicate> for ty::OutlivesPredicate<ty::Region, ty::Region> {
846 fn clean(&self, cx: &DocContext) -> WherePredicate {
847 let ty::OutlivesPredicate(ref a, ref b) = *self;
848 WherePredicate::RegionPredicate {
849 lifetime: a.clean(cx).unwrap(),
850 bounds: vec![b.clean(cx).unwrap()]
851 }
852 }
853}
854
855impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Ty<'tcx>, ty::Region> {
856 fn clean(&self, cx: &DocContext) -> WherePredicate {
857 let ty::OutlivesPredicate(ref ty, ref lt) = *self;
858
859 WherePredicate::BoundPredicate {
860 ty: ty.clean(cx),
861 bounds: vec![TyParamBound::RegionBound(lt.clean(cx).unwrap())]
862 }
863 }
864}
865
866impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
867 fn clean(&self, cx: &DocContext) -> WherePredicate {
868 WherePredicate::EqPredicate {
869 lhs: self.projection_ty.clean(cx),
870 rhs: self.ty.clean(cx)
871 }
872 }
873}
874
875impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
876 fn clean(&self, cx: &DocContext) -> Type {
877 let trait_ = match self.trait_ref.clean(cx) {
878 TyParamBound::TraitBound(t, _) => t.trait_,
9346a6ac
AL
879 TyParamBound::RegionBound(_) => {
880 panic!("cleaning a trait got a region")
881 }
85aaf69f
SL
882 };
883 Type::QPath {
884 name: self.item_name.clean(cx),
885 self_type: box self.trait_ref.self_ty().clean(cx),
886 trait_: box trait_
887 }
888 }
889}
890
d9579d0f 891// maybe use a Generic enum and use Vec<Generic>?
85aaf69f 892#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
893pub struct Generics {
894 pub lifetimes: Vec<Lifetime>,
895 pub type_params: Vec<TyParam>,
896 pub where_predicates: Vec<WherePredicate>
897}
898
899impl Clean<Generics> for ast::Generics {
900 fn clean(&self, cx: &DocContext) -> Generics {
901 Generics {
902 lifetimes: self.lifetimes.clean(cx),
903 type_params: self.ty_params.clean(cx),
904 where_predicates: self.where_clause.predicates.clean(cx)
905 }
906 }
907}
908
85aaf69f
SL
909impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>,
910 &'a ty::GenericPredicates<'tcx>,
911 subst::ParamSpace) {
1a4d82fc 912 fn clean(&self, cx: &DocContext) -> Generics {
85aaf69f 913 use std::collections::HashSet;
85aaf69f
SL
914 use self::WherePredicate as WP;
915
85aaf69f
SL
916 let (gens, preds, space) = *self;
917
9346a6ac
AL
918 // Bounds in the type_params and lifetimes fields are repeated in the
919 // predicates field (see rustc_typeck::collect::ty_generics), so remove
920 // them.
85aaf69f 921 let stripped_typarams = gens.types.get_slice(space).iter().map(|tp| {
c34b1796 922 tp.clean(cx)
85aaf69f
SL
923 }).collect::<Vec<_>>();
924 let stripped_lifetimes = gens.regions.get_slice(space).iter().map(|rp| {
925 let mut srp = rp.clone();
926 srp.bounds = Vec::new();
927 srp.clean(cx)
928 }).collect::<Vec<_>>();
929
9346a6ac
AL
930 let mut where_predicates = preds.predicates.get_slice(space)
931 .to_vec().clean(cx);
85aaf69f 932
9346a6ac
AL
933 // Type parameters and have a Sized bound by default unless removed with
934 // ?Sized. Scan through the predicates and mark any type parameter with
935 // a Sized bound, removing the bounds as we find them.
936 //
937 // Note that associated types also have a sized bound by default, but we
d9579d0f 938 // don't actually know the set of associated types right here so that's
9346a6ac 939 // handled in cleaning associated types
85aaf69f 940 let mut sized_params = HashSet::new();
9346a6ac
AL
941 where_predicates.retain(|pred| {
942 match *pred {
943 WP::BoundPredicate { ty: Generic(ref g), ref bounds } => {
944 if bounds.iter().any(|b| b.is_sized_bound(cx)) {
945 sized_params.insert(g.clone());
946 false
947 } else {
948 true
949 }
85aaf69f 950 }
9346a6ac 951 _ => true,
85aaf69f 952 }
9346a6ac 953 });
85aaf69f 954
9346a6ac
AL
955 // Run through the type parameters again and insert a ?Sized
956 // unbound for any we didn't find to be Sized.
85aaf69f
SL
957 for tp in &stripped_typarams {
958 if !sized_params.contains(&tp.name) {
85aaf69f
SL
959 where_predicates.push(WP::BoundPredicate {
960 ty: Type::Generic(tp.name.clone()),
9346a6ac 961 bounds: vec![TyParamBound::maybe_sized(cx)],
85aaf69f
SL
962 })
963 }
964 }
965
966 // It would be nice to collect all of the bounds on a type and recombine
967 // them if possible, to avoid e.g. `where T: Foo, T: Bar, T: Sized, T: 'a`
968 // and instead see `where T: Foo + Bar + Sized + 'a`
969
1a4d82fc 970 Generics {
9346a6ac 971 type_params: simplify::ty_params(stripped_typarams),
85aaf69f 972 lifetimes: stripped_lifetimes,
9346a6ac 973 where_predicates: simplify::where_clauses(cx, where_predicates),
1a4d82fc
JJ
974 }
975 }
976}
977
85aaf69f 978#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
979pub struct Method {
980 pub generics: Generics,
981 pub self_: SelfTy,
982 pub unsafety: ast::Unsafety,
62682a34 983 pub constness: ast::Constness,
1a4d82fc 984 pub decl: FnDecl,
85aaf69f 985 pub abi: abi::Abi
1a4d82fc
JJ
986}
987
c34b1796
AL
988impl Clean<Method> for ast::MethodSig {
989 fn clean(&self, cx: &DocContext) -> Method {
990 let all_inputs = &self.decl.inputs;
991 let inputs = match self.explicit_self.node {
85aaf69f 992 ast::SelfStatic => &**all_inputs,
1a4d82fc
JJ
993 _ => &all_inputs[1..]
994 };
995 let decl = FnDecl {
996 inputs: Arguments {
c34b1796 997 values: inputs.clean(cx),
1a4d82fc 998 },
c34b1796 999 output: self.decl.output.clean(cx),
1a4d82fc
JJ
1000 attrs: Vec::new()
1001 };
c34b1796
AL
1002 Method {
1003 generics: self.generics.clean(cx),
1004 self_: self.explicit_self.node.clean(cx),
62682a34
SL
1005 unsafety: self.unsafety,
1006 constness: self.constness,
c34b1796
AL
1007 decl: decl,
1008 abi: self.abi
1a4d82fc
JJ
1009 }
1010 }
1011}
1012
85aaf69f 1013#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
1014pub struct TyMethod {
1015 pub unsafety: ast::Unsafety,
1016 pub decl: FnDecl,
1017 pub generics: Generics,
1018 pub self_: SelfTy,
85aaf69f 1019 pub abi: abi::Abi
1a4d82fc
JJ
1020}
1021
c34b1796
AL
1022impl Clean<TyMethod> for ast::MethodSig {
1023 fn clean(&self, cx: &DocContext) -> TyMethod {
1a4d82fc 1024 let inputs = match self.explicit_self.node {
85aaf69f 1025 ast::SelfStatic => &*self.decl.inputs,
1a4d82fc
JJ
1026 _ => &self.decl.inputs[1..]
1027 };
1028 let decl = FnDecl {
1029 inputs: Arguments {
c34b1796 1030 values: inputs.clean(cx),
1a4d82fc
JJ
1031 },
1032 output: self.decl.output.clean(cx),
1033 attrs: Vec::new()
1034 };
c34b1796
AL
1035 TyMethod {
1036 unsafety: self.unsafety.clone(),
1037 decl: decl,
1038 self_: self.explicit_self.node.clean(cx),
1039 generics: self.generics.clean(cx),
1040 abi: self.abi
1a4d82fc
JJ
1041 }
1042 }
1043}
1044
85aaf69f 1045#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
1046pub enum SelfTy {
1047 SelfStatic,
1048 SelfValue,
1049 SelfBorrowed(Option<Lifetime>, Mutability),
1050 SelfExplicit(Type),
1051}
1052
1053impl Clean<SelfTy> for ast::ExplicitSelf_ {
1054 fn clean(&self, cx: &DocContext) -> SelfTy {
1055 match *self {
1056 ast::SelfStatic => SelfStatic,
1057 ast::SelfValue(_) => SelfValue,
1058 ast::SelfRegion(ref lt, ref mt, _) => {
1059 SelfBorrowed(lt.clean(cx), mt.clean(cx))
1060 }
1061 ast::SelfExplicit(ref typ, _) => SelfExplicit(typ.clean(cx)),
1062 }
1063 }
1064}
1065
85aaf69f 1066#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
1067pub struct Function {
1068 pub decl: FnDecl,
1069 pub generics: Generics,
1070 pub unsafety: ast::Unsafety,
62682a34
SL
1071 pub constness: ast::Constness,
1072 pub abi: abi::Abi,
1a4d82fc
JJ
1073}
1074
1075impl Clean<Item> for doctree::Function {
1076 fn clean(&self, cx: &DocContext) -> Item {
1077 Item {
1078 name: Some(self.name.clean(cx)),
1079 attrs: self.attrs.clean(cx),
1080 source: self.whence.clean(cx),
1081 visibility: self.vis.clean(cx),
1082 stability: self.stab.clean(cx),
1083 def_id: ast_util::local_def(self.id),
1084 inner: FunctionItem(Function {
1085 decl: self.decl.clean(cx),
1086 generics: self.generics.clean(cx),
1087 unsafety: self.unsafety,
62682a34 1088 constness: self.constness,
9346a6ac 1089 abi: self.abi,
1a4d82fc
JJ
1090 }),
1091 }
1092 }
1093}
1094
85aaf69f 1095#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
1096pub struct FnDecl {
1097 pub inputs: Arguments,
1098 pub output: FunctionRetTy,
1099 pub attrs: Vec<Attribute>,
1100}
1101
85aaf69f 1102#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
1103pub struct Arguments {
1104 pub values: Vec<Argument>,
1105}
1106
1107impl Clean<FnDecl> for ast::FnDecl {
1108 fn clean(&self, cx: &DocContext) -> FnDecl {
1109 FnDecl {
1110 inputs: Arguments {
1111 values: self.inputs.clean(cx),
1112 },
1113 output: self.output.clean(cx),
1114 attrs: Vec::new()
1115 }
1116 }
1117}
1118
1119impl<'tcx> Clean<Type> for ty::FnOutput<'tcx> {
1120 fn clean(&self, cx: &DocContext) -> Type {
1121 match *self {
1122 ty::FnConverging(ty) => ty.clean(cx),
1123 ty::FnDiverging => Bottom
1124 }
1125 }
1126}
1127
1128impl<'a, 'tcx> Clean<FnDecl> for (ast::DefId, &'a ty::PolyFnSig<'tcx>) {
1129 fn clean(&self, cx: &DocContext) -> FnDecl {
1130 let (did, sig) = *self;
1131 let mut names = if did.node != 0 {
1132 csearch::get_method_arg_names(&cx.tcx().sess.cstore, did).into_iter()
1133 } else {
1134 Vec::new().into_iter()
1135 }.peekable();
85aaf69f 1136 if names.peek().map(|s| &**s) == Some("self") {
1a4d82fc
JJ
1137 let _ = names.next();
1138 }
1139 FnDecl {
1140 output: Return(sig.0.output.clean(cx)),
1141 attrs: Vec::new(),
1142 inputs: Arguments {
1143 values: sig.0.inputs.iter().map(|t| {
1144 Argument {
1145 type_: t.clean(cx),
1146 id: 0,
1147 name: names.next().unwrap_or("".to_string()),
1148 }
1149 }).collect(),
1150 },
1151 }
1152 }
1153}
1154
85aaf69f 1155#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
1156pub struct Argument {
1157 pub type_: Type,
1158 pub name: String,
1159 pub id: ast::NodeId,
1160}
1161
1162impl Clean<Argument> for ast::Arg {
1163 fn clean(&self, cx: &DocContext) -> Argument {
1164 Argument {
1165 name: name_from_pat(&*self.pat),
1166 type_: (self.ty.clean(cx)),
1167 id: self.id
1168 }
1169 }
1170}
1171
85aaf69f 1172#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
1173pub enum FunctionRetTy {
1174 Return(Type),
85aaf69f 1175 DefaultReturn,
1a4d82fc
JJ
1176 NoReturn
1177}
1178
1179impl Clean<FunctionRetTy> for ast::FunctionRetTy {
1180 fn clean(&self, cx: &DocContext) -> FunctionRetTy {
1181 match *self {
1182 ast::Return(ref typ) => Return(typ.clean(cx)),
85aaf69f
SL
1183 ast::DefaultReturn(..) => DefaultReturn,
1184 ast::NoReturn(..) => NoReturn
1a4d82fc
JJ
1185 }
1186 }
1187}
1188
85aaf69f 1189#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
1190pub struct Trait {
1191 pub unsafety: ast::Unsafety,
c34b1796 1192 pub items: Vec<Item>,
1a4d82fc
JJ
1193 pub generics: Generics,
1194 pub bounds: Vec<TyParamBound>,
1195}
1196
1197impl Clean<Item> for doctree::Trait {
1198 fn clean(&self, cx: &DocContext) -> Item {
1199 Item {
1200 name: Some(self.name.clean(cx)),
1201 attrs: self.attrs.clean(cx),
1202 source: self.whence.clean(cx),
1203 def_id: ast_util::local_def(self.id),
1204 visibility: self.vis.clean(cx),
1205 stability: self.stab.clean(cx),
1206 inner: TraitItem(Trait {
1207 unsafety: self.unsafety,
1208 items: self.items.clean(cx),
1209 generics: self.generics.clean(cx),
1210 bounds: self.bounds.clean(cx),
1211 }),
1212 }
1213 }
1214}
1215
1216impl Clean<Type> for ast::TraitRef {
1217 fn clean(&self, cx: &DocContext) -> Type {
1218 resolve_type(cx, self.path.clean(cx), self.ref_id)
1219 }
1220}
1221
1222impl Clean<PolyTrait> for ast::PolyTraitRef {
1223 fn clean(&self, cx: &DocContext) -> PolyTrait {
1224 PolyTrait {
1225 trait_: self.trait_ref.clean(cx),
1226 lifetimes: self.bound_lifetimes.clean(cx)
1227 }
1228 }
1229}
1230
c34b1796
AL
1231impl Clean<Item> for ast::TraitItem {
1232 fn clean(&self, cx: &DocContext) -> Item {
1233 let inner = match self.node {
d9579d0f
AL
1234 ast::ConstTraitItem(ref ty, ref default) => {
1235 AssociatedConstItem(ty.clean(cx),
1236 default.as_ref().map(|expr|
1237 expr.span.to_src(cx)))
1238 }
c34b1796
AL
1239 ast::MethodTraitItem(ref sig, Some(_)) => {
1240 MethodItem(sig.clean(cx))
1241 }
1242 ast::MethodTraitItem(ref sig, None) => {
1243 TyMethodItem(sig.clean(cx))
1244 }
1245 ast::TypeTraitItem(ref bounds, ref default) => {
1246 AssociatedTypeItem(bounds.clean(cx), default.clean(cx))
1247 }
1248 };
1249 Item {
1250 name: Some(self.ident.clean(cx)),
1251 attrs: self.attrs.clean(cx),
1252 source: self.span.clean(cx),
1253 def_id: ast_util::local_def(self.id),
1254 visibility: None,
1255 stability: get_stability(cx, ast_util::local_def(self.id)),
1256 inner: inner
1a4d82fc
JJ
1257 }
1258 }
1259}
1260
c34b1796
AL
1261impl Clean<Item> for ast::ImplItem {
1262 fn clean(&self, cx: &DocContext) -> Item {
1263 let inner = match self.node {
d9579d0f
AL
1264 ast::ConstImplItem(ref ty, ref expr) => {
1265 ConstantItem(Constant{
1266 type_: ty.clean(cx),
1267 expr: expr.span.to_src(cx),
1268 })
1269 }
c34b1796
AL
1270 ast::MethodImplItem(ref sig, _) => {
1271 MethodItem(sig.clean(cx))
1272 }
1273 ast::TypeImplItem(ref ty) => TypedefItem(Typedef {
1274 type_: ty.clean(cx),
1275 generics: Generics {
1276 lifetimes: Vec::new(),
1277 type_params: Vec::new(),
1278 where_predicates: Vec::new()
1279 },
62682a34 1280 }, true),
c34b1796
AL
1281 ast::MacImplItem(_) => {
1282 MacroItem(Macro {
1283 source: self.span.to_src(cx),
d9579d0f 1284 imported_from: None,
c34b1796
AL
1285 })
1286 }
1287 };
1288 Item {
1289 name: Some(self.ident.clean(cx)),
1290 source: self.span.clean(cx),
1291 attrs: self.attrs.clean(cx),
1292 def_id: ast_util::local_def(self.id),
1293 visibility: self.vis.clean(cx),
1294 stability: get_stability(cx, ast_util::local_def(self.id)),
1295 inner: inner
1a4d82fc
JJ
1296 }
1297 }
1298}
1299
1300impl<'tcx> Clean<Item> for ty::Method<'tcx> {
1301 fn clean(&self, cx: &DocContext) -> Item {
1302 let (self_, sig) = match self.explicit_self {
1303 ty::StaticExplicitSelfCategory => (ast::SelfStatic.clean(cx),
1304 self.fty.sig.clone()),
1305 s => {
1306 let sig = ty::Binder(ty::FnSig {
1307 inputs: self.fty.sig.0.inputs[1..].to_vec(),
1308 ..self.fty.sig.0.clone()
1309 });
1310 let s = match s {
1311 ty::ByValueExplicitSelfCategory => SelfValue,
1312 ty::ByReferenceExplicitSelfCategory(..) => {
1313 match self.fty.sig.0.inputs[0].sty {
62682a34 1314 ty::TyRef(r, mt) => {
1a4d82fc
JJ
1315 SelfBorrowed(r.clean(cx), mt.mutbl.clean(cx))
1316 }
1317 _ => unreachable!(),
1318 }
1319 }
1320 ty::ByBoxExplicitSelfCategory => {
1321 SelfExplicit(self.fty.sig.0.inputs[0].clean(cx))
1322 }
1323 ty::StaticExplicitSelfCategory => unreachable!(),
1324 };
1325 (s, sig)
1326 }
1327 };
1328
9346a6ac
AL
1329 let generics = (&self.generics, &self.predicates,
1330 subst::FnSpace).clean(cx);
1331 let decl = (self.def_id, &sig).clean(cx);
1332 let provided = match self.container {
1333 ty::ImplContainer(..) => false,
1334 ty::TraitContainer(did) => {
c1a9b12d 1335 cx.tcx().provided_trait_methods(did).iter().any(|m| {
9346a6ac
AL
1336 m.def_id == self.def_id
1337 })
1338 }
1339 };
1340 let inner = if provided {
1341 MethodItem(Method {
1342 unsafety: self.fty.unsafety,
1343 generics: generics,
1344 self_: self_,
1345 decl: decl,
62682a34
SL
1346 abi: self.fty.abi,
1347
1348 // trait methods canot (currently, at least) be const
1349 constness: ast::Constness::NotConst,
9346a6ac
AL
1350 })
1351 } else {
1352 TyMethodItem(TyMethod {
1353 unsafety: self.fty.unsafety,
1354 generics: generics,
1355 self_: self_,
1356 decl: decl,
62682a34 1357 abi: self.fty.abi,
9346a6ac
AL
1358 })
1359 };
1360
1a4d82fc
JJ
1361 Item {
1362 name: Some(self.name.clean(cx)),
1363 visibility: Some(ast::Inherited),
1364 stability: get_stability(cx, self.def_id),
1365 def_id: self.def_id,
1366 attrs: inline::load_attrs(cx, cx.tcx(), self.def_id),
1367 source: Span::empty(),
9346a6ac 1368 inner: inner,
1a4d82fc
JJ
1369 }
1370 }
1371}
1372
1373impl<'tcx> Clean<Item> for ty::ImplOrTraitItem<'tcx> {
1374 fn clean(&self, cx: &DocContext) -> Item {
1375 match *self {
d9579d0f 1376 ty::ConstTraitItem(ref cti) => cti.clean(cx),
1a4d82fc
JJ
1377 ty::MethodTraitItem(ref mti) => mti.clean(cx),
1378 ty::TypeTraitItem(ref tti) => tti.clean(cx),
1379 }
1380 }
1381}
1382
1383/// A trait reference, which may have higher ranked lifetimes.
85aaf69f 1384#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
1385pub struct PolyTrait {
1386 pub trait_: Type,
1387 pub lifetimes: Vec<Lifetime>
1388}
1389
1390/// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
1391/// type out of the AST/ty::ctxt given one of these, if more information is needed. Most importantly
1392/// it does not preserve mutability or boxes.
85aaf69f 1393#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc 1394pub enum Type {
62682a34 1395 /// structs/enums/traits (most that'd be an ast::TyPath)
1a4d82fc
JJ
1396 ResolvedPath {
1397 path: Path,
1398 typarams: Option<Vec<TyParamBound>>,
1399 did: ast::DefId,
62682a34
SL
1400 /// true if is a `T::Name` path for associated types
1401 is_generic: bool,
1a4d82fc 1402 },
1a4d82fc
JJ
1403 /// For parameterized types, so the consumer of the JSON don't go
1404 /// looking for types which don't exist anywhere.
1405 Generic(String),
c34b1796
AL
1406 /// Primitives are the fixed-size numeric types (plus int/usize/float), char,
1407 /// arrays, slices, and tuples.
1a4d82fc 1408 Primitive(PrimitiveType),
1a4d82fc
JJ
1409 /// extern "ABI" fn
1410 BareFunction(Box<BareFunctionDecl>),
1411 Tuple(Vec<Type>),
1412 Vector(Box<Type>),
1413 FixedVector(Box<Type>, String),
1414 /// aka TyBot
1415 Bottom,
1416 Unique(Box<Type>),
1417 RawPointer(Mutability, Box<Type>),
1418 BorrowedRef {
1419 lifetime: Option<Lifetime>,
1420 mutability: Mutability,
1421 type_: Box<Type>,
1422 },
1423
1424 // <Type as Trait>::Name
1425 QPath {
1426 name: String,
1427 self_type: Box<Type>,
1428 trait_: Box<Type>
1429 },
1430
1431 // _
1432 Infer,
1433
1434 // for<'a> Foo(&'a)
1435 PolyTraitRef(Vec<TyParamBound>),
1436}
1437
85aaf69f 1438#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Copy, Debug)]
1a4d82fc
JJ
1439pub enum PrimitiveType {
1440 Isize, I8, I16, I32, I64,
1441 Usize, U8, U16, U32, U64,
1442 F32, F64,
1443 Char,
1444 Bool,
1445 Str,
1446 Slice,
c34b1796 1447 Array,
1a4d82fc 1448 PrimitiveTuple,
9346a6ac 1449 PrimitiveRawPointer,
1a4d82fc
JJ
1450}
1451
85aaf69f 1452#[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)]
1a4d82fc
JJ
1453pub enum TypeKind {
1454 TypeEnum,
1455 TypeFunction,
1456 TypeModule,
1457 TypeConst,
1458 TypeStatic,
1459 TypeStruct,
1460 TypeTrait,
1461 TypeVariant,
1462 TypeTypedef,
1463}
1464
9346a6ac
AL
1465impl Type {
1466 pub fn primitive_type(&self) -> Option<PrimitiveType> {
1467 match *self {
1468 Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p),
1469 Vector(..) | BorrowedRef{ type_: box Vector(..), .. } => Some(Slice),
1470 FixedVector(..) | BorrowedRef { type_: box FixedVector(..), .. } => {
1471 Some(Array)
1472 }
1473 Tuple(..) => Some(PrimitiveTuple),
1474 RawPointer(..) => Some(PrimitiveRawPointer),
1475 _ => None,
1476 }
1477 }
1478}
1479
1a4d82fc
JJ
1480impl PrimitiveType {
1481 fn from_str(s: &str) -> Option<PrimitiveType> {
85aaf69f 1482 match s {
c34b1796 1483 "isize" => Some(Isize),
1a4d82fc
JJ
1484 "i8" => Some(I8),
1485 "i16" => Some(I16),
1486 "i32" => Some(I32),
1487 "i64" => Some(I64),
c34b1796 1488 "usize" => Some(Usize),
1a4d82fc
JJ
1489 "u8" => Some(U8),
1490 "u16" => Some(U16),
1491 "u32" => Some(U32),
1492 "u64" => Some(U64),
1493 "bool" => Some(Bool),
1494 "char" => Some(Char),
1495 "str" => Some(Str),
1496 "f32" => Some(F32),
1497 "f64" => Some(F64),
c34b1796 1498 "array" => Some(Array),
1a4d82fc
JJ
1499 "slice" => Some(Slice),
1500 "tuple" => Some(PrimitiveTuple),
9346a6ac 1501 "pointer" => Some(PrimitiveRawPointer),
1a4d82fc
JJ
1502 _ => None,
1503 }
1504 }
1505
1506 fn find(attrs: &[Attribute]) -> Option<PrimitiveType> {
85aaf69f 1507 for attr in attrs {
1a4d82fc
JJ
1508 let list = match *attr {
1509 List(ref k, ref l) if *k == "doc" => l,
1510 _ => continue,
1511 };
85aaf69f 1512 for sub_attr in list {
1a4d82fc
JJ
1513 let value = match *sub_attr {
1514 NameValue(ref k, ref v)
85aaf69f 1515 if *k == "primitive" => v,
1a4d82fc
JJ
1516 _ => continue,
1517 };
1518 match PrimitiveType::from_str(value) {
1519 Some(p) => return Some(p),
1520 None => {}
1521 }
1522 }
1523 }
1524 return None
1525 }
1526
1527 pub fn to_string(&self) -> &'static str {
1528 match *self {
1529 Isize => "isize",
1530 I8 => "i8",
1531 I16 => "i16",
1532 I32 => "i32",
1533 I64 => "i64",
1534 Usize => "usize",
1535 U8 => "u8",
1536 U16 => "u16",
1537 U32 => "u32",
1538 U64 => "u64",
1539 F32 => "f32",
1540 F64 => "f64",
1541 Str => "str",
1542 Bool => "bool",
1543 Char => "char",
c34b1796 1544 Array => "array",
1a4d82fc
JJ
1545 Slice => "slice",
1546 PrimitiveTuple => "tuple",
9346a6ac 1547 PrimitiveRawPointer => "pointer",
1a4d82fc
JJ
1548 }
1549 }
1550
1551 pub fn to_url_str(&self) -> &'static str {
1552 self.to_string()
1553 }
1554
1555 /// Creates a rustdoc-specific node id for primitive types.
1556 ///
1557 /// These node ids are generally never used by the AST itself.
1558 pub fn to_node_id(&self) -> ast::NodeId {
1559 u32::MAX - 1 - (*self as u32)
1560 }
1561}
1562
1563impl Clean<Type> for ast::Ty {
1564 fn clean(&self, cx: &DocContext) -> Type {
1565 use syntax::ast::*;
1566 match self.node {
1567 TyPtr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)),
1568 TyRptr(ref l, ref m) =>
1569 BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx),
1570 type_: box m.ty.clean(cx)},
1571 TyVec(ref ty) => Vector(box ty.clean(cx)),
1572 TyFixedLengthVec(ref ty, ref e) => FixedVector(box ty.clean(cx),
1573 e.span.to_src(cx)),
1574 TyTup(ref tys) => Tuple(tys.clean(cx)),
c34b1796
AL
1575 TyPath(None, ref p) => {
1576 resolve_type(cx, p.clean(cx), self.id)
1577 }
1578 TyPath(Some(ref qself), ref p) => {
1579 let mut trait_path = p.clone();
1580 trait_path.segments.pop();
1581 Type::QPath {
1582 name: p.segments.last().unwrap().identifier.clean(cx),
1583 self_type: box qself.ty.clean(cx),
1584 trait_: box resolve_type(cx, trait_path.clean(cx), self.id)
1585 }
1a4d82fc
JJ
1586 }
1587 TyObjectSum(ref lhs, ref bounds) => {
1588 let lhs_ty = lhs.clean(cx);
1589 match lhs_ty {
62682a34
SL
1590 ResolvedPath { path, typarams: None, did, is_generic } => {
1591 ResolvedPath {
1592 path: path,
1593 typarams: Some(bounds.clean(cx)),
1594 did: did,
1595 is_generic: is_generic,
1596 }
1a4d82fc
JJ
1597 }
1598 _ => {
1599 lhs_ty // shouldn't happen
1600 }
1601 }
1602 }
1603 TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
1604 TyParen(ref ty) => ty.clean(cx),
1a4d82fc
JJ
1605 TyPolyTraitRef(ref bounds) => {
1606 PolyTraitRef(bounds.clean(cx))
1607 },
1608 TyInfer(..) => {
1609 Infer
1610 },
1611 TyTypeof(..) => {
1612 panic!("Unimplemented type {:?}", self.node)
1613 },
1614 }
1615 }
1616}
1617
1618impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
1619 fn clean(&self, cx: &DocContext) -> Type {
1620 match self.sty {
62682a34
SL
1621 ty::TyBool => Primitive(Bool),
1622 ty::TyChar => Primitive(Char),
1623 ty::TyInt(ast::TyIs) => Primitive(Isize),
1624 ty::TyInt(ast::TyI8) => Primitive(I8),
1625 ty::TyInt(ast::TyI16) => Primitive(I16),
1626 ty::TyInt(ast::TyI32) => Primitive(I32),
1627 ty::TyInt(ast::TyI64) => Primitive(I64),
1628 ty::TyUint(ast::TyUs) => Primitive(Usize),
1629 ty::TyUint(ast::TyU8) => Primitive(U8),
1630 ty::TyUint(ast::TyU16) => Primitive(U16),
1631 ty::TyUint(ast::TyU32) => Primitive(U32),
1632 ty::TyUint(ast::TyU64) => Primitive(U64),
1633 ty::TyFloat(ast::TyF32) => Primitive(F32),
1634 ty::TyFloat(ast::TyF64) => Primitive(F64),
1635 ty::TyStr => Primitive(Str),
1636 ty::TyBox(t) => {
1a4d82fc
JJ
1637 let box_did = cx.tcx_opt().and_then(|tcx| {
1638 tcx.lang_items.owned_box()
1639 });
1640 lang_struct(cx, box_did, t, "Box", Unique)
1641 }
62682a34
SL
1642 ty::TySlice(ty) => Vector(box ty.clean(cx)),
1643 ty::TyArray(ty, i) => FixedVector(box ty.clean(cx),
1644 format!("{}", i)),
1645 ty::TyRawPtr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)),
1646 ty::TyRef(r, mt) => BorrowedRef {
1a4d82fc
JJ
1647 lifetime: r.clean(cx),
1648 mutability: mt.mutbl.clean(cx),
1649 type_: box mt.ty.clean(cx),
1650 },
62682a34 1651 ty::TyBareFn(_, ref fty) => BareFunction(box BareFunctionDecl {
1a4d82fc
JJ
1652 unsafety: fty.unsafety,
1653 generics: Generics {
1654 lifetimes: Vec::new(),
1655 type_params: Vec::new(),
1656 where_predicates: Vec::new()
1657 },
1658 decl: (ast_util::local_def(0), &fty.sig).clean(cx),
1659 abi: fty.abi.to_string(),
1660 }),
62682a34
SL
1661 ty::TyStruct(did, substs) |
1662 ty::TyEnum(did, substs) => {
1a4d82fc
JJ
1663 let fqn = csearch::get_item_path(cx.tcx(), did);
1664 let fqn: Vec<_> = fqn.into_iter().map(|i| i.to_string()).collect();
1665 let kind = match self.sty {
62682a34 1666 ty::TyStruct(..) => TypeStruct,
1a4d82fc
JJ
1667 _ => TypeEnum,
1668 };
85aaf69f
SL
1669 let path = external_path(cx, &fqn.last().unwrap().to_string(),
1670 None, vec![], substs);
1a4d82fc
JJ
1671 cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, kind));
1672 ResolvedPath {
1673 path: path,
1674 typarams: None,
1675 did: did,
62682a34 1676 is_generic: false,
1a4d82fc
JJ
1677 }
1678 }
62682a34 1679 ty::TyTrait(box ty::TraitTy { ref principal, ref bounds }) => {
1a4d82fc
JJ
1680 let did = principal.def_id();
1681 let fqn = csearch::get_item_path(cx.tcx(), did);
1682 let fqn: Vec<_> = fqn.into_iter().map(|i| i.to_string()).collect();
85aaf69f
SL
1683 let (typarams, bindings) = bounds.clean(cx);
1684 let path = external_path(cx, &fqn.last().unwrap().to_string(),
1685 Some(did), bindings, principal.substs());
1a4d82fc
JJ
1686 cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, TypeTrait));
1687 ResolvedPath {
1688 path: path,
85aaf69f 1689 typarams: Some(typarams),
1a4d82fc 1690 did: did,
62682a34 1691 is_generic: false,
1a4d82fc
JJ
1692 }
1693 }
62682a34 1694 ty::TyTuple(ref t) => Tuple(t.clean(cx)),
1a4d82fc 1695
62682a34 1696 ty::TyProjection(ref data) => data.clean(cx),
1a4d82fc 1697
c1a9b12d 1698 ty::TyParam(ref p) => Generic(p.name.to_string()),
1a4d82fc 1699
62682a34 1700 ty::TyClosure(..) => Tuple(vec![]), // FIXME(pcwalton)
1a4d82fc 1701
62682a34
SL
1702 ty::TyInfer(..) => panic!("TyInfer"),
1703 ty::TyError => panic!("TyError"),
1a4d82fc
JJ
1704 }
1705 }
1706}
1707
85aaf69f 1708#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
1709pub enum StructField {
1710 HiddenStructField, // inserted later by strip passes
1711 TypedStructField(Type),
1712}
1713
1714impl Clean<Item> for ast::StructField {
1715 fn clean(&self, cx: &DocContext) -> Item {
1716 let (name, vis) = match self.node.kind {
1717 ast::NamedField(id, vis) => (Some(id), vis),
1718 ast::UnnamedField(vis) => (None, vis)
1719 };
1720 Item {
1721 name: name.clean(cx),
1722 attrs: self.node.attrs.clean(cx),
1723 source: self.span.clean(cx),
1724 visibility: Some(vis),
1725 stability: get_stability(cx, ast_util::local_def(self.node.id)),
1726 def_id: ast_util::local_def(self.node.id),
1727 inner: StructFieldItem(TypedStructField(self.node.ty.clean(cx))),
1728 }
1729 }
1730}
1731
c1a9b12d 1732impl Clean<Item> for ty::FieldTy {
1a4d82fc
JJ
1733 fn clean(&self, cx: &DocContext) -> Item {
1734 use syntax::parse::token::special_idents::unnamed_field;
1735 use rustc::metadata::csearch;
1736
1737 let attr_map = csearch::get_struct_field_attrs(&cx.tcx().sess.cstore, self.id);
1738
1739 let (name, attrs) = if self.name == unnamed_field.name {
1740 (None, None)
1741 } else {
1742 (Some(self.name), Some(attr_map.get(&self.id.node).unwrap()))
1743 };
1744
c1a9b12d 1745 let ty = cx.tcx().lookup_item_type(self.id);
1a4d82fc
JJ
1746
1747 Item {
1748 name: name.clean(cx),
1749 attrs: attrs.unwrap_or(&Vec::new()).clean(cx),
1750 source: Span::empty(),
1751 visibility: Some(self.vis),
1752 stability: get_stability(cx, self.id),
1753 def_id: self.id,
1754 inner: StructFieldItem(TypedStructField(ty.ty.clean(cx))),
1755 }
1756 }
1757}
1758
1759pub type Visibility = ast::Visibility;
1760
1761impl Clean<Option<Visibility>> for ast::Visibility {
1762 fn clean(&self, _: &DocContext) -> Option<Visibility> {
1763 Some(*self)
1764 }
1765}
1766
85aaf69f 1767#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
1768pub struct Struct {
1769 pub struct_type: doctree::StructType,
1770 pub generics: Generics,
1771 pub fields: Vec<Item>,
1772 pub fields_stripped: bool,
1773}
1774
1775impl Clean<Item> for doctree::Struct {
1776 fn clean(&self, cx: &DocContext) -> Item {
1777 Item {
1778 name: Some(self.name.clean(cx)),
1779 attrs: self.attrs.clean(cx),
1780 source: self.whence.clean(cx),
1781 def_id: ast_util::local_def(self.id),
1782 visibility: self.vis.clean(cx),
1783 stability: self.stab.clean(cx),
1784 inner: StructItem(Struct {
1785 struct_type: self.struct_type,
1786 generics: self.generics.clean(cx),
1787 fields: self.fields.clean(cx),
1788 fields_stripped: false,
1789 }),
1790 }
1791 }
1792}
1793
1794/// This is a more limited form of the standard Struct, different in that
1795/// it lacks the things most items have (name, id, parameterization). Found
1796/// only as a variant in an enum.
85aaf69f 1797#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
1798pub struct VariantStruct {
1799 pub struct_type: doctree::StructType,
1800 pub fields: Vec<Item>,
1801 pub fields_stripped: bool,
1802}
1803
1804impl Clean<VariantStruct> for syntax::ast::StructDef {
1805 fn clean(&self, cx: &DocContext) -> VariantStruct {
1806 VariantStruct {
1807 struct_type: doctree::struct_type_from_def(self),
1808 fields: self.fields.clean(cx),
1809 fields_stripped: false,
1810 }
1811 }
1812}
1813
85aaf69f 1814#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
1815pub struct Enum {
1816 pub variants: Vec<Item>,
1817 pub generics: Generics,
1818 pub variants_stripped: bool,
1819}
1820
1821impl Clean<Item> for doctree::Enum {
1822 fn clean(&self, cx: &DocContext) -> Item {
1823 Item {
1824 name: Some(self.name.clean(cx)),
1825 attrs: self.attrs.clean(cx),
1826 source: self.whence.clean(cx),
1827 def_id: ast_util::local_def(self.id),
1828 visibility: self.vis.clean(cx),
1829 stability: self.stab.clean(cx),
1830 inner: EnumItem(Enum {
1831 variants: self.variants.clean(cx),
1832 generics: self.generics.clean(cx),
1833 variants_stripped: false,
1834 }),
1835 }
1836 }
1837}
1838
85aaf69f 1839#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
1840pub struct Variant {
1841 pub kind: VariantKind,
1842}
1843
1844impl Clean<Item> for doctree::Variant {
1845 fn clean(&self, cx: &DocContext) -> Item {
1846 Item {
1847 name: Some(self.name.clean(cx)),
1848 attrs: self.attrs.clean(cx),
1849 source: self.whence.clean(cx),
1850 visibility: self.vis.clean(cx),
1851 stability: self.stab.clean(cx),
1852 def_id: ast_util::local_def(self.id),
1853 inner: VariantItem(Variant {
1854 kind: self.kind.clean(cx),
1855 }),
1856 }
1857 }
1858}
1859
1860impl<'tcx> Clean<Item> for ty::VariantInfo<'tcx> {
1861 fn clean(&self, cx: &DocContext) -> Item {
1862 // use syntax::parse::token::special_idents::unnamed_field;
85aaf69f 1863 let kind = match self.arg_names.as_ref().map(|s| &**s) {
9346a6ac 1864 None | Some([]) if self.args.is_empty() => CLikeVariant,
1a4d82fc
JJ
1865 None | Some([]) => {
1866 TupleVariant(self.args.clean(cx))
1867 }
1868 Some(s) => {
1869 StructVariant(VariantStruct {
1870 struct_type: doctree::Plain,
1871 fields_stripped: false,
62682a34 1872 fields: s.iter().zip(&self.args).map(|(name, ty)| {
1a4d82fc
JJ
1873 Item {
1874 source: Span::empty(),
1875 name: Some(name.clean(cx)),
1876 attrs: Vec::new(),
1877 visibility: Some(ast::Public),
1878 // FIXME: this is not accurate, we need an id for
1879 // the specific field but we're using the id
1880 // for the whole variant. Thus we read the
1881 // stability from the whole variant as well.
1882 // Struct variants are experimental and need
1883 // more infrastructure work before we can get
1884 // at the needed information here.
1885 def_id: self.id,
1886 stability: get_stability(cx, self.id),
1887 inner: StructFieldItem(
1888 TypedStructField(ty.clean(cx))
1889 )
1890 }
1891 }).collect()
1892 })
1893 }
1894 };
1895 Item {
1896 name: Some(self.name.clean(cx)),
1897 attrs: inline::load_attrs(cx, cx.tcx(), self.id),
1898 source: Span::empty(),
1899 visibility: Some(ast::Public),
1900 def_id: self.id,
1901 inner: VariantItem(Variant { kind: kind }),
1902 stability: get_stability(cx, self.id),
1903 }
1904 }
1905}
1906
85aaf69f 1907#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
1908pub enum VariantKind {
1909 CLikeVariant,
1910 TupleVariant(Vec<Type>),
1911 StructVariant(VariantStruct),
1912}
1913
1914impl Clean<VariantKind> for ast::VariantKind {
1915 fn clean(&self, cx: &DocContext) -> VariantKind {
1916 match self {
1917 &ast::TupleVariantKind(ref args) => {
9346a6ac 1918 if args.is_empty() {
1a4d82fc
JJ
1919 CLikeVariant
1920 } else {
1921 TupleVariant(args.iter().map(|x| x.ty.clean(cx)).collect())
1922 }
1923 },
1924 &ast::StructVariantKind(ref sd) => StructVariant(sd.clean(cx)),
1925 }
1926 }
1927}
1928
85aaf69f 1929#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
1930pub struct Span {
1931 pub filename: String,
c34b1796
AL
1932 pub loline: usize,
1933 pub locol: usize,
1934 pub hiline: usize,
1935 pub hicol: usize,
1a4d82fc
JJ
1936}
1937
1938impl Span {
1939 fn empty() -> Span {
1940 Span {
1941 filename: "".to_string(),
1942 loline: 0, locol: 0,
1943 hiline: 0, hicol: 0,
1944 }
1945 }
1946}
1947
1948impl Clean<Span> for syntax::codemap::Span {
1949 fn clean(&self, cx: &DocContext) -> Span {
c1a9b12d
SL
1950 if *self == DUMMY_SP {
1951 return Span::empty();
1952 }
1953
1a4d82fc
JJ
1954 let cm = cx.sess().codemap();
1955 let filename = cm.span_to_filename(*self);
1956 let lo = cm.lookup_char_pos(self.lo);
1957 let hi = cm.lookup_char_pos(self.hi);
1958 Span {
1959 filename: filename.to_string(),
1960 loline: lo.line,
85aaf69f 1961 locol: lo.col.to_usize(),
1a4d82fc 1962 hiline: hi.line,
85aaf69f 1963 hicol: hi.col.to_usize(),
1a4d82fc
JJ
1964 }
1965 }
1966}
1967
85aaf69f 1968#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
1969pub struct Path {
1970 pub global: bool,
1971 pub segments: Vec<PathSegment>,
1972}
1973
9346a6ac
AL
1974impl Path {
1975 pub fn singleton(name: String) -> Path {
1976 Path {
1977 global: false,
1978 segments: vec![PathSegment {
1979 name: name,
1980 params: PathParameters::AngleBracketed {
1981 lifetimes: Vec::new(),
1982 types: Vec::new(),
1983 bindings: Vec::new()
1984 }
1985 }]
1986 }
1987 }
1988}
1989
1a4d82fc
JJ
1990impl Clean<Path> for ast::Path {
1991 fn clean(&self, cx: &DocContext) -> Path {
1992 Path {
1993 global: self.global,
1994 segments: self.segments.clean(cx),
1995 }
1996 }
1997}
1998
85aaf69f 1999#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
2000pub enum PathParameters {
2001 AngleBracketed {
2002 lifetimes: Vec<Lifetime>,
2003 types: Vec<Type>,
2004 bindings: Vec<TypeBinding>
2005 },
2006 Parenthesized {
2007 inputs: Vec<Type>,
2008 output: Option<Type>
2009 }
2010}
2011
2012impl Clean<PathParameters> for ast::PathParameters {
2013 fn clean(&self, cx: &DocContext) -> PathParameters {
2014 match *self {
2015 ast::AngleBracketedParameters(ref data) => {
2016 PathParameters::AngleBracketed {
2017 lifetimes: data.lifetimes.clean(cx),
2018 types: data.types.clean(cx),
2019 bindings: data.bindings.clean(cx)
2020 }
2021 }
2022
2023 ast::ParenthesizedParameters(ref data) => {
2024 PathParameters::Parenthesized {
2025 inputs: data.inputs.clean(cx),
2026 output: data.output.clean(cx)
2027 }
2028 }
2029 }
2030 }
2031}
2032
85aaf69f 2033#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
2034pub struct PathSegment {
2035 pub name: String,
2036 pub params: PathParameters
2037}
2038
2039impl Clean<PathSegment> for ast::PathSegment {
2040 fn clean(&self, cx: &DocContext) -> PathSegment {
2041 PathSegment {
2042 name: self.identifier.clean(cx),
2043 params: self.parameters.clean(cx)
2044 }
2045 }
2046}
2047
2048fn path_to_string(p: &ast::Path) -> String {
2049 let mut s = String::new();
2050 let mut first = true;
c1a9b12d 2051 for i in p.segments.iter().map(|x| x.identifier.name.as_str()) {
1a4d82fc
JJ
2052 if !first || p.global {
2053 s.push_str("::");
2054 } else {
2055 first = false;
2056 }
85aaf69f 2057 s.push_str(&i);
1a4d82fc
JJ
2058 }
2059 s
2060}
2061
2062impl Clean<String> for ast::Ident {
2063 fn clean(&self, _: &DocContext) -> String {
c1a9b12d 2064 self.to_string()
1a4d82fc
JJ
2065 }
2066}
2067
2068impl Clean<String> for ast::Name {
2069 fn clean(&self, _: &DocContext) -> String {
c1a9b12d 2070 self.to_string()
1a4d82fc
JJ
2071 }
2072}
2073
85aaf69f 2074#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
2075pub struct Typedef {
2076 pub type_: Type,
2077 pub generics: Generics,
2078}
2079
2080impl Clean<Item> for doctree::Typedef {
2081 fn clean(&self, cx: &DocContext) -> Item {
2082 Item {
2083 name: Some(self.name.clean(cx)),
2084 attrs: self.attrs.clean(cx),
2085 source: self.whence.clean(cx),
2086 def_id: ast_util::local_def(self.id.clone()),
2087 visibility: self.vis.clean(cx),
2088 stability: self.stab.clean(cx),
2089 inner: TypedefItem(Typedef {
2090 type_: self.ty.clean(cx),
2091 generics: self.gen.clean(cx),
62682a34 2092 }, false),
1a4d82fc
JJ
2093 }
2094 }
2095}
2096
85aaf69f 2097#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
2098pub struct BareFunctionDecl {
2099 pub unsafety: ast::Unsafety,
2100 pub generics: Generics,
2101 pub decl: FnDecl,
2102 pub abi: String,
2103}
2104
2105impl Clean<BareFunctionDecl> for ast::BareFnTy {
2106 fn clean(&self, cx: &DocContext) -> BareFunctionDecl {
2107 BareFunctionDecl {
2108 unsafety: self.unsafety,
2109 generics: Generics {
2110 lifetimes: self.lifetimes.clean(cx),
2111 type_params: Vec::new(),
2112 where_predicates: Vec::new()
2113 },
2114 decl: self.decl.clean(cx),
2115 abi: self.abi.to_string(),
2116 }
2117 }
2118}
2119
85aaf69f 2120#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
2121pub struct Static {
2122 pub type_: Type,
2123 pub mutability: Mutability,
2124 /// It's useful to have the value of a static documented, but I have no
2125 /// desire to represent expressions (that'd basically be all of the AST,
2126 /// which is huge!). So, have a string.
2127 pub expr: String,
2128}
2129
2130impl Clean<Item> for doctree::Static {
2131 fn clean(&self, cx: &DocContext) -> Item {
2132 debug!("cleaning static {}: {:?}", self.name.clean(cx), self);
2133 Item {
2134 name: Some(self.name.clean(cx)),
2135 attrs: self.attrs.clean(cx),
2136 source: self.whence.clean(cx),
2137 def_id: ast_util::local_def(self.id),
2138 visibility: self.vis.clean(cx),
2139 stability: self.stab.clean(cx),
2140 inner: StaticItem(Static {
2141 type_: self.type_.clean(cx),
2142 mutability: self.mutability.clean(cx),
2143 expr: self.expr.span.to_src(cx),
2144 }),
2145 }
2146 }
2147}
2148
85aaf69f 2149#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
2150pub struct Constant {
2151 pub type_: Type,
2152 pub expr: String,
2153}
2154
2155impl Clean<Item> for doctree::Constant {
2156 fn clean(&self, cx: &DocContext) -> Item {
2157 Item {
2158 name: Some(self.name.clean(cx)),
2159 attrs: self.attrs.clean(cx),
2160 source: self.whence.clean(cx),
2161 def_id: ast_util::local_def(self.id),
2162 visibility: self.vis.clean(cx),
2163 stability: self.stab.clean(cx),
2164 inner: ConstantItem(Constant {
2165 type_: self.type_.clean(cx),
2166 expr: self.expr.span.to_src(cx),
2167 }),
2168 }
2169 }
2170}
2171
85aaf69f 2172#[derive(Debug, Clone, RustcEncodable, RustcDecodable, PartialEq, Copy)]
1a4d82fc
JJ
2173pub enum Mutability {
2174 Mutable,
2175 Immutable,
2176}
2177
2178impl Clean<Mutability> for ast::Mutability {
2179 fn clean(&self, _: &DocContext) -> Mutability {
2180 match self {
2181 &ast::MutMutable => Mutable,
2182 &ast::MutImmutable => Immutable,
2183 }
2184 }
2185}
2186
85aaf69f
SL
2187#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Copy, Debug)]
2188pub enum ImplPolarity {
2189 Positive,
2190 Negative,
2191}
2192
2193impl Clean<ImplPolarity> for ast::ImplPolarity {
2194 fn clean(&self, _: &DocContext) -> ImplPolarity {
2195 match self {
2196 &ast::ImplPolarity::Positive => ImplPolarity::Positive,
2197 &ast::ImplPolarity::Negative => ImplPolarity::Negative,
2198 }
2199 }
2200}
2201
2202#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc 2203pub struct Impl {
c34b1796 2204 pub unsafety: ast::Unsafety,
1a4d82fc
JJ
2205 pub generics: Generics,
2206 pub trait_: Option<Type>,
2207 pub for_: Type,
2208 pub items: Vec<Item>,
2209 pub derived: bool,
85aaf69f 2210 pub polarity: Option<ImplPolarity>,
1a4d82fc
JJ
2211}
2212
2213fn detect_derived<M: AttrMetaMethods>(attrs: &[M]) -> bool {
2214 attr::contains_name(attrs, "automatically_derived")
2215}
2216
d9579d0f
AL
2217impl Clean<Vec<Item>> for doctree::Impl {
2218 fn clean(&self, cx: &DocContext) -> Vec<Item> {
2219 let mut ret = Vec::new();
2220 let trait_ = self.trait_.clean(cx);
2221 let items = self.items.clean(cx);
2222
2223 // If this impl block is an implementation of the Deref trait, then we
2224 // need to try inlining the target's inherent impl blocks as well.
2225 if let Some(ResolvedPath { did, .. }) = trait_ {
2226 if Some(did) == cx.deref_trait_did.get() {
2227 build_deref_target_impls(cx, &items, &mut ret);
2228 }
2229 }
2230
2231 ret.push(Item {
1a4d82fc
JJ
2232 name: None,
2233 attrs: self.attrs.clean(cx),
2234 source: self.whence.clean(cx),
2235 def_id: ast_util::local_def(self.id),
2236 visibility: self.vis.clean(cx),
2237 stability: self.stab.clean(cx),
2238 inner: ImplItem(Impl {
c34b1796 2239 unsafety: self.unsafety,
1a4d82fc 2240 generics: self.generics.clean(cx),
d9579d0f 2241 trait_: trait_,
1a4d82fc 2242 for_: self.for_.clean(cx),
d9579d0f 2243 items: items,
85aaf69f
SL
2244 derived: detect_derived(&self.attrs),
2245 polarity: Some(self.polarity.clean(cx)),
1a4d82fc 2246 }),
d9579d0f
AL
2247 });
2248 return ret;
2249 }
2250}
2251
2252fn build_deref_target_impls(cx: &DocContext,
2253 items: &[Item],
2254 ret: &mut Vec<Item>) {
2255 let tcx = match cx.tcx_opt() {
2256 Some(t) => t,
2257 None => return,
2258 };
2259
2260 for item in items {
2261 let target = match item.inner {
62682a34 2262 TypedefItem(ref t, true) => &t.type_,
d9579d0f
AL
2263 _ => continue,
2264 };
2265 let primitive = match *target {
2266 ResolvedPath { did, .. } if ast_util::is_local(did) => continue,
2267 ResolvedPath { did, .. } => {
2268 ret.extend(inline::build_impls(cx, tcx, did));
2269 continue
2270 }
2271 _ => match target.primitive_type() {
2272 Some(prim) => prim,
2273 None => continue,
2274 }
2275 };
2276 let did = match primitive {
2277 Isize => tcx.lang_items.isize_impl(),
2278 I8 => tcx.lang_items.i8_impl(),
2279 I16 => tcx.lang_items.i16_impl(),
2280 I32 => tcx.lang_items.i32_impl(),
2281 I64 => tcx.lang_items.i64_impl(),
2282 Usize => tcx.lang_items.usize_impl(),
2283 U8 => tcx.lang_items.u8_impl(),
2284 U16 => tcx.lang_items.u16_impl(),
2285 U32 => tcx.lang_items.u32_impl(),
2286 U64 => tcx.lang_items.u64_impl(),
2287 F32 => tcx.lang_items.f32_impl(),
2288 F64 => tcx.lang_items.f64_impl(),
2289 Char => tcx.lang_items.char_impl(),
2290 Bool => None,
2291 Str => tcx.lang_items.str_impl(),
2292 Slice => tcx.lang_items.slice_impl(),
2293 Array => tcx.lang_items.slice_impl(),
2294 PrimitiveTuple => None,
2295 PrimitiveRawPointer => tcx.lang_items.const_ptr_impl(),
2296 };
2297 if let Some(did) = did {
2298 if !ast_util::is_local(did) {
2299 inline::build_impl(cx, tcx, did, ret);
2300 }
1a4d82fc
JJ
2301 }
2302 }
2303}
2304
c34b1796
AL
2305#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2306pub struct DefaultImpl {
2307 pub unsafety: ast::Unsafety,
2308 pub trait_: Type,
2309}
2310
2311impl Clean<Item> for doctree::DefaultImpl {
2312 fn clean(&self, cx: &DocContext) -> Item {
2313 Item {
2314 name: None,
2315 attrs: self.attrs.clean(cx),
2316 source: self.whence.clean(cx),
2317 def_id: ast_util::local_def(self.id),
2318 visibility: Some(ast::Public),
2319 stability: None,
2320 inner: DefaultImplItem(DefaultImpl {
2321 unsafety: self.unsafety,
2322 trait_: self.trait_.clean(cx),
2323 }),
2324 }
2325 }
2326}
2327
85aaf69f
SL
2328impl Clean<Item> for doctree::ExternCrate {
2329 fn clean(&self, cx: &DocContext) -> Item {
2330 Item {
2331 name: None,
2332 attrs: self.attrs.clean(cx),
2333 source: self.whence.clean(cx),
2334 def_id: ast_util::local_def(0),
2335 visibility: self.vis.clean(cx),
2336 stability: None,
2337 inner: ExternCrateItem(self.name.clean(cx), self.path.clone())
2338 }
2339 }
1a4d82fc
JJ
2340}
2341
85aaf69f 2342impl Clean<Vec<Item>> for doctree::Import {
1a4d82fc
JJ
2343 fn clean(&self, cx: &DocContext) -> Vec<Item> {
2344 // We consider inlining the documentation of `pub use` statements, but we
2345 // forcefully don't inline if this is not public or if the
2346 // #[doc(no_inline)] attribute is present.
2347 let denied = self.vis != ast::Public || self.attrs.iter().any(|a| {
c34b1796 2348 &a.name()[..] == "doc" && match a.meta_item_list() {
1a4d82fc
JJ
2349 Some(l) => attr::contains_name(l, "no_inline"),
2350 None => false,
2351 }
2352 });
85aaf69f
SL
2353 let (mut ret, inner) = match self.node {
2354 ast::ViewPathGlob(ref p) => {
2355 (vec![], GlobImport(resolve_use_source(cx, p.clean(cx), self.id)))
1a4d82fc 2356 }
85aaf69f
SL
2357 ast::ViewPathList(ref p, ref list) => {
2358 // Attempt to inline all reexported items, but be sure
2359 // to keep any non-inlineable reexports so they can be
2360 // listed in the documentation.
2361 let mut ret = vec![];
2362 let remaining = if !denied {
2363 let mut remaining = vec![];
2364 for path in list {
2365 match inline::try_inline(cx, path.node.id(), None) {
2366 Some(items) => {
62682a34 2367 ret.extend(items);
85aaf69f
SL
2368 }
2369 None => {
2370 remaining.push(path.clean(cx));
1a4d82fc 2371 }
1a4d82fc
JJ
2372 }
2373 }
85aaf69f
SL
2374 remaining
2375 } else {
2376 list.clean(cx)
1a4d82fc 2377 };
85aaf69f
SL
2378 if remaining.is_empty() {
2379 return ret;
2380 }
2381 (ret, ImportList(resolve_use_source(cx, p.clean(cx), self.id),
2382 remaining))
1a4d82fc 2383 }
85aaf69f
SL
2384 ast::ViewPathSimple(i, ref p) => {
2385 if !denied {
2386 match inline::try_inline(cx, self.id, Some(i)) {
2387 Some(items) => return items,
2388 None => {}
2389 }
2390 }
2391 (vec![], SimpleImport(i.clean(cx),
2392 resolve_use_source(cx, p.clean(cx), self.id)))
1a4d82fc 2393 }
85aaf69f
SL
2394 };
2395 ret.push(Item {
2396 name: None,
2397 attrs: self.attrs.clean(cx),
2398 source: self.whence.clean(cx),
2399 def_id: ast_util::local_def(0),
2400 visibility: self.vis.clean(cx),
2401 stability: None,
2402 inner: ImportItem(inner)
2403 });
2404 ret
1a4d82fc
JJ
2405 }
2406}
2407
85aaf69f
SL
2408#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2409pub enum Import {
1a4d82fc
JJ
2410 // use source as str;
2411 SimpleImport(String, ImportSource),
2412 // use source::*;
2413 GlobImport(ImportSource),
2414 // use source::{a, b, c};
2415 ImportList(ImportSource, Vec<ViewListIdent>),
2416}
2417
85aaf69f 2418#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
2419pub struct ImportSource {
2420 pub path: Path,
2421 pub did: Option<ast::DefId>,
2422}
2423
85aaf69f 2424#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
2425pub struct ViewListIdent {
2426 pub name: String,
2427 pub source: Option<ast::DefId>,
2428}
2429
2430impl Clean<ViewListIdent> for ast::PathListItem {
2431 fn clean(&self, cx: &DocContext) -> ViewListIdent {
2432 match self.node {
2433 ast::PathListIdent { id, name } => ViewListIdent {
2434 name: name.clean(cx),
2435 source: resolve_def(cx, id)
2436 },
2437 ast::PathListMod { id } => ViewListIdent {
85aaf69f 2438 name: "self".to_string(),
1a4d82fc
JJ
2439 source: resolve_def(cx, id)
2440 }
2441 }
2442 }
2443}
2444
2445impl Clean<Vec<Item>> for ast::ForeignMod {
2446 fn clean(&self, cx: &DocContext) -> Vec<Item> {
9346a6ac
AL
2447 let mut items = self.items.clean(cx);
2448 for item in &mut items {
2449 match item.inner {
2450 ForeignFunctionItem(ref mut f) => f.abi = self.abi,
2451 _ => {}
2452 }
2453 }
2454 items
1a4d82fc
JJ
2455 }
2456}
2457
2458impl Clean<Item> for ast::ForeignItem {
2459 fn clean(&self, cx: &DocContext) -> Item {
2460 let inner = match self.node {
2461 ast::ForeignItemFn(ref decl, ref generics) => {
2462 ForeignFunctionItem(Function {
2463 decl: decl.clean(cx),
2464 generics: generics.clean(cx),
2465 unsafety: ast::Unsafety::Unsafe,
9346a6ac 2466 abi: abi::Rust,
62682a34 2467 constness: ast::Constness::NotConst,
1a4d82fc
JJ
2468 })
2469 }
2470 ast::ForeignItemStatic(ref ty, mutbl) => {
2471 ForeignStaticItem(Static {
2472 type_: ty.clean(cx),
2473 mutability: if mutbl {Mutable} else {Immutable},
2474 expr: "".to_string(),
2475 })
2476 }
2477 };
2478 Item {
2479 name: Some(self.ident.clean(cx)),
2480 attrs: self.attrs.clean(cx),
2481 source: self.span.clean(cx),
2482 def_id: ast_util::local_def(self.id),
2483 visibility: self.vis.clean(cx),
2484 stability: get_stability(cx, ast_util::local_def(self.id)),
2485 inner: inner,
2486 }
2487 }
2488}
2489
2490// Utilities
2491
2492trait ToSource {
2493 fn to_src(&self, cx: &DocContext) -> String;
2494}
2495
2496impl ToSource for syntax::codemap::Span {
2497 fn to_src(&self, cx: &DocContext) -> String {
2498 debug!("converting span {:?} to snippet", self.clean(cx));
2499 let sn = match cx.sess().codemap().span_to_snippet(*self) {
85aaf69f
SL
2500 Ok(x) => x.to_string(),
2501 Err(_) => "".to_string()
1a4d82fc
JJ
2502 };
2503 debug!("got snippet {}", sn);
2504 sn
2505 }
2506}
2507
2508fn lit_to_string(lit: &ast::Lit) -> String {
2509 match lit.node {
85aaf69f 2510 ast::LitStr(ref st, _) => st.to_string(),
1a4d82fc
JJ
2511 ast::LitBinary(ref data) => format!("{:?}", data),
2512 ast::LitByte(b) => {
62682a34 2513 let mut res = String::from("b'");
1a4d82fc
JJ
2514 for c in (b as char).escape_default() {
2515 res.push(c);
2516 }
2517 res.push('\'');
2518 res
2519 },
2520 ast::LitChar(c) => format!("'{}'", c),
2521 ast::LitInt(i, _t) => i.to_string(),
85aaf69f
SL
2522 ast::LitFloat(ref f, _t) => f.to_string(),
2523 ast::LitFloatUnsuffixed(ref f) => f.to_string(),
1a4d82fc
JJ
2524 ast::LitBool(b) => b.to_string(),
2525 }
2526}
2527
2528fn name_from_pat(p: &ast::Pat) -> String {
2529 use syntax::ast::*;
2530 debug!("Trying to get a name from pattern: {:?}", p);
2531
2532 match p.node {
2533 PatWild(PatWildSingle) => "_".to_string(),
2534 PatWild(PatWildMulti) => "..".to_string(),
c1a9b12d 2535 PatIdent(_, ref p, _) => p.node.to_string(),
1a4d82fc 2536 PatEnum(ref p, _) => path_to_string(p),
d9579d0f
AL
2537 PatQPath(..) => panic!("tried to get argument name from PatQPath, \
2538 which is not allowed in function arguments"),
1a4d82fc
JJ
2539 PatStruct(ref name, ref fields, etc) => {
2540 format!("{} {{ {}{} }}", path_to_string(name),
2541 fields.iter().map(|&Spanned { node: ref fp, .. }|
c1a9b12d
SL
2542 format!("{}: {}", fp.ident, name_from_pat(&*fp.pat)))
2543 .collect::<Vec<String>>().join(", "),
1a4d82fc
JJ
2544 if etc { ", ..." } else { "" }
2545 )
2546 },
2547 PatTup(ref elts) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
c1a9b12d 2548 .collect::<Vec<String>>().join(", ")),
1a4d82fc
JJ
2549 PatBox(ref p) => name_from_pat(&**p),
2550 PatRegion(ref p, _) => name_from_pat(&**p),
2551 PatLit(..) => {
2552 warn!("tried to get argument name from PatLit, \
2553 which is silly in function arguments");
2554 "()".to_string()
2555 },
2556 PatRange(..) => panic!("tried to get argument name from PatRange, \
2557 which is not allowed in function arguments"),
2558 PatVec(ref begin, ref mid, ref end) => {
2559 let begin = begin.iter().map(|p| name_from_pat(&**p));
2560 let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter();
2561 let end = end.iter().map(|p| name_from_pat(&**p));
c1a9b12d 2562 format!("[{}]", begin.chain(mid).chain(end).collect::<Vec<_>>().join(", "))
1a4d82fc
JJ
2563 },
2564 PatMac(..) => {
2565 warn!("can't document the name of a function argument \
2566 produced by a pattern macro");
2567 "(argument produced by macro)".to_string()
2568 }
2569 }
2570}
2571
2572/// Given a Type, resolve it using the def_map
2573fn resolve_type(cx: &DocContext,
2574 path: Path,
2575 id: ast::NodeId) -> Type {
2576 let tcx = match cx.tcx_opt() {
2577 Some(tcx) => tcx,
2578 // If we're extracting tests, this return value doesn't matter.
2579 None => return Primitive(Bool),
2580 };
2581 debug!("searching for {} in defmap", id);
2582 let def = match tcx.def_map.borrow().get(&id) {
c34b1796 2583 Some(k) => k.full_def(),
1a4d82fc
JJ
2584 None => panic!("unresolved id not in defmap")
2585 };
2586
62682a34 2587 let is_generic = match def {
1a4d82fc
JJ
2588 def::DefPrimTy(p) => match p {
2589 ast::TyStr => return Primitive(Str),
2590 ast::TyBool => return Primitive(Bool),
2591 ast::TyChar => return Primitive(Char),
c34b1796 2592 ast::TyInt(ast::TyIs) => return Primitive(Isize),
1a4d82fc
JJ
2593 ast::TyInt(ast::TyI8) => return Primitive(I8),
2594 ast::TyInt(ast::TyI16) => return Primitive(I16),
2595 ast::TyInt(ast::TyI32) => return Primitive(I32),
2596 ast::TyInt(ast::TyI64) => return Primitive(I64),
c34b1796 2597 ast::TyUint(ast::TyUs) => return Primitive(Usize),
1a4d82fc
JJ
2598 ast::TyUint(ast::TyU8) => return Primitive(U8),
2599 ast::TyUint(ast::TyU16) => return Primitive(U16),
2600 ast::TyUint(ast::TyU32) => return Primitive(U32),
2601 ast::TyUint(ast::TyU64) => return Primitive(U64),
2602 ast::TyFloat(ast::TyF32) => return Primitive(F32),
2603 ast::TyFloat(ast::TyF64) => return Primitive(F64),
2604 },
62682a34 2605 def::DefSelfTy(..) if path.segments.len() == 1 => {
c1a9b12d 2606 return Generic(special_idents::type_self.name.to_string());
c34b1796 2607 }
62682a34
SL
2608 def::DefSelfTy(..) | def::DefTyParam(..) => true,
2609 _ => false,
1a4d82fc
JJ
2610 };
2611 let did = register_def(&*cx, def);
62682a34 2612 ResolvedPath { path: path, typarams: None, did: did, is_generic: is_generic }
1a4d82fc
JJ
2613}
2614
2615fn register_def(cx: &DocContext, def: def::Def) -> ast::DefId {
2616 let (did, kind) = match def {
2617 def::DefFn(i, _) => (i, TypeFunction),
2618 def::DefTy(i, false) => (i, TypeTypedef),
2619 def::DefTy(i, true) => (i, TypeEnum),
2620 def::DefTrait(i) => (i, TypeTrait),
2621 def::DefStruct(i) => (i, TypeStruct),
2622 def::DefMod(i) => (i, TypeModule),
2623 def::DefStatic(i, _) => (i, TypeStatic),
2624 def::DefVariant(i, _, _) => (i, TypeEnum),
2625 _ => return def.def_id()
2626 };
2627 if ast_util::is_local(did) { return did }
2628 let tcx = match cx.tcx_opt() {
2629 Some(tcx) => tcx,
2630 None => return did
2631 };
2632 inline::record_extern_fqn(cx, did, kind);
2633 if let TypeTrait = kind {
2634 let t = inline::build_external_trait(cx, tcx, did);
2635 cx.external_traits.borrow_mut().as_mut().unwrap().insert(did, t);
2636 }
2637 return did;
2638}
2639
2640fn resolve_use_source(cx: &DocContext, path: Path, id: ast::NodeId) -> ImportSource {
2641 ImportSource {
2642 path: path,
2643 did: resolve_def(cx, id),
2644 }
2645}
2646
2647fn resolve_def(cx: &DocContext, id: ast::NodeId) -> Option<ast::DefId> {
2648 cx.tcx_opt().and_then(|tcx| {
c34b1796 2649 tcx.def_map.borrow().get(&id).map(|d| register_def(cx, d.full_def()))
1a4d82fc
JJ
2650 })
2651}
2652
85aaf69f 2653#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
2654pub struct Macro {
2655 pub source: String,
d9579d0f 2656 pub imported_from: Option<String>,
1a4d82fc
JJ
2657}
2658
2659impl Clean<Item> for doctree::Macro {
2660 fn clean(&self, cx: &DocContext) -> Item {
2661 Item {
2662 name: Some(format!("{}!", self.name.clean(cx))),
2663 attrs: self.attrs.clean(cx),
2664 source: self.whence.clean(cx),
2665 visibility: ast::Public.clean(cx),
2666 stability: self.stab.clean(cx),
2667 def_id: ast_util::local_def(self.id),
2668 inner: MacroItem(Macro {
2669 source: self.whence.to_src(cx),
d9579d0f 2670 imported_from: self.imported_from.clean(cx),
1a4d82fc
JJ
2671 }),
2672 }
2673 }
2674}
2675
85aaf69f 2676#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
2677pub struct Stability {
2678 pub level: attr::StabilityLevel,
85aaf69f
SL
2679 pub feature: String,
2680 pub since: String,
2681 pub deprecated_since: String,
2682 pub reason: String
1a4d82fc
JJ
2683}
2684
2685impl Clean<Stability> for attr::Stability {
2686 fn clean(&self, _: &DocContext) -> Stability {
2687 Stability {
2688 level: self.level,
85aaf69f
SL
2689 feature: self.feature.to_string(),
2690 since: self.since.as_ref().map_or("".to_string(),
2691 |interned| interned.to_string()),
2692 deprecated_since: self.deprecated_since.as_ref().map_or("".to_string(),
2693 |istr| istr.to_string()),
2694 reason: self.reason.as_ref().map_or("".to_string(),
2695 |interned| interned.to_string()),
1a4d82fc
JJ
2696 }
2697 }
2698}
2699
62682a34
SL
2700impl<'a> Clean<Stability> for &'a attr::Stability {
2701 fn clean(&self, _: &DocContext) -> Stability {
2702 Stability {
2703 level: self.level,
2704 feature: self.feature.to_string(),
2705 since: self.since.as_ref().map_or("".to_string(),
2706 |interned| interned.to_string()),
2707 deprecated_since: self.deprecated_since.as_ref().map_or("".to_string(),
2708 |istr| istr.to_string()),
2709 reason: self.reason.as_ref().map_or("".to_string(),
2710 |interned| interned.to_string()),
2711 }
2712 }
2713}
2714
d9579d0f
AL
2715impl<'tcx> Clean<Item> for ty::AssociatedConst<'tcx> {
2716 fn clean(&self, cx: &DocContext) -> Item {
2717 Item {
2718 source: DUMMY_SP.clean(cx),
2719 name: Some(self.name.clean(cx)),
2720 attrs: Vec::new(),
2721 inner: AssociatedConstItem(self.ty.clean(cx), None),
2722 visibility: None,
2723 def_id: self.def_id,
2724 stability: None,
2725 }
2726 }
2727}
2728
62682a34 2729impl<'tcx> Clean<Item> for ty::AssociatedType<'tcx> {
1a4d82fc 2730 fn clean(&self, cx: &DocContext) -> Item {
9346a6ac 2731 let my_name = self.name.clean(cx);
62682a34
SL
2732
2733 let mut bounds = if let ty::TraitContainer(did) = self.container {
2734 // When loading a cross-crate associated type, the bounds for this type
2735 // are actually located on the trait/impl itself, so we need to load
2736 // all of the generics from there and then look for bounds that are
2737 // applied to this associated type in question.
c1a9b12d
SL
2738 let def = cx.tcx().lookup_trait_def(did);
2739 let predicates = cx.tcx().lookup_predicates(did);
62682a34
SL
2740 let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx);
2741 generics.where_predicates.iter().filter_map(|pred| {
2742 let (name, self_type, trait_, bounds) = match *pred {
2743 WherePredicate::BoundPredicate {
2744 ty: QPath { ref name, ref self_type, ref trait_ },
2745 ref bounds
2746 } => (name, self_type, trait_, bounds),
2747 _ => return None,
2748 };
2749 if *name != my_name { return None }
2750 match **trait_ {
2751 ResolvedPath { did, .. } if did == self.container.id() => {}
2752 _ => return None,
2753 }
2754 match **self_type {
2755 Generic(ref s) if *s == "Self" => {}
2756 _ => return None,
2757 }
2758 Some(bounds)
2759 }).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>()
2760 } else {
2761 vec![]
2762 };
9346a6ac
AL
2763
2764 // Our Sized/?Sized bound didn't get handled when creating the generics
2765 // because we didn't actually get our whole set of bounds until just now
2766 // (some of them may have come from the trait). If we do have a sized
2767 // bound, we remove it, and if we don't then we add the `?Sized` bound
2768 // at the end.
2769 match bounds.iter().position(|b| b.is_sized_bound(cx)) {
2770 Some(i) => { bounds.remove(i); }
2771 None => bounds.push(TyParamBound::maybe_sized(cx)),
2772 }
2773
1a4d82fc
JJ
2774 Item {
2775 source: DUMMY_SP.clean(cx),
2776 name: Some(self.name.clean(cx)),
9346a6ac 2777 attrs: inline::load_attrs(cx, cx.tcx(), self.def_id),
62682a34 2778 inner: AssociatedTypeItem(bounds, self.ty.clean(cx)),
9346a6ac 2779 visibility: self.vis.clean(cx),
1a4d82fc 2780 def_id: self.def_id,
9346a6ac 2781 stability: stability::lookup(cx.tcx(), self.def_id).clean(cx),
1a4d82fc
JJ
2782 }
2783 }
2784}
2785
9346a6ac
AL
2786impl<'a> Clean<Typedef> for (ty::TypeScheme<'a>, ty::GenericPredicates<'a>,
2787 ParamSpace) {
85aaf69f
SL
2788 fn clean(&self, cx: &DocContext) -> Typedef {
2789 let (ref ty_scheme, ref predicates, ps) = *self;
2790 Typedef {
2791 type_: ty_scheme.ty.clean(cx),
2792 generics: (&ty_scheme.generics, predicates, ps).clean(cx)
2793 }
2794 }
2795}
2796
1a4d82fc
JJ
2797fn lang_struct(cx: &DocContext, did: Option<ast::DefId>,
2798 t: ty::Ty, name: &str,
2799 fallback: fn(Box<Type>) -> Type) -> Type {
2800 let did = match did {
2801 Some(did) => did,
2802 None => return fallback(box t.clean(cx)),
2803 };
2804 let fqn = csearch::get_item_path(cx.tcx(), did);
2805 let fqn: Vec<String> = fqn.into_iter().map(|i| {
2806 i.to_string()
2807 }).collect();
2808 cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, TypeStruct));
2809 ResolvedPath {
2810 typarams: None,
2811 did: did,
2812 path: Path {
2813 global: false,
2814 segments: vec![PathSegment {
2815 name: name.to_string(),
2816 params: PathParameters::AngleBracketed {
2817 lifetimes: vec![],
2818 types: vec![t.clean(cx)],
2819 bindings: vec![]
2820 }
2821 }],
2822 },
62682a34 2823 is_generic: false,
1a4d82fc
JJ
2824 }
2825}
2826
2827/// An equality constraint on an associated type, e.g. `A=Bar` in `Foo<A=Bar>`
85aaf69f 2828#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Debug)]
1a4d82fc
JJ
2829pub struct TypeBinding {
2830 pub name: String,
2831 pub ty: Type
2832}
2833
2834impl Clean<TypeBinding> for ast::TypeBinding {
2835 fn clean(&self, cx: &DocContext) -> TypeBinding {
2836 TypeBinding {
2837 name: self.ident.clean(cx),
2838 ty: self.ty.clean(cx)
2839 }
2840 }
2841}