]>
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 | //! Rust AST Visitor. Extracts useful information and massages it into a form | |
12 | //! usable for clean | |
13 | ||
9346a6ac | 14 | use std::mem; |
1a4d82fc JJ |
15 | |
16 | use syntax::abi; | |
17 | use syntax::ast; | |
b039eaaf | 18 | use syntax::attr; |
8bb4bdeb | 19 | use syntax::tokenstream::TokenStream; |
3157f602 | 20 | use syntax_pos::Span; |
1a4d82fc | 21 | |
54a0048b | 22 | use rustc::hir::map as hir_map; |
a7813a04 | 23 | use rustc::hir::def::Def; |
9e0c209e | 24 | use rustc::hir::def_id::LOCAL_CRATE; |
476ff2be | 25 | use rustc::middle::cstore::LoadedMacro; |
a7813a04 | 26 | use rustc::middle::privacy::AccessLevel; |
476ff2be | 27 | use rustc::util::nodemap::FxHashSet; |
1a4d82fc | 28 | |
54a0048b | 29 | use rustc::hir; |
e9174d1e | 30 | |
1a4d82fc | 31 | use core; |
476ff2be | 32 | use clean::{self, AttributesExt, NestedAttributesExt}; |
1a4d82fc JJ |
33 | use doctree::*; |
34 | ||
35 | // looks to me like the first two of these are actually | |
36 | // output parameters, maybe only mutated once; perhaps | |
37 | // better simply to have the visit method return a tuple | |
38 | // containing them? | |
39 | ||
40 | // also, is there some reason that this doesn't use the 'visit' | |
41 | // framework from syntax? | |
42 | ||
43 | pub struct RustdocVisitor<'a, 'tcx: 'a> { | |
44 | pub module: Module, | |
9cc50fc6 | 45 | pub attrs: hir::HirVec<ast::Attribute>, |
62682a34 | 46 | pub cx: &'a core::DocContext<'a, 'tcx>, |
476ff2be SL |
47 | view_item_stack: FxHashSet<ast::NodeId>, |
48 | inlining: bool, | |
49 | /// Is the current module and all of its parents public? | |
50 | inside_public_path: bool, | |
1a4d82fc JJ |
51 | } |
52 | ||
53 | impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { | |
a7813a04 | 54 | pub fn new(cx: &'a core::DocContext<'a, 'tcx>) -> RustdocVisitor<'a, 'tcx> { |
1a4d82fc | 55 | // If the root is reexported, terminate all recursion. |
476ff2be | 56 | let mut stack = FxHashSet(); |
1a4d82fc JJ |
57 | stack.insert(ast::CRATE_NODE_ID); |
58 | RustdocVisitor { | |
59 | module: Module::new(None), | |
9cc50fc6 | 60 | attrs: hir::HirVec::new(), |
1a4d82fc | 61 | cx: cx, |
1a4d82fc | 62 | view_item_stack: stack, |
476ff2be SL |
63 | inlining: false, |
64 | inside_public_path: true, | |
1a4d82fc JJ |
65 | } |
66 | } | |
67 | ||
68 | fn stability(&self, id: ast::NodeId) -> Option<attr::Stability> { | |
32a655c1 | 69 | self.cx.tcx.hir.opt_local_def_id(id) |
476ff2be | 70 | .and_then(|def_id| self.cx.tcx.lookup_stability(def_id)).cloned() |
1a4d82fc JJ |
71 | } |
72 | ||
9cc50fc6 | 73 | fn deprecation(&self, id: ast::NodeId) -> Option<attr::Deprecation> { |
32a655c1 | 74 | self.cx.tcx.hir.opt_local_def_id(id) |
476ff2be | 75 | .and_then(|def_id| self.cx.tcx.lookup_deprecation(def_id)) |
9cc50fc6 SL |
76 | } |
77 | ||
e9174d1e | 78 | pub fn visit(&mut self, krate: &hir::Crate) { |
1a4d82fc JJ |
79 | self.attrs = krate.attrs.clone(); |
80 | ||
81 | self.module = self.visit_mod_contents(krate.span, | |
82 | krate.attrs.clone(), | |
e9174d1e | 83 | hir::Public, |
1a4d82fc JJ |
84 | ast::CRATE_NODE_ID, |
85 | &krate.module, | |
86 | None); | |
87 | // attach the crate's exported macros to the top-level module: | |
476ff2be | 88 | let macro_exports: Vec<_> = |
32a655c1 | 89 | krate.exported_macros.iter().map(|def| self.visit_local_macro(def)).collect(); |
476ff2be | 90 | self.module.macros.extend(macro_exports); |
1a4d82fc JJ |
91 | self.module.is_crate = true; |
92 | } | |
93 | ||
b039eaaf SL |
94 | pub fn visit_variant_data(&mut self, item: &hir::Item, |
95 | name: ast::Name, sd: &hir::VariantData, | |
e9174d1e | 96 | generics: &hir::Generics) -> Struct { |
1a4d82fc JJ |
97 | debug!("Visiting struct"); |
98 | let struct_type = struct_type_from_def(&*sd); | |
99 | Struct { | |
100 | id: item.id, | |
101 | struct_type: struct_type, | |
102 | name: name, | |
54a0048b | 103 | vis: item.vis.clone(), |
1a4d82fc | 104 | stab: self.stability(item.id), |
9cc50fc6 | 105 | depr: self.deprecation(item.id), |
1a4d82fc JJ |
106 | attrs: item.attrs.clone(), |
107 | generics: generics.clone(), | |
b039eaaf | 108 | fields: sd.fields().iter().cloned().collect(), |
1a4d82fc JJ |
109 | whence: item.span |
110 | } | |
111 | } | |
112 | ||
9e0c209e SL |
113 | pub fn visit_union_data(&mut self, item: &hir::Item, |
114 | name: ast::Name, sd: &hir::VariantData, | |
115 | generics: &hir::Generics) -> Union { | |
116 | debug!("Visiting union"); | |
117 | let struct_type = struct_type_from_def(&*sd); | |
118 | Union { | |
119 | id: item.id, | |
120 | struct_type: struct_type, | |
121 | name: name, | |
122 | vis: item.vis.clone(), | |
123 | stab: self.stability(item.id), | |
124 | depr: self.deprecation(item.id), | |
125 | attrs: item.attrs.clone(), | |
126 | generics: generics.clone(), | |
127 | fields: sd.fields().iter().cloned().collect(), | |
128 | whence: item.span | |
129 | } | |
130 | } | |
131 | ||
e9174d1e | 132 | pub fn visit_enum_def(&mut self, it: &hir::Item, |
b039eaaf | 133 | name: ast::Name, def: &hir::EnumDef, |
e9174d1e | 134 | params: &hir::Generics) -> Enum { |
1a4d82fc JJ |
135 | debug!("Visiting enum"); |
136 | Enum { | |
137 | name: name, | |
138 | variants: def.variants.iter().map(|v| Variant { | |
139 | name: v.node.name, | |
140 | attrs: v.node.attrs.clone(), | |
b039eaaf | 141 | stab: self.stability(v.node.data.id()), |
9cc50fc6 | 142 | depr: self.deprecation(v.node.data.id()), |
b039eaaf | 143 | def: v.node.data.clone(), |
1a4d82fc JJ |
144 | whence: v.span, |
145 | }).collect(), | |
54a0048b | 146 | vis: it.vis.clone(), |
1a4d82fc | 147 | stab: self.stability(it.id), |
9cc50fc6 | 148 | depr: self.deprecation(it.id), |
1a4d82fc JJ |
149 | generics: params.clone(), |
150 | attrs: it.attrs.clone(), | |
151 | id: it.id, | |
152 | whence: it.span, | |
153 | } | |
154 | } | |
155 | ||
e9174d1e | 156 | pub fn visit_fn(&mut self, item: &hir::Item, |
b039eaaf | 157 | name: ast::Name, fd: &hir::FnDecl, |
e9174d1e SL |
158 | unsafety: &hir::Unsafety, |
159 | constness: hir::Constness, | |
62682a34 | 160 | abi: &abi::Abi, |
32a655c1 SL |
161 | gen: &hir::Generics, |
162 | body: hir::BodyId) -> Function { | |
1a4d82fc JJ |
163 | debug!("Visiting fn"); |
164 | Function { | |
165 | id: item.id, | |
54a0048b | 166 | vis: item.vis.clone(), |
1a4d82fc | 167 | stab: self.stability(item.id), |
9cc50fc6 | 168 | depr: self.deprecation(item.id), |
1a4d82fc JJ |
169 | attrs: item.attrs.clone(), |
170 | decl: fd.clone(), | |
171 | name: name, | |
172 | whence: item.span, | |
173 | generics: gen.clone(), | |
174 | unsafety: *unsafety, | |
62682a34 | 175 | constness: constness, |
9346a6ac | 176 | abi: *abi, |
32a655c1 | 177 | body: body, |
1a4d82fc JJ |
178 | } |
179 | } | |
180 | ||
9cc50fc6 | 181 | pub fn visit_mod_contents(&mut self, span: Span, attrs: hir::HirVec<ast::Attribute>, |
e9174d1e SL |
182 | vis: hir::Visibility, id: ast::NodeId, |
183 | m: &hir::Mod, | |
b039eaaf | 184 | name: Option<ast::Name>) -> Module { |
1a4d82fc | 185 | let mut om = Module::new(name); |
1a4d82fc JJ |
186 | om.where_outer = span; |
187 | om.where_inner = m.inner; | |
188 | om.attrs = attrs; | |
54a0048b | 189 | om.vis = vis.clone(); |
1a4d82fc | 190 | om.stab = self.stability(id); |
9cc50fc6 | 191 | om.depr = self.deprecation(id); |
1a4d82fc | 192 | om.id = id; |
476ff2be SL |
193 | // Keep track of if there were any private modules in the path. |
194 | let orig_inside_public_path = self.inside_public_path; | |
195 | self.inside_public_path &= vis == hir::Public; | |
92a42be0 | 196 | for i in &m.item_ids { |
32a655c1 | 197 | let item = self.cx.tcx.hir.expect_item(i.id); |
92a42be0 | 198 | self.visit_item(item, None, &mut om); |
1a4d82fc | 199 | } |
476ff2be SL |
200 | self.inside_public_path = orig_inside_public_path; |
201 | if let Some(exports) = self.cx.export_map.get(&id) { | |
202 | for export in exports { | |
8bb4bdeb | 203 | if let Def::Macro(def_id, ..) = export.def { |
476ff2be SL |
204 | if def_id.krate == LOCAL_CRATE { |
205 | continue // These are `krate.exported_macros`, handled in `self.visit()`. | |
206 | } | |
32a655c1 | 207 | let imported_from = self.cx.sess().cstore.original_crate_name(def_id.krate); |
476ff2be | 208 | let def = match self.cx.sess().cstore.load_macro(def_id, self.cx.sess()) { |
8bb4bdeb | 209 | LoadedMacro::MacroDef(macro_def) => macro_def, |
476ff2be SL |
210 | // FIXME(jseyfried): document proc macro reexports |
211 | LoadedMacro::ProcMacro(..) => continue, | |
212 | }; | |
213 | ||
8bb4bdeb XL |
214 | let matchers = if let ast::ItemKind::MacroDef(ref tokens) = def.node { |
215 | let tts: Vec<_> = TokenStream::from(tokens.clone()).into_trees().collect(); | |
216 | tts.chunks(4).map(|arm| arm[0].span()).collect() | |
217 | } else { | |
218 | unreachable!() | |
219 | }; | |
476ff2be | 220 | om.macros.push(Macro { |
32a655c1 | 221 | def_id: def_id, |
476ff2be SL |
222 | attrs: def.attrs.clone().into(), |
223 | name: def.ident.name, | |
224 | whence: def.span, | |
225 | matchers: matchers, | |
226 | stab: self.stability(def.id), | |
227 | depr: self.deprecation(def.id), | |
32a655c1 | 228 | imported_from: Some(imported_from), |
476ff2be | 229 | }) |
1a4d82fc JJ |
230 | } |
231 | } | |
232 | } | |
476ff2be | 233 | om |
1a4d82fc JJ |
234 | } |
235 | ||
54a0048b SL |
236 | /// Tries to resolve the target of a `pub use` statement and inlines the |
237 | /// target if it is defined locally and would not be documented otherwise, | |
238 | /// or when it is specifically requested with `please_inline`. | |
239 | /// (the latter is the case when the import is marked `doc(inline)`) | |
240 | /// | |
241 | /// Cross-crate inlining occurs later on during crate cleaning | |
242 | /// and follows different rules. | |
243 | /// | |
244 | /// Returns true if the target has been inlined. | |
476ff2be SL |
245 | fn maybe_inline_local(&mut self, |
246 | id: ast::NodeId, | |
247 | def: Def, | |
248 | renamed: Option<ast::Name>, | |
249 | glob: bool, | |
250 | om: &mut Module, | |
251 | please_inline: bool) -> bool { | |
54a0048b SL |
252 | |
253 | fn inherits_doc_hidden(cx: &core::DocContext, mut node: ast::NodeId) -> bool { | |
32a655c1 | 254 | while let Some(id) = cx.tcx.hir.get_enclosing_scope(node) { |
54a0048b | 255 | node = id; |
32a655c1 | 256 | if cx.tcx.hir.attrs(node).lists("doc").has_word("hidden") { |
54a0048b SL |
257 | return true; |
258 | } | |
259 | if node == ast::CRATE_NODE_ID { | |
260 | break; | |
261 | } | |
262 | } | |
263 | false | |
264 | } | |
265 | ||
476ff2be SL |
266 | let tcx = self.cx.tcx; |
267 | if def == Def::Err { | |
268 | return false; | |
269 | } | |
a7813a04 | 270 | let def_did = def.def_id(); |
54a0048b | 271 | |
32a655c1 | 272 | let use_attrs = tcx.hir.attrs(id); |
3157f602 | 273 | // Don't inline doc(hidden) imports so they can be stripped at a later stage. |
476ff2be SL |
274 | let is_no_inline = use_attrs.lists("doc").has_word("no_inline") || |
275 | use_attrs.lists("doc").has_word("hidden"); | |
a7813a04 XL |
276 | |
277 | // For cross-crate impl inlining we need to know whether items are | |
278 | // reachable in documentation - a previously nonreachable item can be | |
279 | // made reachable by cross-crate inlining which we're checking here. | |
280 | // (this is done here because we need to know this upfront) | |
3157f602 | 281 | if !def_did.is_local() && !is_no_inline { |
476ff2be SL |
282 | let attrs = clean::inline::load_attrs(self.cx, def_did); |
283 | let self_is_hidden = attrs.lists("doc").has_word("hidden"); | |
3157f602 | 284 | match def { |
a7813a04 XL |
285 | Def::Trait(did) | |
286 | Def::Struct(did) | | |
9e0c209e | 287 | Def::Union(did) | |
a7813a04 XL |
288 | Def::Enum(did) | |
289 | Def::TyAlias(did) if !self_is_hidden => { | |
290 | self.cx.access_levels.borrow_mut().map.insert(did, AccessLevel::Public); | |
291 | }, | |
292 | Def::Mod(did) => if !self_is_hidden { | |
293 | ::visit_lib::LibEmbargoVisitor::new(self.cx).visit_mod(did); | |
294 | }, | |
295 | _ => {}, | |
296 | } | |
297 | return false | |
298 | } | |
299 | ||
32a655c1 | 300 | let def_node_id = match tcx.hir.as_local_node_id(def_did) { |
a7813a04 XL |
301 | Some(n) => n, None => return false |
302 | }; | |
54a0048b | 303 | |
a7813a04 | 304 | let is_private = !self.cx.access_levels.borrow().is_public(def_did); |
54a0048b | 305 | let is_hidden = inherits_doc_hidden(self.cx, def_node_id); |
54a0048b SL |
306 | |
307 | // Only inline if requested or if the item would otherwise be stripped | |
308 | if (!please_inline && !is_private && !is_hidden) || is_no_inline { | |
1a4d82fc JJ |
309 | return false |
310 | } | |
54a0048b | 311 | |
b039eaaf | 312 | if !self.view_item_stack.insert(def_node_id) { return false } |
1a4d82fc | 313 | |
32a655c1 | 314 | let ret = match tcx.hir.get(def_node_id) { |
e9174d1e | 315 | hir_map::NodeItem(it) => { |
476ff2be | 316 | let prev = mem::replace(&mut self.inlining, true); |
1a4d82fc JJ |
317 | if glob { |
318 | match it.node { | |
e9174d1e | 319 | hir::ItemMod(ref m) => { |
92a42be0 | 320 | for i in &m.item_ids { |
32a655c1 | 321 | let i = self.cx.tcx.hir.expect_item(i.id); |
92a42be0 | 322 | self.visit_item(i, None, om); |
1a4d82fc JJ |
323 | } |
324 | } | |
e9174d1e | 325 | hir::ItemEnum(..) => {} |
1a4d82fc JJ |
326 | _ => { panic!("glob not mapped to a module or enum"); } |
327 | } | |
328 | } else { | |
329 | self.visit_item(it, renamed, om); | |
330 | } | |
476ff2be | 331 | self.inlining = prev; |
1a4d82fc JJ |
332 | true |
333 | } | |
334 | _ => false, | |
335 | }; | |
b039eaaf | 336 | self.view_item_stack.remove(&def_node_id); |
c30ab7b3 | 337 | ret |
1a4d82fc JJ |
338 | } |
339 | ||
e9174d1e | 340 | pub fn visit_item(&mut self, item: &hir::Item, |
b039eaaf | 341 | renamed: Option<ast::Name>, om: &mut Module) { |
1a4d82fc | 342 | debug!("Visiting item {:?}", item); |
b039eaaf | 343 | let name = renamed.unwrap_or(item.name); |
1a4d82fc | 344 | match item.node { |
476ff2be SL |
345 | hir::ItemForeignMod(ref fm) => { |
346 | // If inlining we only want to include public functions. | |
347 | om.foreigns.push(if self.inlining { | |
348 | hir::ForeignMod { | |
349 | abi: fm.abi, | |
350 | items: fm.items.iter().filter(|i| i.vis == hir::Public).cloned().collect(), | |
351 | } | |
352 | } else { | |
353 | fm.clone() | |
354 | }); | |
355 | } | |
356 | // If we're inlining, skip private items. | |
357 | _ if self.inlining && item.vis != hir::Public => {} | |
e9174d1e | 358 | hir::ItemExternCrate(ref p) => { |
a7813a04 | 359 | let cstore = &self.cx.sess().cstore; |
85aaf69f | 360 | om.extern_crates.push(ExternCrate { |
a7813a04 | 361 | cnum: cstore.extern_mod_stmt_cnum(item.id) |
9e0c209e | 362 | .unwrap_or(LOCAL_CRATE), |
85aaf69f | 363 | name: name, |
54a0048b SL |
364 | path: p.map(|x|x.to_string()), |
365 | vis: item.vis.clone(), | |
85aaf69f SL |
366 | attrs: item.attrs.clone(), |
367 | whence: item.span, | |
368 | }) | |
369 | } | |
476ff2be SL |
370 | hir::ItemUse(_, hir::UseKind::ListStem) => {} |
371 | hir::ItemUse(ref path, kind) => { | |
372 | let is_glob = kind == hir::UseKind::Glob; | |
373 | ||
374 | // If there was a private module in the current path then don't bother inlining | |
375 | // anything as it will probably be stripped anyway. | |
376 | if item.vis == hir::Public && self.inside_public_path { | |
85aaf69f SL |
377 | let please_inline = item.attrs.iter().any(|item| { |
378 | match item.meta_item_list() { | |
9e0c209e SL |
379 | Some(list) if item.check_name("doc") => { |
380 | list.iter().any(|i| i.check_name("inline")) | |
85aaf69f | 381 | } |
54a0048b | 382 | _ => false, |
85aaf69f SL |
383 | } |
384 | }); | |
476ff2be SL |
385 | let name = if is_glob { None } else { Some(name) }; |
386 | if self.maybe_inline_local(item.id, | |
387 | path.def, | |
388 | name, | |
389 | is_glob, | |
390 | om, | |
391 | please_inline) { | |
392 | return; | |
85aaf69f | 393 | } |
476ff2be SL |
394 | } |
395 | ||
85aaf69f | 396 | om.imports.push(Import { |
476ff2be | 397 | name: name, |
85aaf69f | 398 | id: item.id, |
54a0048b | 399 | vis: item.vis.clone(), |
85aaf69f | 400 | attrs: item.attrs.clone(), |
476ff2be SL |
401 | path: (**path).clone(), |
402 | glob: is_glob, | |
85aaf69f SL |
403 | whence: item.span, |
404 | }); | |
405 | } | |
e9174d1e | 406 | hir::ItemMod(ref m) => { |
1a4d82fc JJ |
407 | om.mods.push(self.visit_mod_contents(item.span, |
408 | item.attrs.clone(), | |
54a0048b | 409 | item.vis.clone(), |
1a4d82fc JJ |
410 | item.id, |
411 | m, | |
412 | Some(name))); | |
413 | }, | |
e9174d1e | 414 | hir::ItemEnum(ref ed, ref gen) => |
1a4d82fc | 415 | om.enums.push(self.visit_enum_def(item, name, ed, gen)), |
e9174d1e | 416 | hir::ItemStruct(ref sd, ref gen) => |
b039eaaf | 417 | om.structs.push(self.visit_variant_data(item, name, sd, gen)), |
9e0c209e SL |
418 | hir::ItemUnion(ref sd, ref gen) => |
419 | om.unions.push(self.visit_union_data(item, name, sd, gen)), | |
32a655c1 | 420 | hir::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, body) => |
62682a34 | 421 | om.fns.push(self.visit_fn(item, name, &**fd, unsafety, |
32a655c1 | 422 | constness, abi, gen, body)), |
e9174d1e | 423 | hir::ItemTy(ref ty, ref gen) => { |
1a4d82fc JJ |
424 | let t = Typedef { |
425 | ty: ty.clone(), | |
426 | gen: gen.clone(), | |
427 | name: name, | |
428 | id: item.id, | |
429 | attrs: item.attrs.clone(), | |
430 | whence: item.span, | |
54a0048b | 431 | vis: item.vis.clone(), |
1a4d82fc | 432 | stab: self.stability(item.id), |
9cc50fc6 | 433 | depr: self.deprecation(item.id), |
1a4d82fc JJ |
434 | }; |
435 | om.typedefs.push(t); | |
436 | }, | |
e9174d1e | 437 | hir::ItemStatic(ref ty, ref mut_, ref exp) => { |
1a4d82fc JJ |
438 | let s = Static { |
439 | type_: ty.clone(), | |
440 | mutability: mut_.clone(), | |
441 | expr: exp.clone(), | |
442 | id: item.id, | |
443 | name: name, | |
444 | attrs: item.attrs.clone(), | |
445 | whence: item.span, | |
54a0048b | 446 | vis: item.vis.clone(), |
1a4d82fc | 447 | stab: self.stability(item.id), |
9cc50fc6 | 448 | depr: self.deprecation(item.id), |
1a4d82fc JJ |
449 | }; |
450 | om.statics.push(s); | |
451 | }, | |
e9174d1e | 452 | hir::ItemConst(ref ty, ref exp) => { |
1a4d82fc JJ |
453 | let s = Constant { |
454 | type_: ty.clone(), | |
455 | expr: exp.clone(), | |
456 | id: item.id, | |
457 | name: name, | |
458 | attrs: item.attrs.clone(), | |
459 | whence: item.span, | |
54a0048b | 460 | vis: item.vis.clone(), |
1a4d82fc | 461 | stab: self.stability(item.id), |
9cc50fc6 | 462 | depr: self.deprecation(item.id), |
1a4d82fc JJ |
463 | }; |
464 | om.constants.push(s); | |
465 | }, | |
32a655c1 SL |
466 | hir::ItemTrait(unsafety, ref gen, ref b, ref item_ids) => { |
467 | let items = item_ids.iter() | |
468 | .map(|ti| self.cx.tcx.hir.trait_item(ti.id).clone()) | |
469 | .collect(); | |
1a4d82fc JJ |
470 | let t = Trait { |
471 | unsafety: unsafety, | |
472 | name: name, | |
32a655c1 | 473 | items: items, |
1a4d82fc | 474 | generics: gen.clone(), |
85aaf69f | 475 | bounds: b.iter().cloned().collect(), |
1a4d82fc JJ |
476 | id: item.id, |
477 | attrs: item.attrs.clone(), | |
478 | whence: item.span, | |
54a0048b | 479 | vis: item.vis.clone(), |
1a4d82fc | 480 | stab: self.stability(item.id), |
9cc50fc6 | 481 | depr: self.deprecation(item.id), |
1a4d82fc JJ |
482 | }; |
483 | om.traits.push(t); | |
484 | }, | |
476ff2be SL |
485 | |
486 | hir::ItemImpl(unsafety, polarity, ref gen, ref tr, ref ty, ref item_ids) => { | |
487 | // Don't duplicate impls when inlining, we'll pick them up | |
488 | // regardless of where they're located. | |
489 | if !self.inlining { | |
490 | let items = item_ids.iter() | |
32a655c1 | 491 | .map(|ii| self.cx.tcx.hir.impl_item(ii.id).clone()) |
476ff2be SL |
492 | .collect(); |
493 | let i = Impl { | |
494 | unsafety: unsafety, | |
495 | polarity: polarity, | |
496 | generics: gen.clone(), | |
497 | trait_: tr.clone(), | |
498 | for_: ty.clone(), | |
499 | items: items, | |
500 | attrs: item.attrs.clone(), | |
501 | id: item.id, | |
502 | whence: item.span, | |
503 | vis: item.vis.clone(), | |
504 | stab: self.stability(item.id), | |
505 | depr: self.deprecation(item.id), | |
506 | }; | |
9346a6ac AL |
507 | om.impls.push(i); |
508 | } | |
1a4d82fc | 509 | }, |
e9174d1e | 510 | hir::ItemDefaultImpl(unsafety, ref trait_ref) => { |
476ff2be SL |
511 | // See comment above about ItemImpl. |
512 | if !self.inlining { | |
513 | let i = DefaultImpl { | |
514 | unsafety: unsafety, | |
515 | trait_: trait_ref.clone(), | |
516 | id: item.id, | |
517 | attrs: item.attrs.clone(), | |
518 | whence: item.span, | |
519 | }; | |
9346a6ac AL |
520 | om.def_traits.push(i); |
521 | } | |
c34b1796 | 522 | } |
1a4d82fc JJ |
523 | } |
524 | } | |
525 | ||
526 | // convert each exported_macro into a doc item | |
32a655c1 | 527 | fn visit_local_macro(&self, def: &hir::MacroDef) -> Macro { |
8bb4bdeb | 528 | let tts = def.body.trees().collect::<Vec<_>>(); |
92a42be0 | 529 | // Extract the spans of all matchers. They represent the "interface" of the macro. |
8bb4bdeb | 530 | let matchers = tts.chunks(4).map(|arm| arm[0].span()).collect(); |
92a42be0 | 531 | |
1a4d82fc | 532 | Macro { |
32a655c1 | 533 | def_id: self.cx.tcx.hir.local_def_id(def.id), |
1a4d82fc | 534 | attrs: def.attrs.clone(), |
b039eaaf | 535 | name: def.name, |
1a4d82fc | 536 | whence: def.span, |
92a42be0 | 537 | matchers: matchers, |
1a4d82fc | 538 | stab: self.stability(def.id), |
9cc50fc6 | 539 | depr: self.deprecation(def.id), |
32a655c1 | 540 | imported_from: None, |
1a4d82fc JJ |
541 | } |
542 | } | |
543 | } |