]>
Commit | Line | Data |
---|---|---|
d9579d0f AL |
1 | // Copyright 2015 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 | ||
041b39d2 | 11 | //! Write the output of rustc's analysis to an implementor of Dump. |
d9579d0f AL |
12 | //! |
13 | //! Dumping the analysis is implemented by walking the AST and getting a bunch of | |
14 | //! info out from all over the place. We use Def IDs to identify objects. The | |
15 | //! tricky part is getting syntactic (span, source text) and semantic (reference | |
16 | //! Def IDs) information for parts of expressions which the compiler has discarded. | |
17 | //! E.g., in a path `foo::bar::baz`, the compiler only keeps a span for the whole | |
18 | //! path and a reference to `baz`, but we want spans and references for all three | |
19 | //! idents. | |
20 | //! | |
21 | //! SpanUtils is used to manipulate spans. In particular, to extract sub-spans | |
22 | //! from spans (e.g., the span for `bar` from the above example path). | |
54a0048b SL |
23 | //! DumpVisitor walks the AST and processes it, and an implementor of Dump |
24 | //! is used for recording the output in a format-agnostic way (see CsvDumper | |
25 | //! for an example). | |
d9579d0f | 26 | |
041b39d2 XL |
27 | use rustc::hir::def::Def as HirDef; |
28 | use rustc::hir::def_id::DefId; | |
29 | use rustc::hir::map::Node; | |
041b39d2 | 30 | use rustc::ty::{self, TyCtxt}; |
3b2f2976 | 31 | use rustc_data_structures::fx::FxHashSet; |
d9579d0f | 32 | |
7cac9316 | 33 | use std::path::Path; |
d9579d0f | 34 | |
abe05a73 | 35 | use syntax::ast::{self, Attribute, NodeId, PatKind, CRATE_NODE_ID}; |
476ff2be SL |
36 | use syntax::parse::token; |
37 | use syntax::symbol::keywords; | |
d9579d0f | 38 | use syntax::visit::{self, Visitor}; |
abe05a73 | 39 | use syntax::print::pprust::{bounds_to_string, generics_to_string, path_to_string, ty_to_string}; |
d9579d0f | 40 | use syntax::ptr::P; |
3157f602 XL |
41 | use syntax::codemap::Spanned; |
42 | use syntax_pos::*; | |
d9579d0f | 43 | |
abe05a73 XL |
44 | use {escape, generated_code, lower_attributes, PathCollector, SaveContext}; |
45 | use json_dumper::{DumpOutput, JsonDumper}; | |
041b39d2 XL |
46 | use span_utils::SpanUtils; |
47 | use sig; | |
d9579d0f | 48 | |
abe05a73 XL |
49 | use rls_data::{CratePreludeData, Def, DefKind, GlobalCrateId, Import, ImportKind, Ref, RefKind, |
50 | Relation, RelationKind, SpanData}; | |
cc61c64b | 51 | |
62682a34 | 52 | macro_rules! down_cast_data { |
54a0048b | 53 | ($id:ident, $kind:ident, $sp:expr) => { |
62682a34 SL |
54 | let $id = if let super::Data::$kind(data) = $id { |
55 | data | |
56 | } else { | |
54a0048b | 57 | span_bug!($sp, "unexpected data kind: {:?}", $id); |
5bcae85e | 58 | }; |
62682a34 SL |
59 | }; |
60 | } | |
d9579d0f | 61 | |
3b2f2976 | 62 | pub struct DumpVisitor<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> { |
d9579d0f | 63 | save_ctxt: SaveContext<'l, 'tcx>, |
a7813a04 | 64 | tcx: TyCtxt<'l, 'tcx, 'tcx>, |
3b2f2976 | 65 | dumper: &'ll mut JsonDumper<O>, |
d9579d0f AL |
66 | |
67 | span: SpanUtils<'l>, | |
d9579d0f | 68 | |
e9174d1e | 69 | cur_scope: NodeId, |
7453a54e SL |
70 | |
71 | // Set of macro definition (callee) spans, and the set | |
72 | // of macro use (callsite) spans. We store these to ensure | |
73 | // we only write one macro def per unique macro definition, and | |
74 | // one macro use per unique callsite span. | |
041b39d2 | 75 | // mac_defs: HashSet<Span>, |
3b2f2976 | 76 | macro_calls: FxHashSet<Span>, |
d9579d0f AL |
77 | } |
78 | ||
3b2f2976 | 79 | impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { |
abe05a73 XL |
80 | pub fn new( |
81 | save_ctxt: SaveContext<'l, 'tcx>, | |
82 | dumper: &'ll mut JsonDumper<O>, | |
83 | ) -> DumpVisitor<'l, 'tcx, 'll, O> { | |
476ff2be | 84 | let span_utils = SpanUtils::new(&save_ctxt.tcx.sess); |
54a0048b | 85 | DumpVisitor { |
476ff2be | 86 | tcx: save_ctxt.tcx, |
3b2f2976 XL |
87 | save_ctxt, |
88 | dumper, | |
62682a34 | 89 | span: span_utils.clone(), |
9e0c209e | 90 | cur_scope: CRATE_NODE_ID, |
041b39d2 | 91 | // mac_defs: HashSet::new(), |
3b2f2976 | 92 | macro_calls: FxHashSet(), |
d9579d0f AL |
93 | } |
94 | } | |
95 | ||
32a655c1 | 96 | fn nest_scope<F>(&mut self, scope_id: NodeId, f: F) |
abe05a73 XL |
97 | where |
98 | F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, O>), | |
d9579d0f AL |
99 | { |
100 | let parent_scope = self.cur_scope; | |
101 | self.cur_scope = scope_id; | |
102 | f(self); | |
103 | self.cur_scope = parent_scope; | |
104 | } | |
105 | ||
32a655c1 | 106 | fn nest_tables<F>(&mut self, item_id: NodeId, f: F) |
abe05a73 XL |
107 | where |
108 | F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, O>), | |
32a655c1 SL |
109 | { |
110 | let item_def_id = self.tcx.hir.local_def_id(item_id); | |
7cac9316 XL |
111 | if self.tcx.has_typeck_tables(item_def_id) { |
112 | let tables = self.tcx.typeck_tables_of(item_def_id); | |
113 | let old_tables = self.save_ctxt.tables; | |
114 | self.save_ctxt.tables = tables; | |
115 | f(self); | |
116 | self.save_ctxt.tables = old_tables; | |
117 | } else { | |
118 | f(self); | |
32a655c1 SL |
119 | } |
120 | } | |
121 | ||
041b39d2 XL |
122 | fn span_from_span(&self, span: Span) -> SpanData { |
123 | self.save_ctxt.span_from_span(span) | |
124 | } | |
125 | ||
d9579d0f | 126 | pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) { |
92a42be0 | 127 | let source_file = self.tcx.sess.local_crate_source_file.as_ref(); |
54a0048b | 128 | let crate_root = source_file.map(|source_file| { |
7cac9316 | 129 | let source_file = Path::new(source_file); |
54a0048b | 130 | match source_file.file_name() { |
92a42be0 SL |
131 | Some(_) => source_file.parent().unwrap().display().to_string(), |
132 | None => source_file.display().to_string(), | |
54a0048b SL |
133 | } |
134 | }); | |
135 | ||
54a0048b | 136 | let data = CratePreludeData { |
abe05a73 XL |
137 | crate_id: GlobalCrateId { |
138 | name: name.into(), | |
139 | disambiguator: self.tcx | |
140 | .sess | |
141 | .local_crate_disambiguator() | |
142 | .to_fingerprint() | |
143 | .as_value(), | |
144 | }, | |
a7813a04 | 145 | crate_root: crate_root.unwrap_or("<no source>".to_owned()), |
041b39d2 XL |
146 | external_crates: self.save_ctxt.get_external_crates(), |
147 | span: self.span_from_span(krate.span), | |
54a0048b | 148 | }; |
d9579d0f | 149 | |
041b39d2 | 150 | self.dumper.crate_prelude(data); |
d9579d0f AL |
151 | } |
152 | ||
153 | // Return all non-empty prefixes of a path. | |
154 | // For each prefix, we return the span for the last segment in the prefix and | |
155 | // a str representation of the entire prefix. | |
156 | fn process_path_prefixes(&self, path: &ast::Path) -> Vec<(Span, String)> { | |
32a655c1 | 157 | let segments = &path.segments[if path.is_global() { 1 } else { 0 }..]; |
d9579d0f | 158 | |
3b2f2976 | 159 | let mut result = Vec::with_capacity(segments.len()); |
d9579d0f | 160 | |
c30ab7b3 | 161 | let mut segs = vec![]; |
3b2f2976 | 162 | for (i, seg) in segments.iter().enumerate() { |
d9579d0f | 163 | segs.push(seg.clone()); |
e9174d1e | 164 | let sub_path = ast::Path { |
3b2f2976 | 165 | span: seg.span, // span for the last segment |
e9174d1e SL |
166 | segments: segs, |
167 | }; | |
32a655c1 | 168 | let qualname = if i == 0 && path.is_global() { |
d9579d0f AL |
169 | format!("::{}", path_to_string(&sub_path)) |
170 | } else { | |
171 | path_to_string(&sub_path) | |
172 | }; | |
3b2f2976 | 173 | result.push((seg.span, qualname)); |
d9579d0f AL |
174 | segs = sub_path.segments; |
175 | } | |
176 | ||
177 | result | |
178 | } | |
179 | ||
32a655c1 | 180 | fn write_sub_paths(&mut self, path: &ast::Path) { |
d9579d0f | 181 | let sub_paths = self.process_path_prefixes(path); |
041b39d2 XL |
182 | for (span, _) in sub_paths { |
183 | let span = self.span_from_span(span); | |
184 | self.dumper.dump_ref(Ref { | |
185 | kind: RefKind::Mod, | |
186 | span, | |
187 | ref_id: ::null_id(), | |
188 | }); | |
d9579d0f AL |
189 | } |
190 | } | |
191 | ||
192 | // As write_sub_paths, but does not process the last ident in the path (assuming it | |
193 | // will be processed elsewhere). See note on write_sub_paths about global. | |
32a655c1 | 194 | fn write_sub_paths_truncated(&mut self, path: &ast::Path) { |
d9579d0f AL |
195 | let sub_paths = self.process_path_prefixes(path); |
196 | let len = sub_paths.len(); | |
197 | if len <= 1 { | |
198 | return; | |
199 | } | |
200 | ||
041b39d2 XL |
201 | for (span, _) in sub_paths.into_iter().take(len - 1) { |
202 | let span = self.span_from_span(span); | |
203 | self.dumper.dump_ref(Ref { | |
204 | kind: RefKind::Mod, | |
205 | span, | |
206 | ref_id: ::null_id(), | |
207 | }); | |
d9579d0f AL |
208 | } |
209 | } | |
210 | ||
211 | // As write_sub_paths, but expects a path of the form module_path::trait::method | |
212 | // Where trait could actually be a struct too. | |
213 | fn write_sub_path_trait_truncated(&mut self, path: &ast::Path) { | |
214 | let sub_paths = self.process_path_prefixes(path); | |
215 | let len = sub_paths.len(); | |
216 | if len <= 1 { | |
217 | return; | |
218 | } | |
abe05a73 | 219 | let sub_paths = &sub_paths[..(len - 1)]; |
d9579d0f AL |
220 | |
221 | // write the trait part of the sub-path | |
abe05a73 | 222 | let (ref span, _) = sub_paths[len - 2]; |
041b39d2 XL |
223 | let span = self.span_from_span(*span); |
224 | self.dumper.dump_ref(Ref { | |
225 | kind: RefKind::Type, | |
226 | ref_id: ::null_id(), | |
227 | span, | |
228 | }); | |
d9579d0f AL |
229 | |
230 | // write the other sub-paths | |
231 | if len <= 2 { | |
232 | return; | |
233 | } | |
abe05a73 | 234 | let sub_paths = &sub_paths[..len - 2]; |
041b39d2 XL |
235 | for &(ref span, _) in sub_paths { |
236 | let span = self.span_from_span(*span); | |
237 | self.dumper.dump_ref(Ref { | |
238 | kind: RefKind::Mod, | |
239 | span, | |
240 | ref_id: ::null_id(), | |
241 | }); | |
d9579d0f AL |
242 | } |
243 | } | |
244 | ||
c30ab7b3 | 245 | fn lookup_def_id(&self, ref_id: NodeId) -> Option<DefId> { |
476ff2be | 246 | match self.save_ctxt.get_path_def(ref_id) { |
041b39d2 | 247 | HirDef::PrimTy(..) | HirDef::SelfTy(..) | HirDef::Err => None, |
476ff2be SL |
248 | def => Some(def.def_id()), |
249 | } | |
d9579d0f AL |
250 | } |
251 | ||
abe05a73 XL |
252 | fn process_def_kind( |
253 | &mut self, | |
254 | ref_id: NodeId, | |
255 | span: Span, | |
256 | sub_span: Option<Span>, | |
257 | def_id: DefId, | |
258 | ) { | |
54a0048b SL |
259 | if self.span.filter_generated(sub_span, span) { |
260 | return; | |
261 | } | |
262 | ||
476ff2be | 263 | let def = self.save_ctxt.get_path_def(ref_id); |
d9579d0f | 264 | match def { |
041b39d2 XL |
265 | HirDef::Mod(_) => { |
266 | let span = self.span_from_span(sub_span.expect("No span found for mod ref")); | |
267 | self.dumper.dump_ref(Ref { | |
268 | kind: RefKind::Mod, | |
269 | span, | |
270 | ref_id: ::id_from_def_id(def_id), | |
271 | }); | |
54a0048b | 272 | } |
041b39d2 XL |
273 | HirDef::Struct(..) | |
274 | HirDef::Variant(..) | | |
275 | HirDef::Union(..) | | |
276 | HirDef::Enum(..) | | |
277 | HirDef::TyAlias(..) | | |
abe05a73 | 278 | HirDef::TyForeign(..) | |
041b39d2 XL |
279 | HirDef::Trait(_) => { |
280 | let span = self.span_from_span(sub_span.expect("No span found for type ref")); | |
281 | self.dumper.dump_ref(Ref { | |
282 | kind: RefKind::Type, | |
283 | span, | |
284 | ref_id: ::id_from_def_id(def_id), | |
285 | }); | |
54a0048b | 286 | } |
041b39d2 XL |
287 | HirDef::Static(..) | |
288 | HirDef::Const(..) | | |
289 | HirDef::StructCtor(..) | | |
290 | HirDef::VariantCtor(..) => { | |
291 | let span = self.span_from_span(sub_span.expect("No span found for var ref")); | |
292 | self.dumper.dump_ref(Ref { | |
293 | kind: RefKind::Variable, | |
294 | span, | |
295 | ref_id: ::id_from_def_id(def_id), | |
296 | }); | |
54a0048b | 297 | } |
041b39d2 XL |
298 | HirDef::Fn(..) => { |
299 | let span = self.span_from_span(sub_span.expect("No span found for fn ref")); | |
300 | self.dumper.dump_ref(Ref { | |
301 | kind: RefKind::Function, | |
302 | span, | |
303 | ref_id: ::id_from_def_id(def_id), | |
304 | }); | |
54a0048b | 305 | } |
8bb4bdeb XL |
306 | // With macros 2.0, we can legitimately get a ref to a macro, but |
307 | // we don't handle it properly for now (FIXME). | |
041b39d2 XL |
308 | HirDef::Macro(..) => {} |
309 | HirDef::Local(..) | | |
310 | HirDef::Upvar(..) | | |
311 | HirDef::SelfTy(..) | | |
312 | HirDef::Label(_) | | |
313 | HirDef::TyParam(..) | | |
314 | HirDef::Method(..) | | |
315 | HirDef::AssociatedTy(..) | | |
316 | HirDef::AssociatedConst(..) | | |
317 | HirDef::PrimTy(_) | | |
318 | HirDef::GlobalAsm(_) | | |
319 | HirDef::Err => { | |
abe05a73 | 320 | span_bug!(span, "process_def_kind for unexpected item: {:?}", def); |
e9174d1e | 321 | } |
d9579d0f AL |
322 | } |
323 | } | |
324 | ||
476ff2be | 325 | fn process_formals(&mut self, formals: &'l [ast::Arg], qualname: &str) { |
d9579d0f AL |
326 | for arg in formals { |
327 | self.visit_pat(&arg.pat); | |
328 | let mut collector = PathCollector::new(); | |
329 | collector.visit_pat(&arg.pat); | |
330 | let span_utils = self.span.clone(); | |
abe05a73 XL |
331 | |
332 | for (id, i, sp, ..) in collector.collected_idents { | |
3b2f2976 XL |
333 | let hir_id = self.tcx.hir.node_to_hir_id(id); |
334 | let typ = match self.save_ctxt.tables.node_id_to_type_opt(hir_id) { | |
476ff2be SL |
335 | Some(s) => s.to_string(), |
336 | None => continue, | |
337 | }; | |
abe05a73 XL |
338 | let sub_span = span_utils.span_for_last_ident(sp); |
339 | if !self.span.filter_generated(sub_span, sp) { | |
041b39d2 XL |
340 | let id = ::id_from_node_id(id, &self.save_ctxt); |
341 | let span = self.span_from_span(sub_span.expect("No span found for variable")); | |
342 | ||
abe05a73 XL |
343 | self.dumper.dump_def( |
344 | false, | |
345 | Def { | |
346 | kind: DefKind::Local, | |
347 | id, | |
348 | span, | |
349 | name: i.to_string(), | |
350 | qualname: format!("{}::{}", qualname, i.to_string()), | |
351 | value: typ, | |
352 | parent: None, | |
353 | children: vec![], | |
354 | decl_id: None, | |
355 | docs: String::new(), | |
356 | sig: None, | |
357 | attributes: vec![], | |
358 | }, | |
359 | ); | |
54a0048b | 360 | } |
d9579d0f AL |
361 | } |
362 | } | |
363 | } | |
364 | ||
abe05a73 XL |
365 | fn process_method( |
366 | &mut self, | |
367 | sig: &'l ast::MethodSig, | |
368 | body: Option<&'l ast::Block>, | |
369 | id: ast::NodeId, | |
370 | name: ast::Ident, | |
371 | generics: &'l ast::Generics, | |
372 | vis: ast::Visibility, | |
373 | span: Span, | |
374 | ) { | |
c1a9b12d | 375 | debug!("process_method: {}:{}", id, name); |
d9579d0f | 376 | |
041b39d2 | 377 | if let Some(mut method_data) = self.save_ctxt.get_method_data(id, name.name, span) { |
abe05a73 | 378 | let sig_str = ::make_signature(&sig.decl, &generics); |
7453a54e | 379 | if body.is_some() { |
abe05a73 XL |
380 | self.nest_tables( |
381 | id, | |
382 | |v| v.process_formals(&sig.decl.inputs, &method_data.qualname), | |
383 | ); | |
7453a54e | 384 | } |
3157f602 | 385 | |
abe05a73 | 386 | self.process_generic_params(&generics, span, &method_data.qualname, id); |
041b39d2 XL |
387 | |
388 | method_data.value = sig_str; | |
abe05a73 XL |
389 | method_data.sig = sig::method_signature(id, name, generics, sig, &self.save_ctxt); |
390 | self.dumper | |
391 | .dump_def(vis == ast::Visibility::Public, method_data); | |
d9579d0f AL |
392 | } |
393 | ||
394 | // walk arg and return types | |
395 | for arg in &sig.decl.inputs { | |
396 | self.visit_ty(&arg.ty); | |
397 | } | |
398 | ||
7453a54e | 399 | if let ast::FunctionRetTy::Ty(ref ret_ty) = sig.decl.output { |
d9579d0f AL |
400 | self.visit_ty(ret_ty); |
401 | } | |
402 | ||
403 | // walk the fn body | |
404 | if let Some(body) = body { | |
32a655c1 | 405 | self.nest_tables(id, |v| v.nest_scope(id, |v| v.visit_block(body))); |
d9579d0f | 406 | } |
d9579d0f AL |
407 | } |
408 | ||
e9174d1e | 409 | fn process_struct_field_def(&mut self, field: &ast::StructField, parent_id: NodeId) { |
62682a34 | 410 | let field_data = self.save_ctxt.get_field_data(field, parent_id); |
041b39d2 | 411 | if let Some(field_data) = field_data { |
abe05a73 XL |
412 | self.dumper |
413 | .dump_def(field.vis == ast::Visibility::Public, field_data); | |
d9579d0f AL |
414 | } |
415 | } | |
416 | ||
417 | // Dump generic params bindings, then visit_generics | |
abe05a73 XL |
418 | fn process_generic_params( |
419 | &mut self, | |
420 | generics: &'l ast::Generics, | |
421 | full_span: Span, | |
422 | prefix: &str, | |
423 | id: NodeId, | |
424 | ) { | |
3b2f2976 XL |
425 | for param in &generics.ty_params { |
426 | let param_ss = param.span; | |
a7813a04 | 427 | let name = escape(self.span.snippet(param_ss)); |
d9579d0f | 428 | // Append $id to name to make sure each one is unique |
abe05a73 | 429 | let qualname = format!("{}::{}${}", prefix, name, id); |
54a0048b | 430 | if !self.span.filter_generated(Some(param_ss), full_span) { |
041b39d2 XL |
431 | let id = ::id_from_node_id(param.id, &self.save_ctxt); |
432 | let span = self.span_from_span(param_ss); | |
433 | ||
abe05a73 XL |
434 | self.dumper.dump_def( |
435 | false, | |
436 | Def { | |
437 | kind: DefKind::Type, | |
438 | id, | |
439 | span, | |
440 | name, | |
441 | qualname, | |
442 | value: String::new(), | |
443 | parent: None, | |
444 | children: vec![], | |
445 | decl_id: None, | |
446 | docs: String::new(), | |
447 | sig: None, | |
448 | attributes: vec![], | |
449 | }, | |
450 | ); | |
54a0048b | 451 | } |
d9579d0f AL |
452 | } |
453 | self.visit_generics(generics); | |
454 | } | |
455 | ||
abe05a73 XL |
456 | fn process_fn( |
457 | &mut self, | |
458 | item: &'l ast::Item, | |
459 | decl: &'l ast::FnDecl, | |
460 | ty_params: &'l ast::Generics, | |
461 | body: &'l ast::Block, | |
462 | ) { | |
7453a54e | 463 | if let Some(fn_data) = self.save_ctxt.get_item_data(item) { |
041b39d2 | 464 | down_cast_data!(fn_data, DefData, item.span); |
abe05a73 XL |
465 | self.nest_tables( |
466 | item.id, | |
467 | |v| v.process_formals(&decl.inputs, &fn_data.qualname), | |
468 | ); | |
7453a54e | 469 | self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id); |
abe05a73 XL |
470 | self.dumper |
471 | .dump_def(item.vis == ast::Visibility::Public, fn_data); | |
7453a54e | 472 | } |
d9579d0f AL |
473 | |
474 | for arg in &decl.inputs { | |
475 | self.visit_ty(&arg.ty); | |
476 | } | |
477 | ||
7453a54e | 478 | if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output { |
d9579d0f AL |
479 | self.visit_ty(&ret_ty); |
480 | } | |
481 | ||
32a655c1 | 482 | self.nest_tables(item.id, |v| v.nest_scope(item.id, |v| v.visit_block(&body))); |
d9579d0f AL |
483 | } |
484 | ||
abe05a73 XL |
485 | fn process_static_or_const_item( |
486 | &mut self, | |
487 | item: &'l ast::Item, | |
488 | typ: &'l ast::Ty, | |
489 | expr: &'l ast::Expr, | |
490 | ) { | |
3b2f2976 XL |
491 | self.nest_tables(item.id, |v| { |
492 | if let Some(var_data) = v.save_ctxt.get_item_data(item) { | |
493 | down_cast_data!(var_data, DefData, item.span); | |
abe05a73 XL |
494 | v.dumper |
495 | .dump_def(item.vis == ast::Visibility::Public, var_data); | |
3b2f2976 XL |
496 | } |
497 | v.visit_ty(&typ); | |
498 | v.visit_expr(expr); | |
499 | }); | |
d9579d0f AL |
500 | } |
501 | ||
abe05a73 XL |
502 | fn process_assoc_const( |
503 | &mut self, | |
504 | id: ast::NodeId, | |
505 | name: ast::Name, | |
506 | span: Span, | |
507 | typ: &'l ast::Ty, | |
508 | expr: Option<&'l ast::Expr>, | |
509 | parent_id: DefId, | |
510 | vis: ast::Visibility, | |
511 | attrs: &'l [Attribute], | |
512 | ) { | |
54a0048b | 513 | let qualname = format!("::{}", self.tcx.node_path_str(id)); |
d9579d0f | 514 | |
b039eaaf | 515 | let sub_span = self.span.sub_span_after_keyword(span, keywords::Const); |
d9579d0f | 516 | |
54a0048b | 517 | if !self.span.filter_generated(sub_span, span) { |
041b39d2 XL |
518 | let sig = sig::assoc_const_signature(id, name, typ, expr, &self.save_ctxt); |
519 | let id = ::id_from_node_id(id, &self.save_ctxt); | |
520 | let span = self.span_from_span(sub_span.expect("No span found for variable")); | |
521 | ||
abe05a73 XL |
522 | self.dumper.dump_def( |
523 | vis == ast::Visibility::Public, | |
524 | Def { | |
525 | kind: DefKind::Const, | |
526 | id, | |
527 | span, | |
528 | name: name.to_string(), | |
529 | qualname, | |
530 | value: ty_to_string(&typ), | |
531 | parent: Some(::id_from_def_id(parent_id)), | |
532 | children: vec![], | |
533 | decl_id: None, | |
534 | docs: self.save_ctxt.docs_for_attrs(attrs), | |
535 | sig, | |
536 | attributes: lower_attributes(attrs.to_owned(), &self.save_ctxt), | |
537 | }, | |
538 | ); | |
54a0048b | 539 | } |
d9579d0f AL |
540 | |
541 | // walk type and init value | |
542 | self.visit_ty(typ); | |
041b39d2 XL |
543 | if let Some(expr) = expr { |
544 | self.visit_expr(expr); | |
545 | } | |
d9579d0f AL |
546 | } |
547 | ||
a7813a04 | 548 | // FIXME tuple structs should generate tuple-specific data. |
abe05a73 XL |
549 | fn process_struct( |
550 | &mut self, | |
551 | item: &'l ast::Item, | |
552 | def: &'l ast::VariantData, | |
553 | ty_params: &'l ast::Generics, | |
554 | ) { | |
555 | debug!("process_struct {:?} {:?}", item, item.span); | |
a7813a04 | 556 | let name = item.ident.to_string(); |
54a0048b | 557 | let qualname = format!("::{}", self.tcx.node_path_str(item.id)); |
d9579d0f | 558 | |
abe05a73 XL |
559 | let (kind, keyword) = match item.node { |
560 | ast::ItemKind::Struct(_, _) => (DefKind::Struct, keywords::Struct), | |
561 | ast::ItemKind::Union(_, _) => (DefKind::Union, keywords::Union), | |
562 | _ => unreachable!(), | |
563 | }; | |
564 | ||
565 | let sub_span = self.span.sub_span_after_keyword(item.span, keyword); | |
566 | let (value, fields) = match item.node { | |
567 | ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) | | |
568 | ast::ItemKind::Union(ast::VariantData::Struct(ref fields, _), _) => { | |
569 | let include_priv_fields = !self.save_ctxt.config.pub_only; | |
570 | let fields_str = fields | |
571 | .iter() | |
572 | .enumerate() | |
573 | .filter_map(|(i, f)| { | |
574 | if include_priv_fields || f.vis == ast::Visibility::Public { | |
575 | f.ident | |
576 | .map(|i| i.to_string()) | |
577 | .or_else(|| Some(i.to_string())) | |
578 | } else { | |
579 | None | |
580 | } | |
581 | }) | |
582 | .collect::<Vec<_>>() | |
583 | .join(", "); | |
584 | let value = format!("{} {{ {} }}", name, fields_str); | |
585 | ( | |
586 | value, | |
587 | fields | |
588 | .iter() | |
589 | .map(|f| ::id_from_node_id(f.id, &self.save_ctxt)) | |
590 | .collect(), | |
591 | ) | |
592 | } | |
593 | _ => (String::new(), vec![]), | |
a7813a04 XL |
594 | }; |
595 | ||
54a0048b | 596 | if !self.span.filter_generated(sub_span, item.span) { |
041b39d2 | 597 | let span = self.span_from_span(sub_span.expect("No span found for struct")); |
abe05a73 XL |
598 | self.dumper.dump_def( |
599 | item.vis == ast::Visibility::Public, | |
600 | Def { | |
601 | kind, | |
602 | id: ::id_from_node_id(item.id, &self.save_ctxt), | |
603 | span, | |
604 | name, | |
605 | qualname: qualname.clone(), | |
606 | value, | |
607 | parent: None, | |
608 | children: fields, | |
609 | decl_id: None, | |
610 | docs: self.save_ctxt.docs_for_attrs(&item.attrs), | |
611 | sig: sig::item_signature(item, &self.save_ctxt), | |
612 | attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt), | |
613 | }, | |
614 | ); | |
54a0048b SL |
615 | } |
616 | ||
b039eaaf | 617 | for field in def.fields() { |
62682a34 | 618 | self.process_struct_field_def(field, item.id); |
54a0048b | 619 | self.visit_ty(&field.ty); |
d9579d0f AL |
620 | } |
621 | ||
62682a34 | 622 | self.process_generic_params(ty_params, item.span, &qualname, item.id); |
d9579d0f AL |
623 | } |
624 | ||
abe05a73 XL |
625 | fn process_enum( |
626 | &mut self, | |
627 | item: &'l ast::Item, | |
628 | enum_definition: &'l ast::EnumDef, | |
629 | ty_params: &'l ast::Generics, | |
630 | ) { | |
62682a34 | 631 | let enum_data = self.save_ctxt.get_item_data(item); |
7453a54e SL |
632 | let enum_data = match enum_data { |
633 | None => return, | |
634 | Some(data) => data, | |
635 | }; | |
041b39d2 | 636 | down_cast_data!(enum_data, DefData, item.span); |
62682a34 | 637 | |
d9579d0f | 638 | for variant in &enum_definition.variants { |
a7813a04 | 639 | let name = variant.node.name.name.to_string(); |
62682a34 | 640 | let mut qualname = enum_data.qualname.clone(); |
d9579d0f | 641 | qualname.push_str("::"); |
a7813a04 | 642 | qualname.push_str(&name); |
b039eaaf | 643 | |
7453a54e | 644 | match variant.node.data { |
a7813a04 | 645 | ast::VariantData::Struct(ref fields, _) => { |
54a0048b | 646 | let sub_span = self.span.span_for_first_ident(variant.span); |
abe05a73 XL |
647 | let fields_str = fields |
648 | .iter() | |
649 | .enumerate() | |
650 | .map(|(i, f)| { | |
651 | f.ident.map(|i| i.to_string()).unwrap_or(i.to_string()) | |
652 | }) | |
653 | .collect::<Vec<_>>() | |
654 | .join(", "); | |
041b39d2 | 655 | let value = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str); |
54a0048b | 656 | if !self.span.filter_generated(sub_span, variant.span) { |
abe05a73 XL |
657 | let span = self |
658 | .span_from_span(sub_span.expect("No span found for struct variant")); | |
041b39d2 XL |
659 | let id = ::id_from_node_id(variant.node.data.id(), &self.save_ctxt); |
660 | let parent = Some(::id_from_node_id(item.id, &self.save_ctxt)); | |
661 | ||
abe05a73 XL |
662 | self.dumper.dump_def( |
663 | item.vis == ast::Visibility::Public, | |
664 | Def { | |
665 | kind: DefKind::StructVariant, | |
666 | id, | |
667 | span, | |
668 | name, | |
669 | qualname, | |
670 | value, | |
671 | parent, | |
672 | children: vec![], | |
673 | decl_id: None, | |
674 | docs: self.save_ctxt.docs_for_attrs(&variant.node.attrs), | |
675 | sig: sig::variant_signature(variant, &self.save_ctxt), | |
676 | attributes: lower_attributes( | |
677 | variant.node.attrs.clone(), | |
678 | &self.save_ctxt, | |
679 | ), | |
680 | }, | |
681 | ); | |
54a0048b | 682 | } |
7453a54e | 683 | } |
a7813a04 | 684 | ref v => { |
54a0048b | 685 | let sub_span = self.span.span_for_first_ident(variant.span); |
041b39d2 | 686 | let mut value = format!("{}::{}", enum_data.name, name); |
a7813a04 | 687 | if let &ast::VariantData::Tuple(ref fields, _) = v { |
041b39d2 | 688 | value.push('('); |
abe05a73 XL |
689 | value.push_str(&fields |
690 | .iter() | |
691 | .map(|f| ty_to_string(&f.ty)) | |
692 | .collect::<Vec<_>>() | |
693 | .join(", ")); | |
041b39d2 | 694 | value.push(')'); |
a7813a04 | 695 | } |
54a0048b | 696 | if !self.span.filter_generated(sub_span, variant.span) { |
041b39d2 XL |
697 | let span = |
698 | self.span_from_span(sub_span.expect("No span found for tuple variant")); | |
699 | let id = ::id_from_node_id(variant.node.data.id(), &self.save_ctxt); | |
700 | let parent = Some(::id_from_node_id(item.id, &self.save_ctxt)); | |
701 | ||
abe05a73 XL |
702 | self.dumper.dump_def( |
703 | item.vis == ast::Visibility::Public, | |
704 | Def { | |
705 | kind: DefKind::TupleVariant, | |
706 | id, | |
707 | span, | |
708 | name, | |
709 | qualname, | |
710 | value, | |
711 | parent, | |
712 | children: vec![], | |
713 | decl_id: None, | |
714 | docs: self.save_ctxt.docs_for_attrs(&variant.node.attrs), | |
715 | sig: sig::variant_signature(variant, &self.save_ctxt), | |
716 | attributes: lower_attributes( | |
717 | variant.node.attrs.clone(), | |
718 | &self.save_ctxt, | |
719 | ), | |
720 | }, | |
721 | ); | |
54a0048b | 722 | } |
7453a54e SL |
723 | } |
724 | } | |
725 | ||
b039eaaf SL |
726 | |
727 | for field in variant.node.data.fields() { | |
728 | self.process_struct_field_def(field, variant.node.data.id()); | |
54a0048b | 729 | self.visit_ty(&field.ty); |
d9579d0f AL |
730 | } |
731 | } | |
041b39d2 | 732 | self.process_generic_params(ty_params, item.span, &enum_data.qualname, item.id); |
abe05a73 XL |
733 | self.dumper |
734 | .dump_def(item.vis == ast::Visibility::Public, enum_data); | |
d9579d0f AL |
735 | } |
736 | ||
abe05a73 XL |
737 | fn process_impl( |
738 | &mut self, | |
739 | item: &'l ast::Item, | |
740 | type_parameters: &'l ast::Generics, | |
741 | trait_ref: &'l Option<ast::TraitRef>, | |
742 | typ: &'l ast::Ty, | |
743 | impl_items: &'l [ast::ImplItem], | |
744 | ) { | |
7453a54e | 745 | if let Some(impl_data) = self.save_ctxt.get_item_data(item) { |
041b39d2 XL |
746 | down_cast_data!(impl_data, RelationData, item.span); |
747 | self.dumper.dump_relation(impl_data); | |
d9579d0f | 748 | } |
8bb4bdeb | 749 | self.visit_ty(&typ); |
32a655c1 | 750 | if let &Some(ref trait_ref) = trait_ref { |
041b39d2 | 751 | self.process_path(trait_ref.ref_id, &trait_ref.path); |
32a655c1 | 752 | } |
d9579d0f AL |
753 | self.process_generic_params(type_parameters, item.span, "", item.id); |
754 | for impl_item in impl_items { | |
32a655c1 | 755 | let map = &self.tcx.hir; |
041b39d2 | 756 | self.process_impl_item(impl_item, map.local_def_id(item.id)); |
d9579d0f AL |
757 | } |
758 | } | |
759 | ||
abe05a73 XL |
760 | fn process_trait( |
761 | &mut self, | |
762 | item: &'l ast::Item, | |
763 | generics: &'l ast::Generics, | |
764 | trait_refs: &'l ast::TyParamBounds, | |
765 | methods: &'l [ast::TraitItem], | |
766 | ) { | |
a7813a04 | 767 | let name = item.ident.to_string(); |
54a0048b | 768 | let qualname = format!("::{}", self.tcx.node_path_str(item.id)); |
a7813a04 XL |
769 | let mut val = name.clone(); |
770 | if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() { | |
771 | val.push_str(&generics_to_string(generics)); | |
772 | } | |
773 | if !trait_refs.is_empty() { | |
774 | val.push_str(": "); | |
775 | val.push_str(&bounds_to_string(trait_refs)); | |
776 | } | |
d9579d0f | 777 | let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait); |
54a0048b | 778 | if !self.span.filter_generated(sub_span, item.span) { |
041b39d2 XL |
779 | let id = ::id_from_node_id(item.id, &self.save_ctxt); |
780 | let span = self.span_from_span(sub_span.expect("No span found for trait")); | |
abe05a73 XL |
781 | let children = methods |
782 | .iter() | |
783 | .map(|i| ::id_from_node_id(i.id, &self.save_ctxt)) | |
784 | .collect(); | |
785 | self.dumper.dump_def( | |
786 | item.vis == ast::Visibility::Public, | |
787 | Def { | |
788 | kind: DefKind::Trait, | |
789 | id, | |
790 | span, | |
791 | name, | |
792 | qualname: qualname.clone(), | |
793 | value: val, | |
794 | parent: None, | |
795 | children, | |
796 | decl_id: None, | |
797 | docs: self.save_ctxt.docs_for_attrs(&item.attrs), | |
798 | sig: sig::item_signature(item, &self.save_ctxt), | |
799 | attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt), | |
800 | }, | |
801 | ); | |
54a0048b | 802 | } |
d9579d0f AL |
803 | |
804 | // super-traits | |
62682a34 | 805 | for super_bound in trait_refs.iter() { |
d9579d0f | 806 | let trait_ref = match *super_bound { |
abe05a73 | 807 | ast::TraitTyParamBound(ref trait_ref, _) => trait_ref, |
d9579d0f AL |
808 | ast::RegionTyParamBound(..) => { |
809 | continue; | |
810 | } | |
811 | }; | |
812 | ||
813 | let trait_ref = &trait_ref.trait_ref; | |
c30ab7b3 | 814 | if let Some(id) = self.lookup_def_id(trait_ref.ref_id) { |
54a0048b SL |
815 | let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span); |
816 | if !self.span.filter_generated(sub_span, trait_ref.path.span) { | |
041b39d2 XL |
817 | let span = self.span_from_span(sub_span.expect("No span found for trait ref")); |
818 | self.dumper.dump_ref(Ref { | |
819 | kind: RefKind::Type, | |
820 | span, | |
821 | ref_id: ::id_from_def_id(id), | |
822 | }); | |
54a0048b SL |
823 | } |
824 | ||
825 | if !self.span.filter_generated(sub_span, trait_ref.path.span) { | |
041b39d2 XL |
826 | let sub_span = self.span_from_span(sub_span.expect("No span for inheritance")); |
827 | self.dumper.dump_relation(Relation { | |
828 | kind: RelationKind::SuperTrait, | |
54a0048b | 829 | span: sub_span, |
041b39d2 XL |
830 | from: ::id_from_def_id(id), |
831 | to: ::id_from_node_id(item.id, &self.save_ctxt), | |
832 | }); | |
e9174d1e | 833 | } |
d9579d0f AL |
834 | } |
835 | } | |
836 | ||
837 | // walk generics and methods | |
62682a34 | 838 | self.process_generic_params(generics, item.span, &qualname, item.id); |
d9579d0f | 839 | for method in methods { |
32a655c1 | 840 | let map = &self.tcx.hir; |
041b39d2 | 841 | self.process_trait_item(method, map.local_def_id(item.id)) |
d9579d0f AL |
842 | } |
843 | } | |
844 | ||
e9174d1e SL |
845 | // `item` is the module in question, represented as an item. |
846 | fn process_mod(&mut self, item: &ast::Item) { | |
7453a54e | 847 | if let Some(mod_data) = self.save_ctxt.get_item_data(item) { |
041b39d2 | 848 | down_cast_data!(mod_data, DefData, item.span); |
abe05a73 XL |
849 | self.dumper |
850 | .dump_def(item.vis == ast::Visibility::Public, mod_data); | |
7453a54e | 851 | } |
d9579d0f AL |
852 | } |
853 | ||
abe05a73 | 854 | fn dump_path_ref(&mut self, id: NodeId, path: &ast::Path) { |
7453a54e | 855 | let path_data = self.save_ctxt.get_path_data(id, path); |
abe05a73 XL |
856 | if let Some(path_data) = path_data { |
857 | self.dumper.dump_ref(path_data); | |
d9579d0f | 858 | } |
abe05a73 | 859 | } |
d9579d0f | 860 | |
abe05a73 XL |
861 | fn process_path(&mut self, id: NodeId, path: &'l ast::Path) { |
862 | debug!("process_path {:?}", path); | |
863 | if generated_code(path.span) { | |
864 | return; | |
865 | } | |
866 | self.dump_path_ref(id, path); | |
867 | ||
868 | // Type parameters | |
869 | for seg in &path.segments { | |
870 | if let Some(ref params) = seg.parameters { | |
871 | match **params { | |
872 | ast::PathParameters::AngleBracketed(ref data) => for t in &data.types { | |
873 | self.visit_ty(t); | |
874 | }, | |
875 | ast::PathParameters::Parenthesized(ref data) => { | |
876 | for t in &data.inputs { | |
877 | self.visit_ty(t); | |
878 | } | |
879 | if let Some(ref t) = data.output { | |
880 | self.visit_ty(t); | |
881 | } | |
882 | } | |
883 | } | |
c1a9b12d | 884 | } |
abe05a73 | 885 | } |
c1a9b12d SL |
886 | |
887 | // Modules or types in the path prefix. | |
476ff2be | 888 | match self.save_ctxt.get_path_def(id) { |
041b39d2 | 889 | HirDef::Method(did) => { |
476ff2be SL |
890 | let ti = self.tcx.associated_item(did); |
891 | if ti.kind == ty::AssociatedKind::Method && ti.method_has_self_argument { | |
892 | self.write_sub_path_trait_truncated(path); | |
d9579d0f AL |
893 | } |
894 | } | |
041b39d2 XL |
895 | HirDef::Fn(..) | |
896 | HirDef::Const(..) | | |
897 | HirDef::Static(..) | | |
898 | HirDef::StructCtor(..) | | |
899 | HirDef::VariantCtor(..) | | |
900 | HirDef::AssociatedConst(..) | | |
901 | HirDef::Local(..) | | |
902 | HirDef::Upvar(..) | | |
903 | HirDef::Struct(..) | | |
904 | HirDef::Union(..) | | |
905 | HirDef::Variant(..) | | |
906 | HirDef::TyAlias(..) | | |
907 | HirDef::AssociatedTy(..) => self.write_sub_paths_truncated(path), | |
e9174d1e | 908 | _ => {} |
d9579d0f AL |
909 | } |
910 | } | |
911 | ||
abe05a73 XL |
912 | fn process_struct_lit( |
913 | &mut self, | |
914 | ex: &'l ast::Expr, | |
915 | path: &'l ast::Path, | |
916 | fields: &'l [ast::Field], | |
917 | variant: &'l ty::VariantDef, | |
918 | base: &'l Option<P<ast::Expr>>, | |
919 | ) { | |
32a655c1 | 920 | self.write_sub_paths_truncated(path); |
d9579d0f | 921 | |
62682a34 | 922 | if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) { |
041b39d2 XL |
923 | down_cast_data!(struct_lit_data, RefData, ex.span); |
924 | if !generated_code(ex.span) { | |
925 | self.dumper.dump_ref(struct_lit_data); | |
54a0048b SL |
926 | } |
927 | ||
62682a34 | 928 | for field in fields { |
abe05a73 | 929 | if let Some(field_data) = self.save_ctxt.get_field_ref_data(field, variant) { |
041b39d2 | 930 | self.dumper.dump_ref(field_data); |
7453a54e | 931 | } |
62682a34 SL |
932 | |
933 | self.visit_expr(&field.expr) | |
934 | } | |
d9579d0f | 935 | } |
62682a34 | 936 | |
b039eaaf | 937 | walk_list!(self, visit_expr, base); |
d9579d0f AL |
938 | } |
939 | ||
abe05a73 XL |
940 | fn process_method_call( |
941 | &mut self, | |
942 | ex: &'l ast::Expr, | |
943 | seg: &'l ast::PathSegment, | |
944 | args: &'l [P<ast::Expr>], | |
945 | ) { | |
946 | debug!("process_method_call {:?} {:?}", ex, ex.span); | |
54a0048b | 947 | if let Some(mcd) = self.save_ctxt.get_expr_data(ex) { |
041b39d2 XL |
948 | down_cast_data!(mcd, RefData, ex.span); |
949 | if !generated_code(ex.span) { | |
950 | self.dumper.dump_ref(mcd); | |
54a0048b | 951 | } |
c1a9b12d | 952 | } |
d9579d0f | 953 | |
abe05a73 XL |
954 | // Explicit types in the turbo-fish. |
955 | if let Some(ref params) = seg.parameters { | |
956 | if let ast::PathParameters::AngleBracketed(ref data) = **params { | |
957 | for t in &data.types { | |
958 | self.visit_ty(t); | |
959 | } | |
960 | } | |
961 | } | |
962 | ||
d9579d0f | 963 | // walk receiver and args |
b039eaaf | 964 | walk_list!(self, visit_expr, args); |
d9579d0f AL |
965 | } |
966 | ||
476ff2be | 967 | fn process_pat(&mut self, p: &'l ast::Pat) { |
d9579d0f | 968 | match p.node { |
32a655c1 SL |
969 | PatKind::Struct(ref _path, ref fields, _) => { |
970 | // FIXME do something with _path? | |
3b2f2976 XL |
971 | let hir_id = self.tcx.hir.node_to_hir_id(p.id); |
972 | let adt = match self.save_ctxt.tables.node_id_to_type_opt(hir_id) { | |
476ff2be SL |
973 | Some(ty) => ty.ty_adt_def().unwrap(), |
974 | None => { | |
975 | visit::walk_pat(self, p); | |
976 | return; | |
977 | } | |
978 | }; | |
979 | let variant = adt.variant_of_def(self.save_ctxt.get_path_def(p.id)); | |
d9579d0f | 980 | |
abe05a73 XL |
981 | for &Spanned { |
982 | node: ref field, | |
983 | span, | |
984 | } in fields | |
985 | { | |
e9174d1e SL |
986 | let sub_span = self.span.span_for_first_ident(span); |
987 | if let Some(f) = variant.find_field_named(field.ident.name) { | |
54a0048b | 988 | if !self.span.filter_generated(sub_span, span) { |
041b39d2 XL |
989 | let span = |
990 | self.span_from_span(sub_span.expect("No span fund for var ref")); | |
991 | self.dumper.dump_ref(Ref { | |
992 | kind: RefKind::Variable, | |
993 | span, | |
994 | ref_id: ::id_from_def_id(f.did), | |
995 | }); | |
54a0048b | 996 | } |
d9579d0f | 997 | } |
e9174d1e | 998 | self.visit_pat(&field.pat); |
d9579d0f AL |
999 | } |
1000 | } | |
e9174d1e | 1001 | _ => visit::walk_pat(self, p), |
d9579d0f AL |
1002 | } |
1003 | } | |
b039eaaf SL |
1004 | |
1005 | ||
476ff2be | 1006 | fn process_var_decl(&mut self, p: &'l ast::Pat, value: String) { |
b039eaaf SL |
1007 | // The local could declare multiple new vars, we must walk the |
1008 | // pattern and collect them all. | |
1009 | let mut collector = PathCollector::new(); | |
1010 | collector.visit_pat(&p); | |
1011 | self.visit_pat(&p); | |
1012 | ||
abe05a73 | 1013 | for (id, i, sp, immut) in collector.collected_idents { |
9e0c209e SL |
1014 | let mut value = match immut { |
1015 | ast::Mutability::Immutable => value.to_string(), | |
1016 | _ => String::new(), | |
b039eaaf | 1017 | }; |
3b2f2976 XL |
1018 | let hir_id = self.tcx.hir.node_to_hir_id(id); |
1019 | let typ = match self.save_ctxt.tables.node_id_to_type_opt(hir_id) { | |
9e0c209e SL |
1020 | Some(typ) => { |
1021 | let typ = typ.to_string(); | |
1022 | if !value.is_empty() { | |
1023 | value.push_str(": "); | |
1024 | } | |
1025 | value.push_str(&typ); | |
1026 | typ | |
1027 | } | |
1028 | None => String::new(), | |
1029 | }; | |
1030 | ||
b039eaaf SL |
1031 | // Get the span only for the name of the variable (I hope the path |
1032 | // is only ever a variable name, but who knows?). | |
abe05a73 | 1033 | let sub_span = self.span.span_for_last_ident(sp); |
b039eaaf | 1034 | // Rust uses the id of the pattern for var lookups, so we'll use it too. |
abe05a73 XL |
1035 | if !self.span.filter_generated(sub_span, sp) { |
1036 | let qualname = format!("{}${}", i.to_string(), id); | |
041b39d2 XL |
1037 | let id = ::id_from_node_id(id, &self.save_ctxt); |
1038 | let span = self.span_from_span(sub_span.expect("No span found for variable")); | |
1039 | ||
abe05a73 XL |
1040 | self.dumper.dump_def( |
1041 | false, | |
1042 | Def { | |
1043 | kind: DefKind::Local, | |
1044 | id, | |
1045 | span, | |
1046 | name: i.to_string(), | |
1047 | qualname, | |
1048 | value: typ, | |
1049 | parent: None, | |
1050 | children: vec![], | |
1051 | decl_id: None, | |
1052 | docs: String::new(), | |
1053 | sig: None, | |
1054 | attributes: vec![], | |
1055 | }, | |
1056 | ); | |
54a0048b | 1057 | } |
b039eaaf SL |
1058 | } |
1059 | } | |
7453a54e SL |
1060 | |
1061 | /// Extract macro use and definition information from the AST node defined | |
1062 | /// by the given NodeId, using the expansion information from the node's | |
1063 | /// span. | |
1064 | /// | |
1065 | /// If the span is not macro-generated, do nothing, else use callee and | |
1066 | /// callsite spans to record macro definition and use data, using the | |
1067 | /// mac_uses and mac_defs sets to prevent multiples. | |
041b39d2 | 1068 | fn process_macro_use(&mut self, span: Span) { |
3b2f2976 XL |
1069 | let source_span = span.source_callsite(); |
1070 | if self.macro_calls.contains(&source_span) { | |
1071 | return; | |
1072 | } | |
1073 | self.macro_calls.insert(source_span); | |
1074 | ||
041b39d2 | 1075 | let data = match self.save_ctxt.get_macro_use_data(span) { |
7453a54e SL |
1076 | None => return, |
1077 | Some(data) => data, | |
1078 | }; | |
041b39d2 | 1079 | |
3b2f2976 XL |
1080 | self.dumper.macro_use(data); |
1081 | ||
041b39d2 XL |
1082 | // FIXME write the macro def |
1083 | // let mut hasher = DefaultHasher::new(); | |
1084 | // data.callee_span.hash(&mut hasher); | |
1085 | // let hash = hasher.finish(); | |
1086 | // let qualname = format!("{}::{}", data.name, hash); | |
7453a54e | 1087 | // Don't write macro definition for imported macros |
041b39d2 XL |
1088 | // if !self.mac_defs.contains(&data.callee_span) |
1089 | // && !data.imported { | |
1090 | // self.mac_defs.insert(data.callee_span); | |
1091 | // if let Some(sub_span) = self.span.span_for_macro_def_name(data.callee_span) { | |
1092 | // self.dumper.macro_data(MacroData { | |
1093 | // span: sub_span, | |
1094 | // name: data.name.clone(), | |
1095 | // qualname: qualname.clone(), | |
1096 | // // FIXME where do macro docs come from? | |
1097 | // docs: String::new(), | |
1098 | // }.lower(self.tcx)); | |
1099 | // } | |
1100 | // } | |
7453a54e | 1101 | } |
9e0c209e | 1102 | |
476ff2be | 1103 | fn process_trait_item(&mut self, trait_item: &'l ast::TraitItem, trait_id: DefId) { |
041b39d2 | 1104 | self.process_macro_use(trait_item.span); |
9e0c209e | 1105 | match trait_item.node { |
041b39d2 | 1106 | ast::TraitItemKind::Const(ref ty, ref expr) => { |
abe05a73 XL |
1107 | self.process_assoc_const( |
1108 | trait_item.id, | |
1109 | trait_item.ident.name, | |
1110 | trait_item.span, | |
1111 | &ty, | |
1112 | expr.as_ref().map(|e| &**e), | |
1113 | trait_id, | |
1114 | ast::Visibility::Public, | |
1115 | &trait_item.attrs, | |
1116 | ); | |
9e0c209e SL |
1117 | } |
1118 | ast::TraitItemKind::Method(ref sig, ref body) => { | |
abe05a73 XL |
1119 | self.process_method( |
1120 | sig, | |
1121 | body.as_ref().map(|x| &**x), | |
1122 | trait_item.id, | |
1123 | trait_item.ident, | |
1124 | &trait_item.generics, | |
1125 | ast::Visibility::Public, | |
1126 | trait_item.span, | |
1127 | ); | |
9e0c209e | 1128 | } |
041b39d2 | 1129 | ast::TraitItemKind::Type(ref bounds, ref default_ty) => { |
cc61c64b XL |
1130 | // FIXME do something with _bounds (for type refs) |
1131 | let name = trait_item.ident.name.to_string(); | |
1132 | let qualname = format!("::{}", self.tcx.node_path_str(trait_item.id)); | |
abe05a73 XL |
1133 | let sub_span = self.span |
1134 | .sub_span_after_keyword(trait_item.span, keywords::Type); | |
cc61c64b XL |
1135 | |
1136 | if !self.span.filter_generated(sub_span, trait_item.span) { | |
041b39d2 XL |
1137 | let span = self.span_from_span(sub_span.expect("No span found for assoc type")); |
1138 | let id = ::id_from_node_id(trait_item.id, &self.save_ctxt); | |
1139 | ||
abe05a73 XL |
1140 | self.dumper.dump_def( |
1141 | true, | |
1142 | Def { | |
1143 | kind: DefKind::Type, | |
1144 | id, | |
1145 | span, | |
1146 | name, | |
1147 | qualname, | |
1148 | value: self.span.snippet(trait_item.span), | |
1149 | parent: Some(::id_from_def_id(trait_id)), | |
1150 | children: vec![], | |
1151 | decl_id: None, | |
1152 | docs: self.save_ctxt.docs_for_attrs(&trait_item.attrs), | |
1153 | sig: sig::assoc_type_signature( | |
1154 | trait_item.id, | |
1155 | trait_item.ident, | |
1156 | Some(bounds), | |
1157 | default_ty.as_ref().map(|ty| &**ty), | |
1158 | &self.save_ctxt, | |
1159 | ), | |
1160 | attributes: lower_attributes(trait_item.attrs.clone(), &self.save_ctxt), | |
1161 | }, | |
1162 | ); | |
cc61c64b XL |
1163 | } |
1164 | ||
1165 | if let &Some(ref default_ty) = default_ty { | |
1166 | self.visit_ty(default_ty) | |
1167 | } | |
1168 | } | |
9e0c209e SL |
1169 | ast::TraitItemKind::Macro(_) => {} |
1170 | } | |
1171 | } | |
1172 | ||
476ff2be | 1173 | fn process_impl_item(&mut self, impl_item: &'l ast::ImplItem, impl_id: DefId) { |
041b39d2 | 1174 | self.process_macro_use(impl_item.span); |
9e0c209e SL |
1175 | match impl_item.node { |
1176 | ast::ImplItemKind::Const(ref ty, ref expr) => { | |
abe05a73 XL |
1177 | self.process_assoc_const( |
1178 | impl_item.id, | |
1179 | impl_item.ident.name, | |
1180 | impl_item.span, | |
1181 | &ty, | |
1182 | Some(expr), | |
1183 | impl_id, | |
1184 | impl_item.vis.clone(), | |
1185 | &impl_item.attrs, | |
1186 | ); | |
9e0c209e SL |
1187 | } |
1188 | ast::ImplItemKind::Method(ref sig, ref body) => { | |
abe05a73 XL |
1189 | self.process_method( |
1190 | sig, | |
1191 | Some(body), | |
1192 | impl_item.id, | |
1193 | impl_item.ident, | |
1194 | &impl_item.generics, | |
1195 | impl_item.vis.clone(), | |
1196 | impl_item.span, | |
1197 | ); | |
9e0c209e | 1198 | } |
041b39d2 XL |
1199 | ast::ImplItemKind::Type(ref ty) => { |
1200 | // FIXME uses of the assoc type should ideally point to this | |
1201 | // 'def' and the name here should be a ref to the def in the | |
1202 | // trait. | |
1203 | self.visit_ty(ty) | |
1204 | } | |
9e0c209e SL |
1205 | ast::ImplItemKind::Macro(_) => {} |
1206 | } | |
1207 | } | |
d9579d0f AL |
1208 | } |
1209 | ||
3b2f2976 | 1210 | impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, O> { |
7cac9316 XL |
1211 | fn visit_mod(&mut self, m: &'l ast::Mod, span: Span, attrs: &[ast::Attribute], id: NodeId) { |
1212 | // Since we handle explicit modules ourselves in visit_item, this should | |
1213 | // only get called for the root module of a crate. | |
1214 | assert_eq!(id, ast::CRATE_NODE_ID); | |
1215 | ||
1216 | let qualname = format!("::{}", self.tcx.node_path_str(id)); | |
1217 | ||
1218 | let cm = self.tcx.sess.codemap(); | |
1219 | let filename = cm.span_to_filename(span); | |
041b39d2 | 1220 | let data_id = ::id_from_node_id(id, &self.save_ctxt); |
abe05a73 XL |
1221 | let children = m.items |
1222 | .iter() | |
1223 | .map(|i| ::id_from_node_id(i.id, &self.save_ctxt)) | |
1224 | .collect(); | |
041b39d2 XL |
1225 | let span = self.span_from_span(span); |
1226 | ||
abe05a73 XL |
1227 | self.dumper.dump_def( |
1228 | true, | |
1229 | Def { | |
1230 | kind: DefKind::Mod, | |
1231 | id: data_id, | |
1232 | name: String::new(), | |
1233 | qualname, | |
1234 | span, | |
1235 | value: filename, | |
1236 | children, | |
1237 | parent: None, | |
1238 | decl_id: None, | |
1239 | docs: self.save_ctxt.docs_for_attrs(attrs), | |
1240 | sig: None, | |
1241 | attributes: lower_attributes(attrs.to_owned(), &self.save_ctxt), | |
1242 | }, | |
1243 | ); | |
7cac9316 XL |
1244 | self.nest_scope(id, |v| visit::walk_mod(v, m)); |
1245 | } | |
1246 | ||
476ff2be | 1247 | fn visit_item(&mut self, item: &'l ast::Item) { |
7453a54e | 1248 | use syntax::ast::ItemKind::*; |
041b39d2 | 1249 | self.process_macro_use(item.span); |
d9579d0f | 1250 | match item.node { |
7453a54e | 1251 | Use(ref use_item) => { |
d9579d0f AL |
1252 | match use_item.node { |
1253 | ast::ViewPathSimple(ident, ref path) => { | |
1254 | let sub_span = self.span.span_for_last_ident(path.span); | |
c30ab7b3 | 1255 | let mod_id = match self.lookup_def_id(item.id) { |
d9579d0f | 1256 | Some(def_id) => { |
041b39d2 | 1257 | self.process_def_kind(item.id, path.span, sub_span, def_id); |
d9579d0f | 1258 | Some(def_id) |
e9174d1e | 1259 | } |
d9579d0f AL |
1260 | None => None, |
1261 | }; | |
1262 | ||
1263 | // 'use' always introduces an alias, if there is not an explicit | |
1264 | // one, there is an implicit one. | |
abe05a73 XL |
1265 | let sub_span = match self.span |
1266 | .sub_span_after_keyword(use_item.span, keywords::As) | |
1267 | { | |
b039eaaf SL |
1268 | Some(sub_span) => Some(sub_span), |
1269 | None => sub_span, | |
1270 | }; | |
d9579d0f | 1271 | |
54a0048b | 1272 | if !self.span.filter_generated(sub_span, path.span) { |
041b39d2 XL |
1273 | let span = |
1274 | self.span_from_span(sub_span.expect("No span found for use")); | |
abe05a73 XL |
1275 | self.dumper.import( |
1276 | item.vis == ast::Visibility::Public, | |
1277 | Import { | |
1278 | kind: ImportKind::Use, | |
1279 | ref_id: mod_id.map(|id| ::id_from_def_id(id)), | |
1280 | span, | |
1281 | name: ident.to_string(), | |
1282 | value: String::new(), | |
1283 | }, | |
1284 | ); | |
54a0048b | 1285 | } |
32a655c1 | 1286 | self.write_sub_paths_truncated(path); |
d9579d0f AL |
1287 | } |
1288 | ast::ViewPathGlob(ref path) => { | |
1289 | // Make a comma-separated list of names of imported modules. | |
54a0048b | 1290 | let mut names = vec![]; |
476ff2be | 1291 | let glob_map = &self.save_ctxt.analysis.glob_map; |
d9579d0f AL |
1292 | let glob_map = glob_map.as_ref().unwrap(); |
1293 | if glob_map.contains_key(&item.id) { | |
1294 | for n in glob_map.get(&item.id).unwrap() { | |
54a0048b | 1295 | names.push(n.to_string()); |
d9579d0f AL |
1296 | } |
1297 | } | |
1298 | ||
b039eaaf | 1299 | let sub_span = self.span |
abe05a73 | 1300 | .sub_span_of_token(item.span, token::BinOp(token::Star)); |
a7813a04 | 1301 | if !self.span.filter_generated(sub_span, item.span) { |
041b39d2 XL |
1302 | let span = |
1303 | self.span_from_span(sub_span.expect("No span found for use glob")); | |
abe05a73 XL |
1304 | self.dumper.import( |
1305 | item.vis == ast::Visibility::Public, | |
1306 | Import { | |
1307 | kind: ImportKind::GlobUse, | |
1308 | ref_id: None, | |
1309 | span, | |
1310 | name: "*".to_owned(), | |
1311 | value: names.join(", "), | |
1312 | }, | |
1313 | ); | |
54a0048b | 1314 | } |
32a655c1 | 1315 | self.write_sub_paths(path); |
d9579d0f AL |
1316 | } |
1317 | ast::ViewPathList(ref path, ref list) => { | |
1318 | for plid in list { | |
9e0c209e | 1319 | let id = plid.node.id; |
c30ab7b3 | 1320 | if let Some(def_id) = self.lookup_def_id(id) { |
9e0c209e | 1321 | let span = plid.span; |
041b39d2 | 1322 | self.process_def_kind(id, span, Some(span), def_id); |
d9579d0f AL |
1323 | } |
1324 | } | |
1325 | ||
32a655c1 | 1326 | self.write_sub_paths(path); |
d9579d0f AL |
1327 | } |
1328 | } | |
1329 | } | |
041b39d2 | 1330 | ExternCrate(_) => { |
d9579d0f | 1331 | let alias_span = self.span.span_for_last_ident(item.span); |
54a0048b SL |
1332 | |
1333 | if !self.span.filter_generated(alias_span, item.span) { | |
041b39d2 XL |
1334 | let span = |
1335 | self.span_from_span(alias_span.expect("No span found for extern crate")); | |
abe05a73 XL |
1336 | self.dumper.import( |
1337 | false, | |
1338 | Import { | |
1339 | kind: ImportKind::ExternCrate, | |
1340 | ref_id: None, | |
1341 | span, | |
1342 | name: item.ident.to_string(), | |
1343 | value: String::new(), | |
1344 | }, | |
1345 | ); | |
54a0048b | 1346 | } |
d9579d0f | 1347 | } |
abe05a73 XL |
1348 | Fn(ref decl, .., ref ty_params, ref body) => { |
1349 | self.process_fn(item, &decl, ty_params, &body) | |
1350 | } | |
1351 | Static(ref typ, _, ref expr) => self.process_static_or_const_item(item, typ, expr), | |
1352 | Const(ref typ, ref expr) => self.process_static_or_const_item(item, &typ, &expr), | |
1353 | Struct(ref def, ref ty_params) | Union(ref def, ref ty_params) => { | |
1354 | self.process_struct(item, def, ty_params) | |
1355 | } | |
7453a54e | 1356 | Enum(ref def, ref ty_params) => self.process_enum(item, def, ty_params), |
abe05a73 | 1357 | Impl(.., ref ty_params, ref trait_ref, ref typ, ref impl_items) => { |
b039eaaf | 1358 | self.process_impl(item, ty_params, trait_ref, &typ, impl_items) |
d9579d0f | 1359 | } |
abe05a73 XL |
1360 | Trait(_, _, ref generics, ref trait_refs, ref methods) => { |
1361 | self.process_trait(item, generics, trait_refs, methods) | |
1362 | } | |
7453a54e | 1363 | Mod(ref m) => { |
62682a34 | 1364 | self.process_mod(item); |
32a655c1 | 1365 | self.nest_scope(item.id, |v| visit::walk_mod(v, m)); |
62682a34 | 1366 | } |
7453a54e | 1367 | Ty(ref ty, ref ty_params) => { |
54a0048b | 1368 | let qualname = format!("::{}", self.tcx.node_path_str(item.id)); |
7453a54e | 1369 | let value = ty_to_string(&ty); |
d9579d0f | 1370 | let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type); |
54a0048b | 1371 | if !self.span.filter_generated(sub_span, item.span) { |
041b39d2 XL |
1372 | let span = self.span_from_span(sub_span.expect("No span found for typedef")); |
1373 | let id = ::id_from_node_id(item.id, &self.save_ctxt); | |
1374 | ||
abe05a73 XL |
1375 | self.dumper.dump_def( |
1376 | item.vis == ast::Visibility::Public, | |
1377 | Def { | |
1378 | kind: DefKind::Type, | |
1379 | id, | |
1380 | span, | |
1381 | name: item.ident.to_string(), | |
1382 | qualname: qualname.clone(), | |
1383 | value, | |
1384 | parent: None, | |
1385 | children: vec![], | |
1386 | decl_id: None, | |
1387 | docs: self.save_ctxt.docs_for_attrs(&item.attrs), | |
1388 | sig: sig::item_signature(item, &self.save_ctxt), | |
1389 | attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt), | |
1390 | }, | |
1391 | ); | |
54a0048b | 1392 | } |
d9579d0f | 1393 | |
7453a54e | 1394 | self.visit_ty(&ty); |
d9579d0f | 1395 | self.process_generic_params(ty_params, item.span, &qualname, item.id); |
e9174d1e | 1396 | } |
7453a54e | 1397 | Mac(_) => (), |
d9579d0f AL |
1398 | _ => visit::walk_item(self, item), |
1399 | } | |
1400 | } | |
1401 | ||
476ff2be | 1402 | fn visit_generics(&mut self, generics: &'l ast::Generics) { |
62682a34 SL |
1403 | for param in generics.ty_params.iter() { |
1404 | for bound in param.bounds.iter() { | |
d9579d0f | 1405 | if let ast::TraitTyParamBound(ref trait_ref, _) = *bound { |
abe05a73 | 1406 | self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path) |
d9579d0f AL |
1407 | } |
1408 | } | |
1409 | if let Some(ref ty) = param.default { | |
7453a54e | 1410 | self.visit_ty(&ty); |
d9579d0f AL |
1411 | } |
1412 | } | |
1413 | } | |
1414 | ||
476ff2be | 1415 | fn visit_ty(&mut self, t: &'l ast::Ty) { |
041b39d2 | 1416 | self.process_macro_use(t.span); |
d9579d0f | 1417 | match t.node { |
7453a54e | 1418 | ast::TyKind::Path(_, ref path) => { |
32a655c1 | 1419 | if generated_code(t.span) { |
476ff2be SL |
1420 | return; |
1421 | } | |
1422 | ||
c30ab7b3 | 1423 | if let Some(id) = self.lookup_def_id(t.id) { |
32a655c1 | 1424 | if let Some(sub_span) = self.span.sub_span_for_type_name(t.span) { |
041b39d2 XL |
1425 | let span = self.span_from_span(sub_span); |
1426 | self.dumper.dump_ref(Ref { | |
1427 | kind: RefKind::Type, | |
1428 | span, | |
1429 | ref_id: ::id_from_def_id(id), | |
1430 | }); | |
32a655c1 | 1431 | } |
d9579d0f AL |
1432 | } |
1433 | ||
32a655c1 | 1434 | self.write_sub_paths_truncated(path); |
d9579d0f | 1435 | visit::walk_path(self, path); |
e9174d1e | 1436 | } |
32a655c1 SL |
1437 | ast::TyKind::Array(ref element, ref length) => { |
1438 | self.visit_ty(element); | |
1439 | self.nest_tables(length.id, |v| v.visit_expr(length)); | |
1440 | } | |
d9579d0f AL |
1441 | _ => visit::walk_ty(self, t), |
1442 | } | |
1443 | } | |
1444 | ||
476ff2be | 1445 | fn visit_expr(&mut self, ex: &'l ast::Expr) { |
32a655c1 | 1446 | debug!("visit_expr {:?}", ex.node); |
041b39d2 | 1447 | self.process_macro_use(ex.span); |
d9579d0f | 1448 | match ex.node { |
7453a54e | 1449 | ast::ExprKind::Struct(ref path, ref fields, ref base) => { |
32a655c1 SL |
1450 | let hir_expr = self.save_ctxt.tcx.hir.expect_expr(ex.id); |
1451 | let adt = match self.save_ctxt.tables.expr_ty_opt(&hir_expr) { | |
3b2f2976 XL |
1452 | Some(ty) if ty.ty_adt_def().is_some() => ty.ty_adt_def().unwrap(), |
1453 | _ => { | |
476ff2be SL |
1454 | visit::walk_expr(self, ex); |
1455 | return; | |
1456 | } | |
1457 | }; | |
1458 | let def = self.save_ctxt.get_path_def(hir_expr.id); | |
b039eaaf | 1459 | self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base) |
e9174d1e | 1460 | } |
abe05a73 | 1461 | ast::ExprKind::MethodCall(ref seg, ref args) => self.process_method_call(ex, seg, args), |
7453a54e | 1462 | ast::ExprKind::Field(ref sub_ex, _) => { |
62682a34 SL |
1463 | self.visit_expr(&sub_ex); |
1464 | ||
1465 | if let Some(field_data) = self.save_ctxt.get_expr_data(ex) { | |
041b39d2 XL |
1466 | down_cast_data!(field_data, RefData, ex.span); |
1467 | if !generated_code(ex.span) { | |
1468 | self.dumper.dump_ref(field_data); | |
54a0048b | 1469 | } |
d9579d0f | 1470 | } |
e9174d1e | 1471 | } |
7453a54e SL |
1472 | ast::ExprKind::TupField(ref sub_ex, idx) => { |
1473 | self.visit_expr(&sub_ex); | |
d9579d0f | 1474 | |
32a655c1 | 1475 | let hir_node = match self.save_ctxt.tcx.hir.find(sub_ex.id) { |
5bcae85e SL |
1476 | Some(Node::NodeExpr(expr)) => expr, |
1477 | _ => { | |
abe05a73 XL |
1478 | debug!( |
1479 | "Missing or weird node for sub-expression {} in {:?}", | |
1480 | sub_ex.id, | |
1481 | ex | |
1482 | ); | |
5bcae85e SL |
1483 | return; |
1484 | } | |
1485 | }; | |
32a655c1 | 1486 | let ty = match self.save_ctxt.tables.expr_ty_adjusted_opt(&hir_node) { |
476ff2be SL |
1487 | Some(ty) => &ty.sty, |
1488 | None => { | |
1489 | visit::walk_expr(self, ex); | |
1490 | return; | |
1491 | } | |
1492 | }; | |
d9579d0f | 1493 | match *ty { |
9e0c209e | 1494 | ty::TyAdt(def, _) => { |
e9174d1e | 1495 | let sub_span = self.span.sub_span_after_token(ex.span, token::Dot); |
54a0048b | 1496 | if !self.span.filter_generated(sub_span, ex.span) { |
041b39d2 XL |
1497 | let span = |
1498 | self.span_from_span(sub_span.expect("No span found for var ref")); | |
1499 | self.dumper.dump_ref(Ref { | |
1500 | kind: RefKind::Variable, | |
3b2f2976 | 1501 | span, |
041b39d2 XL |
1502 | ref_id: ::id_from_def_id(def.struct_variant().fields[idx.node].did), |
1503 | }); | |
54a0048b | 1504 | } |
d9579d0f | 1505 | } |
8bb4bdeb | 1506 | ty::TyTuple(..) => {} |
abe05a73 | 1507 | _ => span_bug!(ex.span, "Expected struct or tuple type, found {:?}", ty), |
d9579d0f | 1508 | } |
e9174d1e | 1509 | } |
a7813a04 | 1510 | ast::ExprKind::Closure(_, ref decl, ref body, _fn_decl_span) => { |
62682a34 | 1511 | let mut id = String::from("$"); |
d9579d0f | 1512 | id.push_str(&ex.id.to_string()); |
d9579d0f AL |
1513 | |
1514 | // walk arg and return types | |
1515 | for arg in &decl.inputs { | |
7453a54e | 1516 | self.visit_ty(&arg.ty); |
d9579d0f AL |
1517 | } |
1518 | ||
7453a54e SL |
1519 | if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output { |
1520 | self.visit_ty(&ret_ty); | |
d9579d0f AL |
1521 | } |
1522 | ||
1523 | // walk the body | |
32a655c1 SL |
1524 | self.nest_tables(ex.id, |v| { |
1525 | v.process_formals(&decl.inputs, &id); | |
1526 | v.nest_scope(ex.id, |v| v.visit_expr(body)) | |
1527 | }); | |
e9174d1e | 1528 | } |
7453a54e SL |
1529 | ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) | |
1530 | ast::ExprKind::WhileLet(ref pattern, ref subexpression, ref block, _) => { | |
a7813a04 | 1531 | let value = self.span.snippet(subexpression.span); |
b039eaaf | 1532 | self.process_var_decl(pattern, value); |
32a655c1 | 1533 | debug!("for loop, walk sub-expr: {:?}", subexpression.node); |
abe05a73 | 1534 | self.visit_expr(subexpression); |
b039eaaf SL |
1535 | visit::walk_block(self, block); |
1536 | } | |
7453a54e | 1537 | ast::ExprKind::IfLet(ref pattern, ref subexpression, ref block, ref opt_else) => { |
a7813a04 | 1538 | let value = self.span.snippet(subexpression.span); |
b039eaaf | 1539 | self.process_var_decl(pattern, value); |
abe05a73 | 1540 | self.visit_expr(subexpression); |
b039eaaf | 1541 | visit::walk_block(self, block); |
abe05a73 | 1542 | opt_else.as_ref().map(|el| self.visit_expr(el)); |
b039eaaf | 1543 | } |
32a655c1 SL |
1544 | ast::ExprKind::Repeat(ref element, ref count) => { |
1545 | self.visit_expr(element); | |
1546 | self.nest_tables(count.id, |v| v.visit_expr(count)); | |
1547 | } | |
cc61c64b XL |
1548 | // In particular, we take this branch for call and path expressions, |
1549 | // where we'll index the idents involved just by continuing to walk. | |
abe05a73 | 1550 | _ => visit::walk_expr(self, ex), |
d9579d0f AL |
1551 | } |
1552 | } | |
1553 | ||
476ff2be | 1554 | fn visit_mac(&mut self, mac: &'l ast::Mac) { |
7453a54e | 1555 | // These shouldn't exist in the AST at this point, log a span bug. |
abe05a73 XL |
1556 | span_bug!( |
1557 | mac.span, | |
1558 | "macro invocation should have been expanded out of AST" | |
1559 | ); | |
d9579d0f AL |
1560 | } |
1561 | ||
476ff2be | 1562 | fn visit_pat(&mut self, p: &'l ast::Pat) { |
041b39d2 | 1563 | self.process_macro_use(p.span); |
d9579d0f AL |
1564 | self.process_pat(p); |
1565 | } | |
1566 | ||
476ff2be | 1567 | fn visit_arm(&mut self, arm: &'l ast::Arm) { |
d9579d0f AL |
1568 | let mut collector = PathCollector::new(); |
1569 | for pattern in &arm.pats { | |
1570 | // collect paths from the arm's patterns | |
1571 | collector.visit_pat(&pattern); | |
1572 | self.visit_pat(&pattern); | |
1573 | } | |
1574 | ||
d9579d0f | 1575 | // process collected paths |
abe05a73 | 1576 | for (id, i, sp, immut) in collector.collected_idents { |
476ff2be | 1577 | match self.save_ctxt.get_path_def(id) { |
ea8adc8c | 1578 | HirDef::Local(id) => { |
9e0c209e | 1579 | let mut value = if immut == ast::Mutability::Immutable { |
abe05a73 | 1580 | self.span.snippet(sp).to_string() |
d9579d0f AL |
1581 | } else { |
1582 | "<mutable>".to_string() | |
1583 | }; | |
3b2f2976 XL |
1584 | let hir_id = self.tcx.hir.node_to_hir_id(id); |
1585 | let typ = self.save_ctxt | |
abe05a73 XL |
1586 | .tables |
1587 | .node_id_to_type_opt(hir_id) | |
1588 | .map(|t| t.to_string()) | |
1589 | .unwrap_or(String::new()); | |
9e0c209e SL |
1590 | value.push_str(": "); |
1591 | value.push_str(&typ); | |
d9579d0f | 1592 | |
abe05a73 XL |
1593 | if !self.span.filter_generated(Some(sp), sp) { |
1594 | let qualname = format!("{}${}", i.to_string(), id); | |
041b39d2 | 1595 | let id = ::id_from_node_id(id, &self.save_ctxt); |
abe05a73 | 1596 | let span = self.span_from_span(sp); |
041b39d2 | 1597 | |
abe05a73 XL |
1598 | self.dumper.dump_def( |
1599 | false, | |
1600 | Def { | |
1601 | kind: DefKind::Local, | |
1602 | id, | |
1603 | span, | |
1604 | name: i.to_string(), | |
1605 | qualname, | |
1606 | value: typ, | |
1607 | parent: None, | |
1608 | children: vec![], | |
1609 | decl_id: None, | |
1610 | docs: String::new(), | |
1611 | sig: None, | |
1612 | attributes: vec![], | |
1613 | }, | |
1614 | ); | |
54a0048b | 1615 | } |
d9579d0f | 1616 | } |
abe05a73 XL |
1617 | HirDef::StructCtor(..) | |
1618 | HirDef::VariantCtor(..) | | |
1619 | HirDef::Const(..) | | |
1620 | HirDef::AssociatedConst(..) | | |
1621 | HirDef::Struct(..) | | |
1622 | HirDef::Variant(..) | | |
1623 | HirDef::TyAlias(..) | | |
1624 | HirDef::AssociatedTy(..) | | |
041b39d2 | 1625 | HirDef::SelfTy(..) => { |
abe05a73 | 1626 | self.dump_path_ref(id, &ast::Path::from_ident(sp, i)); |
d9579d0f | 1627 | } |
abe05a73 XL |
1628 | def => error!( |
1629 | "unexpected definition kind when processing collected idents: {:?}", | |
1630 | def | |
1631 | ), | |
d9579d0f AL |
1632 | } |
1633 | } | |
c1a9b12d | 1634 | |
abe05a73 | 1635 | for (id, ref path) in collector.collected_paths { |
041b39d2 | 1636 | self.process_path(id, path); |
d9579d0f | 1637 | } |
b039eaaf | 1638 | walk_list!(self, visit_expr, &arm.guard); |
c1a9b12d | 1639 | self.visit_expr(&arm.body); |
d9579d0f AL |
1640 | } |
1641 | ||
32a655c1 | 1642 | fn visit_path(&mut self, p: &'l ast::Path, id: NodeId) { |
041b39d2 | 1643 | self.process_path(id, p); |
32a655c1 SL |
1644 | } |
1645 | ||
476ff2be | 1646 | fn visit_stmt(&mut self, s: &'l ast::Stmt) { |
041b39d2 | 1647 | self.process_macro_use(s.span); |
d9579d0f AL |
1648 | visit::walk_stmt(self, s) |
1649 | } | |
1650 | ||
476ff2be | 1651 | fn visit_local(&mut self, l: &'l ast::Local) { |
041b39d2 | 1652 | self.process_macro_use(l.span); |
abe05a73 XL |
1653 | let value = l.init |
1654 | .as_ref() | |
1655 | .map(|i| self.span.snippet(i.span)) | |
1656 | .unwrap_or(String::new()); | |
b039eaaf | 1657 | self.process_var_decl(&l.pat, value); |
d9579d0f AL |
1658 | |
1659 | // Just walk the initialiser and type (don't want to walk the pattern again). | |
b039eaaf SL |
1660 | walk_list!(self, visit_ty, &l.ty); |
1661 | walk_list!(self, visit_expr, &l.init); | |
d9579d0f | 1662 | } |
cc61c64b XL |
1663 | |
1664 | fn visit_foreign_item(&mut self, item: &'l ast::ForeignItem) { | |
1665 | match item.node { | |
1666 | ast::ForeignItemKind::Fn(ref decl, ref generics) => { | |
1667 | if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) { | |
041b39d2 | 1668 | down_cast_data!(fn_data, DefData, item.span); |
cc61c64b | 1669 | |
abe05a73 XL |
1670 | self.nest_tables( |
1671 | item.id, | |
1672 | |v| v.process_formals(&decl.inputs, &fn_data.qualname), | |
1673 | ); | |
cc61c64b | 1674 | self.process_generic_params(generics, item.span, &fn_data.qualname, item.id); |
abe05a73 XL |
1675 | self.dumper |
1676 | .dump_def(item.vis == ast::Visibility::Public, fn_data); | |
cc61c64b XL |
1677 | } |
1678 | ||
1679 | for arg in &decl.inputs { | |
1680 | self.visit_ty(&arg.ty); | |
1681 | } | |
1682 | ||
1683 | if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output { | |
1684 | self.visit_ty(&ret_ty); | |
1685 | } | |
1686 | } | |
1687 | ast::ForeignItemKind::Static(ref ty, _) => { | |
1688 | if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) { | |
041b39d2 | 1689 | down_cast_data!(var_data, DefData, item.span); |
abe05a73 XL |
1690 | self.dumper |
1691 | .dump_def(item.vis == ast::Visibility::Public, var_data); | |
cc61c64b XL |
1692 | } |
1693 | ||
1694 | self.visit_ty(ty); | |
1695 | } | |
abe05a73 XL |
1696 | ast::ForeignItemKind::Ty => { |
1697 | if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) { | |
1698 | down_cast_data!(var_data, DefData, item.span); | |
1699 | self.dumper | |
1700 | .dump_def(item.vis == ast::Visibility::Public, var_data); | |
1701 | } | |
1702 | } | |
cc61c64b XL |
1703 | } |
1704 | } | |
d9579d0f | 1705 | } |