]>
Commit | Line | Data |
---|---|---|
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 |
14 | pub use self::Type::*; |
15 | pub use self::PrimitiveType::*; | |
16 | pub use self::TypeKind::*; | |
17 | pub use self::StructField::*; | |
18 | pub use self::VariantKind::*; | |
19 | pub use self::Mutability::*; | |
85aaf69f | 20 | pub use self::Import::*; |
1a4d82fc JJ |
21 | pub use self::ItemEnum::*; |
22 | pub use self::Attribute::*; | |
23 | pub use self::TyParamBound::*; | |
24 | pub use self::SelfTy::*; | |
25 | pub use self::FunctionRetTy::*; | |
1a4d82fc JJ |
26 | |
27 | use syntax; | |
85aaf69f | 28 | use syntax::abi; |
1a4d82fc JJ |
29 | use syntax::ast; |
30 | use syntax::ast_util; | |
1a4d82fc JJ |
31 | use syntax::attr; |
32 | use syntax::attr::{AttributeMethods, AttrMetaMethods}; | |
85aaf69f | 33 | use syntax::codemap; |
1a4d82fc JJ |
34 | use syntax::codemap::{DUMMY_SP, Pos, Spanned}; |
35 | use syntax::parse::token::{self, InternedString, special_idents}; | |
36 | use syntax::ptr::P; | |
37 | ||
38 | use rustc_trans::back::link; | |
39 | use rustc::metadata::cstore; | |
40 | use rustc::metadata::csearch; | |
41 | use rustc::metadata::decoder; | |
42 | use rustc::middle::def; | |
43 | use rustc::middle::subst::{self, ParamSpace, VecPerParamSpace}; | |
44 | use rustc::middle::ty; | |
45 | use rustc::middle::stability; | |
1a4d82fc | 46 | |
9346a6ac AL |
47 | use std::collections::HashMap; |
48 | use std::path::PathBuf; | |
1a4d82fc JJ |
49 | use std::rc::Rc; |
50 | use std::u32; | |
1a4d82fc JJ |
51 | |
52 | use core::DocContext; | |
53 | use doctree; | |
54 | use 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 | 58 | pub const SCHEMA_VERSION: &'static str = "0.8.3"; |
1a4d82fc JJ |
59 | |
60 | mod inline; | |
9346a6ac | 61 | mod simplify; |
1a4d82fc JJ |
62 | |
63 | // extract the stability index for a node from tcx, if possible | |
64 | fn 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 | ||
68 | pub trait Clean<T> { | |
69 | fn clean(&self, cx: &DocContext) -> T; | |
70 | } | |
71 | ||
c34b1796 | 72 | impl<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 | ||
78 | impl<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 | ||
84 | impl<T: Clean<U>, U> Clean<U> for P<T> { | |
85 | fn clean(&self, cx: &DocContext) -> U { | |
86 | (**self).clean(cx) | |
87 | } | |
88 | } | |
89 | ||
90 | impl<T: Clean<U>, U> Clean<U> for Rc<T> { | |
91 | fn clean(&self, cx: &DocContext) -> U { | |
92 | (**self).clean(cx) | |
93 | } | |
94 | } | |
95 | ||
96 | impl<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 |
105 | impl<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 |
111 | impl<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 |
118 | pub 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 | ||
127 | impl<'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 |
214 | pub struct ExternalCrate { |
215 | pub name: String, | |
216 | pub attrs: Vec<Attribute>, | |
217 | pub primitives: Vec<PrimitiveType>, | |
218 | } | |
219 | ||
220 | impl 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 |
247 | pub 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 | ||
259 | impl 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 | 339 | pub 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 |
370 | pub struct Module { |
371 | pub items: Vec<Item>, | |
372 | pub is_crate: bool, | |
373 | } | |
374 | ||
375 | impl 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 |
430 | pub enum Attribute { |
431 | Word(String), | |
432 | List(String, Vec<Attribute> ), | |
433 | NameValue(String, String) | |
434 | } | |
435 | ||
436 | impl 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 | ||
450 | impl 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. | |
457 | impl 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 | } |
477 | impl<'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 |
485 | pub struct TyParam { |
486 | pub name: String, | |
487 | pub did: ast::DefId, | |
488 | pub bounds: Vec<TyParamBound>, | |
489 | pub default: Option<Type>, | |
490 | } | |
491 | ||
492 | impl 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 | ||
503 | impl<'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 |
517 | pub enum TyParamBound { |
518 | RegionBound(Lifetime), | |
519 | TraitBound(PolyTrait, ast::TraitBoundModifier) | |
520 | } | |
521 | ||
9346a6ac AL |
522 | impl 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 |
551 | impl 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 |
560 | impl<'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 | ||
580 | fn 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 | |
625 | fn 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 | ||
636 | impl 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 |
673 | impl<'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 |
719 | impl<'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 |
732 | pub struct Lifetime(String); |
733 | ||
734 | impl 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 | ||
746 | impl Clean<Lifetime> for ast::Lifetime { | |
747 | fn clean(&self, _: &DocContext) -> Lifetime { | |
c1a9b12d | 748 | Lifetime(self.name.to_string()) |
1a4d82fc JJ |
749 | } |
750 | } | |
751 | ||
752 | impl Clean<Lifetime> for ast::LifetimeDef { | |
753 | fn clean(&self, _: &DocContext) -> Lifetime { | |
c1a9b12d | 754 | Lifetime(self.lifetime.name.to_string()) |
1a4d82fc JJ |
755 | } |
756 | } | |
757 | ||
758 | impl Clean<Lifetime> for ty::RegionParameterDef { | |
759 | fn clean(&self, _: &DocContext) -> Lifetime { | |
c1a9b12d | 760 | Lifetime(self.name.to_string()) |
1a4d82fc JJ |
761 | } |
762 | } | |
763 | ||
764 | impl 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 |
782 | pub 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 | ||
788 | impl 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 |
812 | impl<'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 | ||
826 | impl<'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 | ||
835 | impl<'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 | ||
845 | impl 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 | ||
855 | impl<'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 | ||
866 | impl<'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 | ||
875 | impl<'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 |
893 | pub struct Generics { |
894 | pub lifetimes: Vec<Lifetime>, | |
895 | pub type_params: Vec<TyParam>, | |
896 | pub where_predicates: Vec<WherePredicate> | |
897 | } | |
898 | ||
899 | impl 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 |
909 | impl<'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 |
979 | pub 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 |
988 | impl 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 |
1014 | pub 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 |
1022 | impl 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 |
1046 | pub enum SelfTy { |
1047 | SelfStatic, | |
1048 | SelfValue, | |
1049 | SelfBorrowed(Option<Lifetime>, Mutability), | |
1050 | SelfExplicit(Type), | |
1051 | } | |
1052 | ||
1053 | impl 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 |
1067 | pub 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 | ||
1075 | impl 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 |
1096 | pub 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 |
1103 | pub struct Arguments { |
1104 | pub values: Vec<Argument>, | |
1105 | } | |
1106 | ||
1107 | impl 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 | ||
1119 | impl<'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 | ||
1128 | impl<'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 |
1156 | pub struct Argument { |
1157 | pub type_: Type, | |
1158 | pub name: String, | |
1159 | pub id: ast::NodeId, | |
1160 | } | |
1161 | ||
1162 | impl 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 |
1173 | pub enum FunctionRetTy { |
1174 | Return(Type), | |
85aaf69f | 1175 | DefaultReturn, |
1a4d82fc JJ |
1176 | NoReturn |
1177 | } | |
1178 | ||
1179 | impl 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 |
1190 | pub 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 | ||
1197 | impl 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 | ||
1216 | impl 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 | ||
1222 | impl 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 |
1231 | impl 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 |
1261 | impl 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 | ||
1300 | impl<'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 | ||
1373 | impl<'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 |
1385 | pub 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 | 1394 | pub 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 |
1439 | pub 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 |
1453 | pub enum TypeKind { |
1454 | TypeEnum, | |
1455 | TypeFunction, | |
1456 | TypeModule, | |
1457 | TypeConst, | |
1458 | TypeStatic, | |
1459 | TypeStruct, | |
1460 | TypeTrait, | |
1461 | TypeVariant, | |
1462 | TypeTypedef, | |
1463 | } | |
1464 | ||
9346a6ac AL |
1465 | impl 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 |
1480 | impl 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 | ||
1563 | impl 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 | ||
1618 | impl<'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 |
1709 | pub enum StructField { |
1710 | HiddenStructField, // inserted later by strip passes | |
1711 | TypedStructField(Type), | |
1712 | } | |
1713 | ||
1714 | impl 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 | 1732 | impl 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 | ||
1759 | pub type Visibility = ast::Visibility; | |
1760 | ||
1761 | impl 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 |
1768 | pub struct Struct { |
1769 | pub struct_type: doctree::StructType, | |
1770 | pub generics: Generics, | |
1771 | pub fields: Vec<Item>, | |
1772 | pub fields_stripped: bool, | |
1773 | } | |
1774 | ||
1775 | impl 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 |
1798 | pub struct VariantStruct { |
1799 | pub struct_type: doctree::StructType, | |
1800 | pub fields: Vec<Item>, | |
1801 | pub fields_stripped: bool, | |
1802 | } | |
1803 | ||
1804 | impl 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 |
1815 | pub struct Enum { |
1816 | pub variants: Vec<Item>, | |
1817 | pub generics: Generics, | |
1818 | pub variants_stripped: bool, | |
1819 | } | |
1820 | ||
1821 | impl 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 |
1840 | pub struct Variant { |
1841 | pub kind: VariantKind, | |
1842 | } | |
1843 | ||
1844 | impl 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 | ||
1860 | impl<'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 |
1908 | pub enum VariantKind { |
1909 | CLikeVariant, | |
1910 | TupleVariant(Vec<Type>), | |
1911 | StructVariant(VariantStruct), | |
1912 | } | |
1913 | ||
1914 | impl 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 |
1930 | pub 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 | ||
1938 | impl 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 | ||
1948 | impl 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 |
1969 | pub struct Path { |
1970 | pub global: bool, | |
1971 | pub segments: Vec<PathSegment>, | |
1972 | } | |
1973 | ||
9346a6ac AL |
1974 | impl 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 |
1990 | impl 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 |
2000 | pub 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 | ||
2012 | impl 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 |
2034 | pub struct PathSegment { |
2035 | pub name: String, | |
2036 | pub params: PathParameters | |
2037 | } | |
2038 | ||
2039 | impl 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 | ||
2048 | fn 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 | ||
2062 | impl Clean<String> for ast::Ident { | |
2063 | fn clean(&self, _: &DocContext) -> String { | |
c1a9b12d | 2064 | self.to_string() |
1a4d82fc JJ |
2065 | } |
2066 | } | |
2067 | ||
2068 | impl 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 |
2075 | pub struct Typedef { |
2076 | pub type_: Type, | |
2077 | pub generics: Generics, | |
2078 | } | |
2079 | ||
2080 | impl 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 |
2098 | pub struct BareFunctionDecl { |
2099 | pub unsafety: ast::Unsafety, | |
2100 | pub generics: Generics, | |
2101 | pub decl: FnDecl, | |
2102 | pub abi: String, | |
2103 | } | |
2104 | ||
2105 | impl 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 |
2121 | pub 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 | ||
2130 | impl 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 |
2150 | pub struct Constant { |
2151 | pub type_: Type, | |
2152 | pub expr: String, | |
2153 | } | |
2154 | ||
2155 | impl 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 |
2173 | pub enum Mutability { |
2174 | Mutable, | |
2175 | Immutable, | |
2176 | } | |
2177 | ||
2178 | impl 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)] |
2188 | pub enum ImplPolarity { | |
2189 | Positive, | |
2190 | Negative, | |
2191 | } | |
2192 | ||
2193 | impl 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 | 2203 | pub 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 | ||
2213 | fn detect_derived<M: AttrMetaMethods>(attrs: &[M]) -> bool { | |
2214 | attr::contains_name(attrs, "automatically_derived") | |
2215 | } | |
2216 | ||
d9579d0f AL |
2217 | impl 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 | ||
2252 | fn 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)] |
2306 | pub struct DefaultImpl { | |
2307 | pub unsafety: ast::Unsafety, | |
2308 | pub trait_: Type, | |
2309 | } | |
2310 | ||
2311 | impl 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 |
2328 | impl 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 | 2342 | impl 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)] |
2409 | pub 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 |
2419 | pub struct ImportSource { |
2420 | pub path: Path, | |
2421 | pub did: Option<ast::DefId>, | |
2422 | } | |
2423 | ||
85aaf69f | 2424 | #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] |
1a4d82fc JJ |
2425 | pub struct ViewListIdent { |
2426 | pub name: String, | |
2427 | pub source: Option<ast::DefId>, | |
2428 | } | |
2429 | ||
2430 | impl 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 | ||
2445 | impl 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 | ||
2458 | impl 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 | ||
2492 | trait ToSource { | |
2493 | fn to_src(&self, cx: &DocContext) -> String; | |
2494 | } | |
2495 | ||
2496 | impl 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 | ||
2508 | fn 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 | ||
2528 | fn 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 | |
2573 | fn 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 | ||
2615 | fn 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 | ||
2640 | fn 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 | ||
2647 | fn 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 |
2654 | pub struct Macro { |
2655 | pub source: String, | |
d9579d0f | 2656 | pub imported_from: Option<String>, |
1a4d82fc JJ |
2657 | } |
2658 | ||
2659 | impl 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 |
2677 | pub 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 | ||
2685 | impl 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 |
2700 | impl<'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 |
2715 | impl<'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 | 2729 | impl<'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 |
2786 | impl<'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 |
2797 | fn 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 |
2829 | pub struct TypeBinding { |
2830 | pub name: String, | |
2831 | pub ty: Type | |
2832 | } | |
2833 | ||
2834 | impl 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 | } |