]>
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 | ||
11 | //! Output a CSV file containing the output from rustc's analysis. The data is | |
12 | //! primarily designed to be used as input to the DXR tool, specifically its | |
13 | //! Rust plugin. It could also be used by IDEs or other code browsing, search, or | |
14 | //! cross-referencing tools. | |
15 | //! | |
16 | //! Dumping the analysis is implemented by walking the AST and getting a bunch of | |
17 | //! info out from all over the place. We use Def IDs to identify objects. The | |
18 | //! tricky part is getting syntactic (span, source text) and semantic (reference | |
19 | //! Def IDs) information for parts of expressions which the compiler has discarded. | |
20 | //! E.g., in a path `foo::bar::baz`, the compiler only keeps a span for the whole | |
21 | //! path and a reference to `baz`, but we want spans and references for all three | |
22 | //! idents. | |
23 | //! | |
24 | //! SpanUtils is used to manipulate spans. In particular, to extract sub-spans | |
25 | //! from spans (e.g., the span for `bar` from the above example path). | |
26 | //! Recorder is used for recording the output in csv format. FmtStrs separates | |
27 | //! the format of the output away from extracting it from the compiler. | |
28 | //! DumpCsvVisitor walks the AST and processes it. | |
29 | ||
30 | ||
31 | use super::{escape, generated_code, recorder, SaveContext, PathCollector}; | |
32 | ||
33 | use session::Session; | |
34 | ||
35 | use middle::def; | |
36 | use middle::ty::{self, Ty}; | |
62682a34 | 37 | use rustc::ast_map::NodeItem; |
d9579d0f AL |
38 | |
39 | use std::cell::Cell; | |
40 | use std::fs::File; | |
41 | use std::path::Path; | |
42 | ||
43 | use syntax::ast_util; | |
44 | use syntax::ast::{self, NodeId, DefId}; | |
d9579d0f AL |
45 | use syntax::codemap::*; |
46 | use syntax::parse::token::{self, get_ident, keywords}; | |
47 | use syntax::owned_slice::OwnedSlice; | |
48 | use syntax::visit::{self, Visitor}; | |
49 | use syntax::print::pprust::{path_to_string, ty_to_string}; | |
50 | use syntax::ptr::P; | |
51 | ||
52 | use super::span_utils::SpanUtils; | |
53 | use super::recorder::{Recorder, FmtStrs}; | |
54 | ||
62682a34 SL |
55 | macro_rules! down_cast_data { |
56 | ($id:ident, $kind:ident, $this:ident, $sp:expr) => { | |
57 | let $id = if let super::Data::$kind(data) = $id { | |
58 | data | |
59 | } else { | |
60 | $this.sess.span_bug($sp, &format!("unexpected data kind: {:?}", $id)); | |
61 | }; | |
62 | }; | |
63 | } | |
d9579d0f AL |
64 | |
65 | pub struct DumpCsvVisitor<'l, 'tcx: 'l> { | |
66 | save_ctxt: SaveContext<'l, 'tcx>, | |
67 | sess: &'l Session, | |
62682a34 SL |
68 | tcx: &'l ty::ctxt<'tcx>, |
69 | analysis: &'l ty::CrateAnalysis, | |
d9579d0f AL |
70 | |
71 | span: SpanUtils<'l>, | |
72 | fmt: FmtStrs<'l>, | |
73 | ||
74 | cur_scope: NodeId | |
75 | } | |
76 | ||
77 | impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { | |
62682a34 SL |
78 | pub fn new(tcx: &'l ty::ctxt<'tcx>, |
79 | analysis: &'l ty::CrateAnalysis, | |
d9579d0f | 80 | output_file: Box<File>) -> DumpCsvVisitor<'l, 'tcx> { |
62682a34 SL |
81 | let span_utils = SpanUtils { |
82 | sess: &tcx.sess, | |
83 | err_count: Cell::new(0) | |
84 | }; | |
d9579d0f | 85 | DumpCsvVisitor { |
62682a34 SL |
86 | sess: &tcx.sess, |
87 | tcx: tcx, | |
88 | save_ctxt: SaveContext::new(tcx, span_utils.clone()), | |
d9579d0f | 89 | analysis: analysis, |
62682a34 | 90 | span: span_utils.clone(), |
d9579d0f AL |
91 | fmt: FmtStrs::new(box Recorder { |
92 | out: output_file, | |
93 | dump_spans: false, | |
62682a34 | 94 | }, span_utils), |
d9579d0f AL |
95 | cur_scope: 0 |
96 | } | |
97 | } | |
98 | ||
99 | fn nest<F>(&mut self, scope_id: NodeId, f: F) where | |
100 | F: FnOnce(&mut DumpCsvVisitor<'l, 'tcx>), | |
101 | { | |
102 | let parent_scope = self.cur_scope; | |
103 | self.cur_scope = scope_id; | |
104 | f(self); | |
105 | self.cur_scope = parent_scope; | |
106 | } | |
107 | ||
108 | pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) { | |
109 | // The current crate. | |
110 | self.fmt.crate_str(krate.span, name); | |
111 | ||
112 | // Dump info about all the external crates referenced from this crate. | |
113 | for c in &self.save_ctxt.get_external_crates() { | |
114 | self.fmt.external_crate_str(krate.span, &c.name, c.number); | |
115 | } | |
116 | self.fmt.recorder.record("end_external_crates\n"); | |
117 | } | |
118 | ||
119 | // Return all non-empty prefixes of a path. | |
120 | // For each prefix, we return the span for the last segment in the prefix and | |
121 | // a str representation of the entire prefix. | |
122 | fn process_path_prefixes(&self, path: &ast::Path) -> Vec<(Span, String)> { | |
123 | let spans = self.span.spans_for_path_segments(path); | |
124 | ||
125 | // Paths to enums seem to not match their spans - the span includes all the | |
126 | // variants too. But they seem to always be at the end, so I hope we can cope with | |
127 | // always using the first ones. So, only error out if we don't have enough spans. | |
128 | // What could go wrong...? | |
129 | if spans.len() < path.segments.len() { | |
130 | error!("Mis-calculated spans for path '{}'. \ | |
131 | Found {} spans, expected {}. Found spans:", | |
132 | path_to_string(path), spans.len(), path.segments.len()); | |
133 | for s in &spans { | |
134 | let loc = self.sess.codemap().lookup_char_pos(s.lo); | |
135 | error!(" '{}' in {}, line {}", | |
136 | self.span.snippet(*s), loc.file.name, loc.line); | |
137 | } | |
138 | return vec!(); | |
139 | } | |
140 | ||
141 | let mut result: Vec<(Span, String)> = vec!(); | |
142 | ||
143 | let mut segs = vec!(); | |
62682a34 | 144 | for (i, (seg, span)) in path.segments.iter().zip(&spans).enumerate() { |
d9579d0f AL |
145 | segs.push(seg.clone()); |
146 | let sub_path = ast::Path{span: *span, // span for the last segment | |
147 | global: path.global, | |
148 | segments: segs}; | |
149 | let qualname = if i == 0 && path.global { | |
150 | format!("::{}", path_to_string(&sub_path)) | |
151 | } else { | |
152 | path_to_string(&sub_path) | |
153 | }; | |
154 | result.push((*span, qualname)); | |
155 | segs = sub_path.segments; | |
156 | } | |
157 | ||
158 | result | |
159 | } | |
160 | ||
161 | // The global arg allows us to override the global-ness of the path (which | |
162 | // actually means 'does the path start with `::`', rather than 'is the path | |
163 | // semantically global). We use the override for `use` imports (etc.) where | |
164 | // the syntax is non-global, but the semantics are global. | |
165 | fn write_sub_paths(&mut self, path: &ast::Path, global: bool) { | |
166 | let sub_paths = self.process_path_prefixes(path); | |
167 | for (i, &(ref span, ref qualname)) in sub_paths.iter().enumerate() { | |
168 | let qualname = if i == 0 && global && !path.global { | |
169 | format!("::{}", qualname) | |
170 | } else { | |
171 | qualname.clone() | |
172 | }; | |
173 | self.fmt.sub_mod_ref_str(path.span, | |
174 | *span, | |
62682a34 | 175 | &qualname, |
d9579d0f AL |
176 | self.cur_scope); |
177 | } | |
178 | } | |
179 | ||
180 | // As write_sub_paths, but does not process the last ident in the path (assuming it | |
181 | // will be processed elsewhere). See note on write_sub_paths about global. | |
182 | fn write_sub_paths_truncated(&mut self, path: &ast::Path, global: bool) { | |
183 | let sub_paths = self.process_path_prefixes(path); | |
184 | let len = sub_paths.len(); | |
185 | if len <= 1 { | |
186 | return; | |
187 | } | |
188 | ||
189 | let sub_paths = &sub_paths[..len-1]; | |
190 | for (i, &(ref span, ref qualname)) in sub_paths.iter().enumerate() { | |
191 | let qualname = if i == 0 && global && !path.global { | |
192 | format!("::{}", qualname) | |
193 | } else { | |
194 | qualname.clone() | |
195 | }; | |
196 | self.fmt.sub_mod_ref_str(path.span, | |
197 | *span, | |
62682a34 | 198 | &qualname, |
d9579d0f AL |
199 | self.cur_scope); |
200 | } | |
201 | } | |
202 | ||
203 | // As write_sub_paths, but expects a path of the form module_path::trait::method | |
204 | // Where trait could actually be a struct too. | |
205 | fn write_sub_path_trait_truncated(&mut self, path: &ast::Path) { | |
206 | let sub_paths = self.process_path_prefixes(path); | |
207 | let len = sub_paths.len(); | |
208 | if len <= 1 { | |
209 | return; | |
210 | } | |
211 | let sub_paths = &sub_paths[.. (len-1)]; | |
212 | ||
213 | // write the trait part of the sub-path | |
214 | let (ref span, ref qualname) = sub_paths[len-2]; | |
215 | self.fmt.sub_type_ref_str(path.span, | |
216 | *span, | |
62682a34 | 217 | &qualname); |
d9579d0f AL |
218 | |
219 | // write the other sub-paths | |
220 | if len <= 2 { | |
221 | return; | |
222 | } | |
223 | let sub_paths = &sub_paths[..len-2]; | |
224 | for &(ref span, ref qualname) in sub_paths { | |
225 | self.fmt.sub_mod_ref_str(path.span, | |
226 | *span, | |
62682a34 | 227 | &qualname, |
d9579d0f AL |
228 | self.cur_scope); |
229 | } | |
230 | } | |
231 | ||
232 | // looks up anything, not just a type | |
233 | fn lookup_type_ref(&self, ref_id: NodeId) -> Option<DefId> { | |
62682a34 | 234 | if !self.tcx.def_map.borrow().contains_key(&ref_id) { |
d9579d0f AL |
235 | self.sess.bug(&format!("def_map has no key for {} in lookup_type_ref", |
236 | ref_id)); | |
237 | } | |
62682a34 | 238 | let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def(); |
d9579d0f AL |
239 | match def { |
240 | def::DefPrimTy(_) => None, | |
241 | _ => Some(def.def_id()), | |
242 | } | |
243 | } | |
244 | ||
245 | fn lookup_def_kind(&self, ref_id: NodeId, span: Span) -> Option<recorder::Row> { | |
62682a34 | 246 | let def_map = self.tcx.def_map.borrow(); |
d9579d0f AL |
247 | if !def_map.contains_key(&ref_id) { |
248 | self.sess.span_bug(span, &format!("def_map has no key for {} in lookup_def_kind", | |
249 | ref_id)); | |
250 | } | |
251 | let def = def_map.get(&ref_id).unwrap().full_def(); | |
252 | match def { | |
253 | def::DefMod(_) | | |
254 | def::DefForeignMod(_) => Some(recorder::ModRef), | |
62682a34 | 255 | def::DefStruct(_) => Some(recorder::TypeRef), |
d9579d0f AL |
256 | def::DefTy(..) | |
257 | def::DefAssociatedTy(..) | | |
258 | def::DefTrait(_) => Some(recorder::TypeRef), | |
259 | def::DefStatic(_, _) | | |
260 | def::DefConst(_) | | |
261 | def::DefAssociatedConst(..) | | |
262 | def::DefLocal(_) | | |
263 | def::DefVariant(_, _, _) | | |
264 | def::DefUpvar(..) => Some(recorder::VarRef), | |
265 | ||
266 | def::DefFn(..) => Some(recorder::FnRef), | |
267 | ||
268 | def::DefSelfTy(..) | | |
269 | def::DefRegion(_) | | |
270 | def::DefLabel(_) | | |
271 | def::DefTyParam(..) | | |
272 | def::DefUse(_) | | |
273 | def::DefMethod(..) | | |
274 | def::DefPrimTy(_) => { | |
275 | self.sess.span_bug(span, &format!("lookup_def_kind for unexpected item: {:?}", | |
276 | def)); | |
277 | }, | |
278 | } | |
279 | } | |
280 | ||
281 | fn process_formals(&mut self, formals: &Vec<ast::Arg>, qualname: &str) { | |
282 | for arg in formals { | |
283 | self.visit_pat(&arg.pat); | |
284 | let mut collector = PathCollector::new(); | |
285 | collector.visit_pat(&arg.pat); | |
286 | let span_utils = self.span.clone(); | |
287 | for &(id, ref p, _, _) in &collector.collected_paths { | |
62682a34 | 288 | let typ = self.tcx.node_types().get(&id).unwrap().to_string(); |
d9579d0f AL |
289 | // get the span only for the name of the variable (I hope the path is only ever a |
290 | // variable name, but who knows?) | |
291 | self.fmt.formal_str(p.span, | |
292 | span_utils.span_for_last_ident(p.span), | |
293 | id, | |
294 | qualname, | |
295 | &path_to_string(p), | |
62682a34 | 296 | &typ); |
d9579d0f AL |
297 | } |
298 | } | |
299 | } | |
300 | ||
301 | fn process_method(&mut self, sig: &ast::MethodSig, | |
302 | body: Option<&ast::Block>, | |
303 | id: ast::NodeId, name: ast::Name, | |
304 | span: Span) { | |
305 | if generated_code(span) { | |
306 | return; | |
307 | } | |
308 | ||
309 | debug!("process_method: {}:{}", id, token::get_name(name)); | |
310 | ||
311 | let mut scope_id; | |
312 | // The qualname for a method is the trait name or name of the struct in an impl in | |
313 | // which the method is declared in, followed by the method's name. | |
62682a34 SL |
314 | let qualname = match ty::impl_of_method(self.tcx, ast_util::local_def(id)) { |
315 | Some(impl_id) => match self.tcx.map.get(impl_id.node) { | |
d9579d0f AL |
316 | NodeItem(item) => { |
317 | scope_id = item.id; | |
318 | match item.node { | |
319 | ast::ItemImpl(_, _, _, _, ref ty, _) => { | |
62682a34 | 320 | let mut result = String::from("<"); |
d9579d0f AL |
321 | result.push_str(&ty_to_string(&**ty)); |
322 | ||
62682a34 | 323 | match ty::trait_of_item(self.tcx, ast_util::local_def(id)) { |
d9579d0f AL |
324 | Some(def_id) => { |
325 | result.push_str(" as "); | |
326 | result.push_str( | |
62682a34 | 327 | &ty::item_path_str(self.tcx, def_id)); |
d9579d0f AL |
328 | }, |
329 | None => {} | |
330 | } | |
331 | result.push_str(">"); | |
332 | result | |
333 | } | |
334 | _ => { | |
335 | self.sess.span_bug(span, | |
336 | &format!("Container {} for method {} not an impl?", | |
337 | impl_id.node, id)); | |
338 | }, | |
339 | } | |
340 | }, | |
341 | _ => { | |
342 | self.sess.span_bug(span, | |
343 | &format!("Container {} for method {} is not a node item {:?}", | |
62682a34 | 344 | impl_id.node, id, self.tcx.map.get(impl_id.node))); |
d9579d0f AL |
345 | }, |
346 | }, | |
62682a34 | 347 | None => match ty::trait_of_item(self.tcx, ast_util::local_def(id)) { |
d9579d0f AL |
348 | Some(def_id) => { |
349 | scope_id = def_id.node; | |
62682a34 | 350 | match self.tcx.map.get(def_id.node) { |
d9579d0f | 351 | NodeItem(_) => { |
62682a34 | 352 | format!("::{}", ty::item_path_str(self.tcx, def_id)) |
d9579d0f AL |
353 | } |
354 | _ => { | |
355 | self.sess.span_bug(span, | |
356 | &format!("Could not find container {} for method {}", | |
357 | def_id.node, id)); | |
358 | } | |
359 | } | |
360 | }, | |
361 | None => { | |
362 | self.sess.span_bug(span, | |
363 | &format!("Could not find container for method {}", id)); | |
364 | }, | |
365 | }, | |
366 | }; | |
367 | ||
368 | let qualname = &format!("{}::{}", qualname, &token::get_name(name)); | |
369 | ||
370 | // record the decl for this def (if it has one) | |
62682a34 | 371 | let decl_id = ty::trait_item_of_item(self.tcx, ast_util::local_def(id)) |
d9579d0f AL |
372 | .and_then(|new_id| { |
373 | let def_id = new_id.def_id(); | |
374 | if def_id.node != 0 && def_id != ast_util::local_def(id) { | |
375 | Some(def_id) | |
376 | } else { | |
377 | None | |
378 | } | |
379 | }); | |
380 | ||
381 | let sub_span = self.span.sub_span_after_keyword(span, keywords::Fn); | |
382 | if body.is_some() { | |
383 | self.fmt.method_str(span, | |
384 | sub_span, | |
385 | id, | |
386 | qualname, | |
387 | decl_id, | |
388 | scope_id); | |
389 | self.process_formals(&sig.decl.inputs, qualname); | |
390 | } else { | |
391 | self.fmt.method_decl_str(span, | |
392 | sub_span, | |
393 | id, | |
394 | qualname, | |
395 | scope_id); | |
396 | } | |
397 | ||
398 | // walk arg and return types | |
399 | for arg in &sig.decl.inputs { | |
400 | self.visit_ty(&arg.ty); | |
401 | } | |
402 | ||
403 | if let ast::Return(ref ret_ty) = sig.decl.output { | |
404 | self.visit_ty(ret_ty); | |
405 | } | |
406 | ||
407 | // walk the fn body | |
408 | if let Some(body) = body { | |
409 | self.nest(id, |v| v.visit_block(body)); | |
410 | } | |
411 | ||
412 | self.process_generic_params(&sig.generics, | |
413 | span, | |
414 | qualname, | |
415 | id); | |
416 | } | |
417 | ||
62682a34 SL |
418 | fn process_trait_ref(&mut self, trait_ref: &ast::TraitRef) { |
419 | let trait_ref_data = self.save_ctxt.get_trait_ref_data(trait_ref, self.cur_scope); | |
420 | if let Some(trait_ref_data) = trait_ref_data { | |
421 | self.fmt.ref_str(recorder::TypeRef, | |
422 | trait_ref.path.span, | |
423 | Some(trait_ref_data.span), | |
424 | trait_ref_data.ref_id, | |
425 | trait_ref_data.scope); | |
426 | visit::walk_path(self, &trait_ref.path); | |
d9579d0f AL |
427 | } |
428 | } | |
429 | ||
430 | fn process_struct_field_def(&mut self, | |
431 | field: &ast::StructField, | |
62682a34 SL |
432 | parent_id: NodeId) { |
433 | let field_data = self.save_ctxt.get_field_data(field, parent_id); | |
434 | if let Some(field_data) = field_data { | |
435 | down_cast_data!(field_data, VariableData, self, field.span); | |
436 | self.fmt.field_str(field.span, | |
437 | Some(field_data.span), | |
438 | field_data.id, | |
439 | &field_data.name, | |
440 | &field_data.qualname, | |
441 | &field_data.type_value, | |
442 | field_data.scope); | |
d9579d0f AL |
443 | } |
444 | } | |
445 | ||
446 | // Dump generic params bindings, then visit_generics | |
447 | fn process_generic_params(&mut self, | |
448 | generics:&ast::Generics, | |
449 | full_span: Span, | |
450 | prefix: &str, | |
451 | id: NodeId) { | |
452 | // We can't only use visit_generics since we don't have spans for param | |
453 | // bindings, so we reparse the full_span to get those sub spans. | |
454 | // However full span is the entire enum/fn/struct block, so we only want | |
455 | // the first few to match the number of generics we're looking for. | |
456 | let param_sub_spans = self.span.spans_for_ty_params(full_span, | |
457 | (generics.ty_params.len() as isize)); | |
62682a34 | 458 | for (param, param_ss) in generics.ty_params.iter().zip(param_sub_spans) { |
d9579d0f AL |
459 | // Append $id to name to make sure each one is unique |
460 | let name = format!("{}::{}${}", | |
461 | prefix, | |
62682a34 | 462 | escape(self.span.snippet(param_ss)), |
d9579d0f AL |
463 | id); |
464 | self.fmt.typedef_str(full_span, | |
62682a34 | 465 | Some(param_ss), |
d9579d0f | 466 | param.id, |
62682a34 | 467 | &name, |
d9579d0f AL |
468 | ""); |
469 | } | |
470 | self.visit_generics(generics); | |
471 | } | |
472 | ||
473 | fn process_fn(&mut self, | |
474 | item: &ast::Item, | |
475 | decl: &ast::FnDecl, | |
476 | ty_params: &ast::Generics, | |
477 | body: &ast::Block) { | |
478 | let fn_data = self.save_ctxt.get_item_data(item); | |
62682a34 SL |
479 | down_cast_data!(fn_data, FunctionData, self, item.span); |
480 | self.fmt.fn_str(item.span, | |
481 | Some(fn_data.span), | |
482 | fn_data.id, | |
483 | &fn_data.qualname, | |
484 | fn_data.scope); | |
d9579d0f AL |
485 | |
486 | ||
62682a34 SL |
487 | self.process_formals(&decl.inputs, &fn_data.qualname); |
488 | self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id); | |
d9579d0f AL |
489 | |
490 | for arg in &decl.inputs { | |
491 | self.visit_ty(&arg.ty); | |
492 | } | |
493 | ||
494 | if let ast::Return(ref ret_ty) = decl.output { | |
495 | self.visit_ty(&ret_ty); | |
496 | } | |
497 | ||
498 | self.nest(item.id, |v| v.visit_block(&body)); | |
499 | } | |
500 | ||
501 | fn process_static_or_const_item(&mut self, | |
502 | item: &ast::Item, | |
503 | typ: &ast::Ty, | |
504 | expr: &ast::Expr) | |
505 | { | |
506 | let var_data = self.save_ctxt.get_item_data(item); | |
62682a34 SL |
507 | down_cast_data!(var_data, VariableData, self, item.span); |
508 | self.fmt.static_str(item.span, | |
509 | Some(var_data.span), | |
510 | var_data.id, | |
511 | &var_data.name, | |
512 | &var_data.qualname, | |
513 | &var_data.value, | |
514 | &var_data.type_value, | |
515 | var_data.scope); | |
d9579d0f AL |
516 | |
517 | self.visit_ty(&typ); | |
518 | self.visit_expr(expr); | |
519 | } | |
520 | ||
521 | fn process_const(&mut self, | |
522 | id: ast::NodeId, | |
523 | ident: &ast::Ident, | |
524 | span: Span, | |
525 | typ: &ast::Ty, | |
526 | expr: &ast::Expr) | |
527 | { | |
62682a34 | 528 | let qualname = format!("::{}", self.tcx.map.path_to_string(id)); |
d9579d0f AL |
529 | |
530 | let sub_span = self.span.sub_span_after_keyword(span, | |
531 | keywords::Const); | |
532 | ||
533 | self.fmt.static_str(span, | |
534 | sub_span, | |
535 | id, | |
536 | &get_ident((*ident).clone()), | |
62682a34 | 537 | &qualname, |
d9579d0f AL |
538 | &self.span.snippet(expr.span), |
539 | &ty_to_string(&*typ), | |
540 | self.cur_scope); | |
541 | ||
542 | // walk type and init value | |
543 | self.visit_ty(typ); | |
544 | self.visit_expr(expr); | |
545 | } | |
546 | ||
547 | fn process_struct(&mut self, | |
548 | item: &ast::Item, | |
549 | def: &ast::StructDef, | |
550 | ty_params: &ast::Generics) { | |
62682a34 | 551 | let qualname = format!("::{}", self.tcx.map.path_to_string(item.id)); |
d9579d0f AL |
552 | |
553 | let ctor_id = match def.ctor_id { | |
554 | Some(node_id) => node_id, | |
555 | None => -1, | |
556 | }; | |
557 | let val = self.span.snippet(item.span); | |
558 | let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct); | |
559 | self.fmt.struct_str(item.span, | |
560 | sub_span, | |
561 | item.id, | |
562 | ctor_id, | |
62682a34 | 563 | &qualname, |
d9579d0f | 564 | self.cur_scope, |
62682a34 | 565 | &val); |
d9579d0f AL |
566 | |
567 | // fields | |
568 | for field in &def.fields { | |
62682a34 SL |
569 | self.process_struct_field_def(field, item.id); |
570 | self.visit_ty(&field.node.ty); | |
d9579d0f AL |
571 | } |
572 | ||
62682a34 | 573 | self.process_generic_params(ty_params, item.span, &qualname, item.id); |
d9579d0f AL |
574 | } |
575 | ||
576 | fn process_enum(&mut self, | |
577 | item: &ast::Item, | |
578 | enum_definition: &ast::EnumDef, | |
579 | ty_params: &ast::Generics) { | |
62682a34 SL |
580 | let enum_data = self.save_ctxt.get_item_data(item); |
581 | down_cast_data!(enum_data, EnumData, self, item.span); | |
582 | self.fmt.enum_str(item.span, | |
583 | Some(enum_data.span), | |
584 | enum_data.id, | |
585 | &enum_data.qualname, | |
586 | enum_data.scope, | |
587 | &enum_data.value); | |
588 | ||
d9579d0f | 589 | for variant in &enum_definition.variants { |
62682a34 SL |
590 | let name = &get_ident(variant.node.name); |
591 | let mut qualname = enum_data.qualname.clone(); | |
d9579d0f AL |
592 | qualname.push_str("::"); |
593 | qualname.push_str(name); | |
594 | let val = self.span.snippet(variant.span); | |
595 | match variant.node.kind { | |
596 | ast::TupleVariantKind(ref args) => { | |
597 | // first ident in span is the variant's name | |
598 | self.fmt.tuple_variant_str(variant.span, | |
599 | self.span.span_for_first_ident(variant.span), | |
600 | variant.node.id, | |
601 | name, | |
62682a34 SL |
602 | &qualname, |
603 | &enum_data.qualname, | |
604 | &val, | |
605 | enum_data.id); | |
d9579d0f AL |
606 | for arg in args { |
607 | self.visit_ty(&*arg.ty); | |
608 | } | |
609 | } | |
610 | ast::StructVariantKind(ref struct_def) => { | |
611 | let ctor_id = match struct_def.ctor_id { | |
612 | Some(node_id) => node_id, | |
613 | None => -1, | |
614 | }; | |
62682a34 SL |
615 | self.fmt.struct_variant_str(variant.span, |
616 | self.span.span_for_first_ident(variant.span), | |
617 | variant.node.id, | |
618 | ctor_id, | |
619 | &qualname, | |
620 | &enum_data.qualname, | |
621 | &val, | |
622 | enum_data.id); | |
d9579d0f AL |
623 | |
624 | for field in &struct_def.fields { | |
62682a34 | 625 | self.process_struct_field_def(field, variant.node.id); |
d9579d0f AL |
626 | self.visit_ty(&*field.node.ty); |
627 | } | |
628 | } | |
629 | } | |
630 | } | |
62682a34 | 631 | self.process_generic_params(ty_params, item.span, &enum_data.qualname, enum_data.id); |
d9579d0f AL |
632 | } |
633 | ||
634 | fn process_impl(&mut self, | |
635 | item: &ast::Item, | |
636 | type_parameters: &ast::Generics, | |
637 | trait_ref: &Option<ast::TraitRef>, | |
638 | typ: &ast::Ty, | |
639 | impl_items: &[P<ast::ImplItem>]) { | |
62682a34 SL |
640 | let impl_data = self.save_ctxt.get_item_data(item); |
641 | down_cast_data!(impl_data, ImplData, self, item.span); | |
642 | match impl_data.self_ref { | |
643 | Some(ref self_ref) => { | |
644 | self.fmt.ref_str(recorder::TypeRef, | |
645 | item.span, | |
646 | Some(self_ref.span), | |
647 | self_ref.ref_id, | |
648 | self_ref.scope); | |
649 | } | |
650 | None => { | |
651 | self.visit_ty(&typ); | |
d9579d0f AL |
652 | } |
653 | } | |
62682a34 SL |
654 | if let Some(ref trait_ref_data) = impl_data.trait_ref { |
655 | self.fmt.ref_str(recorder::TypeRef, | |
656 | item.span, | |
657 | Some(trait_ref_data.span), | |
658 | trait_ref_data.ref_id, | |
659 | trait_ref_data.scope); | |
660 | visit::walk_path(self, &trait_ref.as_ref().unwrap().path); | |
d9579d0f AL |
661 | } |
662 | ||
62682a34 SL |
663 | self.fmt.impl_str(item.span, |
664 | Some(impl_data.span), | |
665 | impl_data.id, | |
666 | impl_data.self_ref.map(|data| data.ref_id), | |
667 | impl_data.trait_ref.map(|data| data.ref_id), | |
668 | impl_data.scope); | |
669 | ||
d9579d0f AL |
670 | self.process_generic_params(type_parameters, item.span, "", item.id); |
671 | for impl_item in impl_items { | |
672 | self.visit_impl_item(impl_item); | |
673 | } | |
674 | } | |
675 | ||
676 | fn process_trait(&mut self, | |
677 | item: &ast::Item, | |
678 | generics: &ast::Generics, | |
679 | trait_refs: &OwnedSlice<ast::TyParamBound>, | |
680 | methods: &[P<ast::TraitItem>]) { | |
62682a34 | 681 | let qualname = format!("::{}", self.tcx.map.path_to_string(item.id)); |
d9579d0f AL |
682 | let val = self.span.snippet(item.span); |
683 | let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait); | |
684 | self.fmt.trait_str(item.span, | |
685 | sub_span, | |
686 | item.id, | |
62682a34 | 687 | &qualname, |
d9579d0f | 688 | self.cur_scope, |
62682a34 | 689 | &val); |
d9579d0f AL |
690 | |
691 | // super-traits | |
62682a34 | 692 | for super_bound in trait_refs.iter() { |
d9579d0f AL |
693 | let trait_ref = match *super_bound { |
694 | ast::TraitTyParamBound(ref trait_ref, _) => { | |
695 | trait_ref | |
696 | } | |
697 | ast::RegionTyParamBound(..) => { | |
698 | continue; | |
699 | } | |
700 | }; | |
701 | ||
702 | let trait_ref = &trait_ref.trait_ref; | |
703 | match self.lookup_type_ref(trait_ref.ref_id) { | |
704 | Some(id) => { | |
705 | let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span); | |
706 | self.fmt.ref_str(recorder::TypeRef, | |
707 | trait_ref.path.span, | |
708 | sub_span, | |
709 | id, | |
710 | self.cur_scope); | |
711 | self.fmt.inherit_str(trait_ref.path.span, | |
712 | sub_span, | |
713 | id, | |
714 | item.id); | |
715 | }, | |
716 | None => () | |
717 | } | |
718 | } | |
719 | ||
720 | // walk generics and methods | |
62682a34 | 721 | self.process_generic_params(generics, item.span, &qualname, item.id); |
d9579d0f AL |
722 | for method in methods { |
723 | self.visit_trait_item(method) | |
724 | } | |
725 | } | |
726 | ||
727 | fn process_mod(&mut self, | |
62682a34 SL |
728 | item: &ast::Item) { // The module in question, represented as an item. |
729 | let mod_data = self.save_ctxt.get_item_data(item); | |
730 | down_cast_data!(mod_data, ModData, self, item.span); | |
d9579d0f | 731 | self.fmt.mod_str(item.span, |
62682a34 SL |
732 | Some(mod_data.span), |
733 | mod_data.id, | |
734 | &mod_data.qualname, | |
735 | mod_data.scope, | |
736 | &mod_data.filename); | |
d9579d0f AL |
737 | } |
738 | ||
739 | fn process_path(&mut self, | |
740 | id: NodeId, | |
741 | span: Span, | |
742 | path: &ast::Path, | |
743 | ref_kind: Option<recorder::Row>) { | |
744 | if generated_code(span) { | |
745 | return | |
746 | } | |
747 | ||
62682a34 | 748 | let def_map = self.tcx.def_map.borrow(); |
d9579d0f AL |
749 | if !def_map.contains_key(&id) { |
750 | self.sess.span_bug(span, | |
751 | &format!("def_map has no key for {} in visit_expr", id)); | |
752 | } | |
753 | let def = def_map.get(&id).unwrap().full_def(); | |
754 | let sub_span = self.span.span_for_last_ident(span); | |
755 | match def { | |
756 | def::DefUpvar(..) | | |
757 | def::DefLocal(..) | | |
758 | def::DefStatic(..) | | |
759 | def::DefConst(..) | | |
760 | def::DefAssociatedConst(..) | | |
761 | def::DefVariant(..) => self.fmt.ref_str(ref_kind.unwrap_or(recorder::VarRef), | |
762 | span, | |
763 | sub_span, | |
764 | def.def_id(), | |
765 | self.cur_scope), | |
62682a34 | 766 | def::DefStruct(def_id) => self.fmt.ref_str(recorder::TypeRef, |
d9579d0f AL |
767 | span, |
768 | sub_span, | |
769 | def_id, | |
770 | self.cur_scope), | |
771 | def::DefTy(def_id, _) => self.fmt.ref_str(recorder::TypeRef, | |
772 | span, | |
773 | sub_span, | |
774 | def_id, | |
775 | self.cur_scope), | |
776 | def::DefMethod(declid, provenence) => { | |
777 | let sub_span = self.span.sub_span_for_meth_name(span); | |
778 | let defid = if declid.krate == ast::LOCAL_CRATE { | |
62682a34 | 779 | let ti = ty::impl_or_trait_item(self.tcx, declid); |
d9579d0f AL |
780 | match provenence { |
781 | def::FromTrait(def_id) => { | |
62682a34 | 782 | Some(ty::trait_items(self.tcx, def_id) |
d9579d0f AL |
783 | .iter() |
784 | .find(|mr| { | |
785 | mr.name() == ti.name() | |
786 | }) | |
787 | .unwrap() | |
788 | .def_id()) | |
789 | } | |
790 | def::FromImpl(def_id) => { | |
62682a34 | 791 | let impl_items = self.tcx.impl_items.borrow(); |
d9579d0f AL |
792 | Some(impl_items.get(&def_id) |
793 | .unwrap() | |
794 | .iter() | |
795 | .find(|mr| { | |
796 | ty::impl_or_trait_item( | |
62682a34 | 797 | self.tcx, |
d9579d0f AL |
798 | mr.def_id() |
799 | ).name() == ti.name() | |
800 | }) | |
801 | .unwrap() | |
802 | .def_id()) | |
803 | } | |
804 | } | |
805 | } else { | |
806 | None | |
807 | }; | |
808 | self.fmt.meth_call_str(span, | |
809 | sub_span, | |
810 | defid, | |
811 | Some(declid), | |
812 | self.cur_scope); | |
813 | }, | |
814 | def::DefFn(def_id, _) => { | |
815 | self.fmt.fn_call_str(span, | |
816 | sub_span, | |
817 | def_id, | |
818 | self.cur_scope) | |
819 | } | |
820 | _ => self.sess.span_bug(span, | |
821 | &format!("Unexpected def kind while looking \ | |
822 | up path in `{}`: `{:?}`", | |
823 | self.span.snippet(span), | |
824 | def)), | |
825 | } | |
826 | // modules or types in the path prefix | |
827 | match def { | |
828 | def::DefMethod(did, _) => { | |
62682a34 | 829 | let ti = ty::impl_or_trait_item(self.tcx, did); |
d9579d0f AL |
830 | if let ty::MethodTraitItem(m) = ti { |
831 | if m.explicit_self == ty::StaticExplicitSelfCategory { | |
832 | self.write_sub_path_trait_truncated(path); | |
833 | } | |
834 | } | |
835 | } | |
836 | def::DefLocal(_) | | |
837 | def::DefStatic(_,_) | | |
838 | def::DefConst(..) | | |
839 | def::DefAssociatedConst(..) | | |
840 | def::DefStruct(_) | | |
841 | def::DefVariant(..) | | |
842 | def::DefFn(..) => self.write_sub_paths_truncated(path, false), | |
843 | _ => {}, | |
844 | } | |
845 | } | |
846 | ||
847 | fn process_struct_lit(&mut self, | |
848 | ex: &ast::Expr, | |
849 | path: &ast::Path, | |
850 | fields: &Vec<ast::Field>, | |
851 | base: &Option<P<ast::Expr>>) { | |
852 | if generated_code(path.span) { | |
853 | return | |
854 | } | |
855 | ||
856 | self.write_sub_paths_truncated(path, false); | |
857 | ||
62682a34 SL |
858 | if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) { |
859 | down_cast_data!(struct_lit_data, TypeRefData, self, ex.span); | |
860 | self.fmt.ref_str(recorder::TypeRef, | |
861 | ex.span, | |
862 | Some(struct_lit_data.span), | |
863 | struct_lit_data.ref_id, | |
864 | struct_lit_data.scope); | |
865 | let struct_def = struct_lit_data.ref_id; | |
866 | ||
867 | for field in fields { | |
868 | if generated_code(field.ident.span) { | |
869 | continue; | |
d9579d0f | 870 | } |
d9579d0f | 871 | |
62682a34 SL |
872 | let field_data = self.save_ctxt.get_field_ref_data(field, |
873 | struct_def, | |
874 | self.cur_scope); | |
875 | self.fmt.ref_str(recorder::VarRef, | |
876 | field.ident.span, | |
877 | Some(field_data.span), | |
878 | field_data.ref_id, | |
879 | field_data.scope); | |
880 | ||
881 | self.visit_expr(&field.expr) | |
882 | } | |
d9579d0f | 883 | } |
62682a34 | 884 | |
d9579d0f AL |
885 | visit::walk_expr_opt(self, base) |
886 | } | |
887 | ||
888 | fn process_method_call(&mut self, | |
889 | ex: &ast::Expr, | |
890 | args: &Vec<P<ast::Expr>>) { | |
62682a34 | 891 | let method_map = self.tcx.method_map.borrow(); |
d9579d0f AL |
892 | let method_callee = method_map.get(&ty::MethodCall::expr(ex.id)).unwrap(); |
893 | let (def_id, decl_id) = match method_callee.origin { | |
894 | ty::MethodStatic(def_id) | | |
895 | ty::MethodStaticClosure(def_id) => { | |
896 | // method invoked on an object with a concrete type (not a static method) | |
897 | let decl_id = | |
62682a34 | 898 | match ty::trait_item_of_item(self.tcx, def_id) { |
d9579d0f AL |
899 | None => None, |
900 | Some(decl_id) => Some(decl_id.def_id()), | |
901 | }; | |
902 | ||
903 | // This incantation is required if the method referenced is a | |
904 | // trait's default implementation. | |
62682a34 | 905 | let def_id = match ty::impl_or_trait_item(self.tcx, def_id) { |
d9579d0f AL |
906 | ty::MethodTraitItem(method) => { |
907 | method.provided_source.unwrap_or(def_id) | |
908 | } | |
909 | _ => self.sess | |
910 | .span_bug(ex.span, | |
911 | "save::process_method_call: non-method \ | |
912 | DefId in MethodStatic or MethodStaticClosure"), | |
913 | }; | |
914 | (Some(def_id), decl_id) | |
915 | } | |
916 | ty::MethodTypeParam(ref mp) => { | |
917 | // method invoked on a type parameter | |
62682a34 | 918 | let trait_item = ty::trait_item(self.tcx, |
d9579d0f AL |
919 | mp.trait_ref.def_id, |
920 | mp.method_num); | |
921 | (None, Some(trait_item.def_id())) | |
922 | } | |
923 | ty::MethodTraitObject(ref mo) => { | |
924 | // method invoked on a trait instance | |
62682a34 | 925 | let trait_item = ty::trait_item(self.tcx, |
d9579d0f AL |
926 | mo.trait_ref.def_id, |
927 | mo.method_num); | |
928 | (None, Some(trait_item.def_id())) | |
929 | } | |
930 | }; | |
931 | let sub_span = self.span.sub_span_for_meth_name(ex.span); | |
932 | self.fmt.meth_call_str(ex.span, | |
933 | sub_span, | |
934 | def_id, | |
935 | decl_id, | |
936 | self.cur_scope); | |
937 | ||
938 | // walk receiver and args | |
62682a34 | 939 | visit::walk_exprs(self, &args); |
d9579d0f AL |
940 | } |
941 | ||
942 | fn process_pat(&mut self, p:&ast::Pat) { | |
943 | if generated_code(p.span) { | |
944 | return | |
945 | } | |
946 | ||
947 | match p.node { | |
948 | ast::PatStruct(ref path, ref fields, _) => { | |
949 | visit::walk_path(self, path); | |
950 | ||
62682a34 | 951 | let def = self.tcx.def_map.borrow().get(&p.id).unwrap().full_def(); |
d9579d0f AL |
952 | let struct_def = match def { |
953 | def::DefConst(..) | def::DefAssociatedConst(..) => None, | |
954 | def::DefVariant(_, variant_id, _) => Some(variant_id), | |
955 | _ => { | |
62682a34 | 956 | match ty::ty_to_def_id(ty::node_id_to_type(self.tcx, p.id)) { |
d9579d0f AL |
957 | None => { |
958 | self.sess.span_bug(p.span, | |
959 | &format!("Could not find struct_def for `{}`", | |
960 | self.span.snippet(p.span))); | |
961 | } | |
962 | Some(def_id) => Some(def_id), | |
963 | } | |
964 | } | |
965 | }; | |
966 | ||
967 | if let Some(struct_def) = struct_def { | |
62682a34 | 968 | let struct_fields = ty::lookup_struct_fields(self.tcx, struct_def); |
d9579d0f AL |
969 | for &Spanned { node: ref field, span } in fields { |
970 | let sub_span = self.span.span_for_first_ident(span); | |
971 | for f in &struct_fields { | |
972 | if f.name == field.ident.name { | |
973 | self.fmt.ref_str(recorder::VarRef, | |
974 | span, | |
975 | sub_span, | |
976 | f.id, | |
977 | self.cur_scope); | |
978 | break; | |
979 | } | |
980 | } | |
981 | self.visit_pat(&*field.pat); | |
982 | } | |
983 | } | |
984 | } | |
985 | _ => visit::walk_pat(self, p) | |
986 | } | |
987 | } | |
988 | } | |
989 | ||
990 | impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { | |
991 | fn visit_item(&mut self, item: &ast::Item) { | |
992 | if generated_code(item.span) { | |
993 | return | |
994 | } | |
995 | ||
996 | match item.node { | |
997 | ast::ItemUse(ref use_item) => { | |
998 | match use_item.node { | |
999 | ast::ViewPathSimple(ident, ref path) => { | |
1000 | let sub_span = self.span.span_for_last_ident(path.span); | |
1001 | let mod_id = match self.lookup_type_ref(item.id) { | |
1002 | Some(def_id) => { | |
1003 | match self.lookup_def_kind(item.id, path.span) { | |
1004 | Some(kind) => self.fmt.ref_str(kind, | |
1005 | path.span, | |
1006 | sub_span, | |
1007 | def_id, | |
1008 | self.cur_scope), | |
1009 | None => {}, | |
1010 | } | |
1011 | Some(def_id) | |
1012 | }, | |
1013 | None => None, | |
1014 | }; | |
1015 | ||
1016 | // 'use' always introduces an alias, if there is not an explicit | |
1017 | // one, there is an implicit one. | |
1018 | let sub_span = | |
1019 | match self.span.sub_span_after_keyword(use_item.span, keywords::As) { | |
1020 | Some(sub_span) => Some(sub_span), | |
1021 | None => sub_span, | |
1022 | }; | |
1023 | ||
1024 | self.fmt.use_alias_str(path.span, | |
1025 | sub_span, | |
1026 | item.id, | |
1027 | mod_id, | |
1028 | &get_ident(ident), | |
1029 | self.cur_scope); | |
1030 | self.write_sub_paths_truncated(path, true); | |
1031 | } | |
1032 | ast::ViewPathGlob(ref path) => { | |
1033 | // Make a comma-separated list of names of imported modules. | |
1034 | let mut name_string = String::new(); | |
1035 | let glob_map = &self.analysis.glob_map; | |
1036 | let glob_map = glob_map.as_ref().unwrap(); | |
1037 | if glob_map.contains_key(&item.id) { | |
1038 | for n in glob_map.get(&item.id).unwrap() { | |
1039 | if !name_string.is_empty() { | |
1040 | name_string.push_str(", "); | |
1041 | } | |
1042 | name_string.push_str(n.as_str()); | |
1043 | } | |
1044 | } | |
1045 | ||
1046 | let sub_span = self.span.sub_span_of_token(path.span, | |
1047 | token::BinOp(token::Star)); | |
1048 | self.fmt.use_glob_str(path.span, | |
1049 | sub_span, | |
1050 | item.id, | |
1051 | &name_string, | |
1052 | self.cur_scope); | |
1053 | self.write_sub_paths(path, true); | |
1054 | } | |
1055 | ast::ViewPathList(ref path, ref list) => { | |
1056 | for plid in list { | |
1057 | match plid.node { | |
1058 | ast::PathListIdent { id, .. } => { | |
1059 | match self.lookup_type_ref(id) { | |
1060 | Some(def_id) => | |
1061 | match self.lookup_def_kind(id, plid.span) { | |
1062 | Some(kind) => { | |
1063 | self.fmt.ref_str( | |
1064 | kind, plid.span, | |
1065 | Some(plid.span), | |
1066 | def_id, self.cur_scope); | |
1067 | } | |
1068 | None => () | |
1069 | }, | |
1070 | None => () | |
1071 | } | |
1072 | }, | |
1073 | ast::PathListMod { .. } => () | |
1074 | } | |
1075 | } | |
1076 | ||
1077 | self.write_sub_paths(path, true); | |
1078 | } | |
1079 | } | |
1080 | } | |
1081 | ast::ItemExternCrate(ref s) => { | |
1082 | let name = get_ident(item.ident); | |
1083 | let name = &name; | |
1084 | let location = match *s { | |
1085 | Some(s) => s.to_string(), | |
1086 | None => name.to_string(), | |
1087 | }; | |
1088 | let alias_span = self.span.span_for_last_ident(item.span); | |
1089 | let cnum = match self.sess.cstore.find_extern_mod_stmt_cnum(item.id) { | |
1090 | Some(cnum) => cnum, | |
1091 | None => 0, | |
1092 | }; | |
1093 | self.fmt.extern_crate_str(item.span, | |
1094 | alias_span, | |
1095 | item.id, | |
1096 | cnum, | |
1097 | name, | |
62682a34 | 1098 | &location, |
d9579d0f AL |
1099 | self.cur_scope); |
1100 | } | |
62682a34 | 1101 | ast::ItemFn(ref decl, _, _, _, ref ty_params, ref body) => |
d9579d0f AL |
1102 | self.process_fn(item, &**decl, ty_params, &**body), |
1103 | ast::ItemStatic(ref typ, _, ref expr) => | |
1104 | self.process_static_or_const_item(item, typ, expr), | |
1105 | ast::ItemConst(ref typ, ref expr) => | |
1106 | self.process_static_or_const_item(item, &typ, &expr), | |
1107 | ast::ItemStruct(ref def, ref ty_params) => self.process_struct(item, &**def, ty_params), | |
1108 | ast::ItemEnum(ref def, ref ty_params) => self.process_enum(item, def, ty_params), | |
1109 | ast::ItemImpl(_, _, | |
1110 | ref ty_params, | |
1111 | ref trait_ref, | |
1112 | ref typ, | |
1113 | ref impl_items) => { | |
1114 | self.process_impl(item, | |
1115 | ty_params, | |
1116 | trait_ref, | |
62682a34 | 1117 | &typ, |
d9579d0f AL |
1118 | impl_items) |
1119 | } | |
1120 | ast::ItemTrait(_, ref generics, ref trait_refs, ref methods) => | |
1121 | self.process_trait(item, generics, trait_refs, methods), | |
62682a34 SL |
1122 | ast::ItemMod(ref m) => { |
1123 | self.process_mod(item); | |
1124 | self.nest(item.id, |v| visit::walk_mod(v, m)); | |
1125 | } | |
d9579d0f | 1126 | ast::ItemTy(ref ty, ref ty_params) => { |
62682a34 | 1127 | let qualname = format!("::{}", self.tcx.map.path_to_string(item.id)); |
d9579d0f AL |
1128 | let value = ty_to_string(&**ty); |
1129 | let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type); | |
1130 | self.fmt.typedef_str(item.span, | |
1131 | sub_span, | |
1132 | item.id, | |
62682a34 SL |
1133 | &qualname, |
1134 | &value); | |
d9579d0f AL |
1135 | |
1136 | self.visit_ty(&**ty); | |
1137 | self.process_generic_params(ty_params, item.span, &qualname, item.id); | |
1138 | }, | |
1139 | ast::ItemMac(_) => (), | |
1140 | _ => visit::walk_item(self, item), | |
1141 | } | |
1142 | } | |
1143 | ||
1144 | fn visit_generics(&mut self, generics: &ast::Generics) { | |
62682a34 SL |
1145 | for param in generics.ty_params.iter() { |
1146 | for bound in param.bounds.iter() { | |
d9579d0f AL |
1147 | if let ast::TraitTyParamBound(ref trait_ref, _) = *bound { |
1148 | self.process_trait_ref(&trait_ref.trait_ref); | |
1149 | } | |
1150 | } | |
1151 | if let Some(ref ty) = param.default { | |
1152 | self.visit_ty(&**ty); | |
1153 | } | |
1154 | } | |
1155 | } | |
1156 | ||
1157 | fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) { | |
1158 | match trait_item.node { | |
1159 | ast::ConstTraitItem(ref ty, Some(ref expr)) => { | |
1160 | self.process_const(trait_item.id, &trait_item.ident, | |
1161 | trait_item.span, &*ty, &*expr); | |
1162 | } | |
1163 | ast::MethodTraitItem(ref sig, ref body) => { | |
1164 | self.process_method(sig, body.as_ref().map(|x| &**x), | |
1165 | trait_item.id, trait_item.ident.name, trait_item.span); | |
1166 | } | |
1167 | ast::ConstTraitItem(_, None) | | |
1168 | ast::TypeTraitItem(..) => {} | |
1169 | } | |
1170 | } | |
1171 | ||
1172 | fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) { | |
1173 | match impl_item.node { | |
1174 | ast::ConstImplItem(ref ty, ref expr) => { | |
1175 | self.process_const(impl_item.id, &impl_item.ident, | |
1176 | impl_item.span, &ty, &expr); | |
1177 | } | |
1178 | ast::MethodImplItem(ref sig, ref body) => { | |
1179 | self.process_method(sig, Some(body), impl_item.id, | |
1180 | impl_item.ident.name, impl_item.span); | |
1181 | } | |
1182 | ast::TypeImplItem(_) | | |
1183 | ast::MacImplItem(_) => {} | |
1184 | } | |
1185 | } | |
1186 | ||
1187 | fn visit_ty(&mut self, t: &ast::Ty) { | |
1188 | if generated_code(t.span) { | |
1189 | return | |
1190 | } | |
1191 | ||
1192 | match t.node { | |
1193 | ast::TyPath(_, ref path) => { | |
1194 | match self.lookup_type_ref(t.id) { | |
1195 | Some(id) => { | |
1196 | let sub_span = self.span.sub_span_for_type_name(t.span); | |
1197 | self.fmt.ref_str(recorder::TypeRef, | |
1198 | t.span, | |
1199 | sub_span, | |
1200 | id, | |
1201 | self.cur_scope); | |
1202 | }, | |
1203 | None => () | |
1204 | } | |
1205 | ||
1206 | self.write_sub_paths_truncated(path, false); | |
1207 | ||
1208 | visit::walk_path(self, path); | |
1209 | }, | |
1210 | _ => visit::walk_ty(self, t), | |
1211 | } | |
1212 | } | |
1213 | ||
1214 | fn visit_expr(&mut self, ex: &ast::Expr) { | |
1215 | if generated_code(ex.span) { | |
1216 | return | |
1217 | } | |
1218 | ||
1219 | match ex.node { | |
1220 | ast::ExprCall(ref _f, ref _args) => { | |
1221 | // Don't need to do anything for function calls, | |
1222 | // because just walking the callee path does what we want. | |
1223 | visit::walk_expr(self, ex); | |
1224 | } | |
1225 | ast::ExprPath(_, ref path) => { | |
1226 | self.process_path(ex.id, path.span, path, None); | |
1227 | visit::walk_expr(self, ex); | |
1228 | } | |
1229 | ast::ExprStruct(ref path, ref fields, ref base) => | |
1230 | self.process_struct_lit(ex, path, fields, base), | |
1231 | ast::ExprMethodCall(_, _, ref args) => self.process_method_call(ex, args), | |
62682a34 | 1232 | ast::ExprField(ref sub_ex, _) => { |
d9579d0f AL |
1233 | if generated_code(sub_ex.span) { |
1234 | return | |
1235 | } | |
1236 | ||
62682a34 SL |
1237 | self.visit_expr(&sub_ex); |
1238 | ||
1239 | if let Some(field_data) = self.save_ctxt.get_expr_data(ex) { | |
1240 | down_cast_data!(field_data, VariableRefData, self, ex.span); | |
1241 | self.fmt.ref_str(recorder::VarRef, | |
1242 | ex.span, | |
1243 | Some(field_data.span), | |
1244 | field_data.ref_id, | |
1245 | field_data.scope); | |
d9579d0f AL |
1246 | } |
1247 | }, | |
1248 | ast::ExprTupField(ref sub_ex, idx) => { | |
1249 | if generated_code(sub_ex.span) { | |
1250 | return | |
1251 | } | |
1252 | ||
1253 | self.visit_expr(&**sub_ex); | |
1254 | ||
62682a34 | 1255 | let ty = &ty::expr_ty_adjusted(self.tcx, &**sub_ex).sty; |
d9579d0f | 1256 | match *ty { |
62682a34 SL |
1257 | ty::TyStruct(def_id, _) => { |
1258 | let fields = ty::lookup_struct_fields(self.tcx, def_id); | |
d9579d0f AL |
1259 | for (i, f) in fields.iter().enumerate() { |
1260 | if i == idx.node { | |
1261 | let sub_span = self.span.sub_span_after_token(ex.span, token::Dot); | |
1262 | self.fmt.ref_str(recorder::VarRef, | |
1263 | ex.span, | |
1264 | sub_span, | |
1265 | f.id, | |
1266 | self.cur_scope); | |
1267 | break; | |
1268 | } | |
1269 | } | |
1270 | } | |
62682a34 | 1271 | ty::TyTuple(_) => {} |
d9579d0f AL |
1272 | _ => self.sess.span_bug(ex.span, |
1273 | &format!("Expected struct or tuple \ | |
1274 | type, found {:?}", ty)), | |
1275 | } | |
1276 | }, | |
1277 | ast::ExprClosure(_, ref decl, ref body) => { | |
1278 | if generated_code(body.span) { | |
1279 | return | |
1280 | } | |
1281 | ||
62682a34 | 1282 | let mut id = String::from("$"); |
d9579d0f | 1283 | id.push_str(&ex.id.to_string()); |
62682a34 | 1284 | self.process_formals(&decl.inputs, &id); |
d9579d0f AL |
1285 | |
1286 | // walk arg and return types | |
1287 | for arg in &decl.inputs { | |
1288 | self.visit_ty(&*arg.ty); | |
1289 | } | |
1290 | ||
1291 | if let ast::Return(ref ret_ty) = decl.output { | |
1292 | self.visit_ty(&**ret_ty); | |
1293 | } | |
1294 | ||
1295 | // walk the body | |
1296 | self.nest(ex.id, |v| v.visit_block(&**body)); | |
1297 | }, | |
1298 | _ => { | |
1299 | visit::walk_expr(self, ex) | |
1300 | } | |
1301 | } | |
1302 | } | |
1303 | ||
1304 | fn visit_mac(&mut self, _: &ast::Mac) { | |
1305 | // Just stop, macros are poison to us. | |
1306 | } | |
1307 | ||
1308 | fn visit_pat(&mut self, p: &ast::Pat) { | |
1309 | self.process_pat(p); | |
1310 | } | |
1311 | ||
1312 | fn visit_arm(&mut self, arm: &ast::Arm) { | |
1313 | let mut collector = PathCollector::new(); | |
1314 | for pattern in &arm.pats { | |
1315 | // collect paths from the arm's patterns | |
1316 | collector.visit_pat(&pattern); | |
1317 | self.visit_pat(&pattern); | |
1318 | } | |
1319 | ||
1320 | // This is to get around borrow checking, because we need mut self to call process_path. | |
1321 | let mut paths_to_process = vec![]; | |
1322 | // process collected paths | |
1323 | for &(id, ref p, immut, ref_kind) in &collector.collected_paths { | |
62682a34 | 1324 | let def_map = self.tcx.def_map.borrow(); |
d9579d0f AL |
1325 | if !def_map.contains_key(&id) { |
1326 | self.sess.span_bug(p.span, | |
1327 | &format!("def_map has no key for {} in visit_arm", | |
1328 | id)); | |
1329 | } | |
1330 | let def = def_map.get(&id).unwrap().full_def(); | |
1331 | match def { | |
1332 | def::DefLocal(id) => { | |
1333 | let value = if immut == ast::MutImmutable { | |
1334 | self.span.snippet(p.span).to_string() | |
1335 | } else { | |
1336 | "<mutable>".to_string() | |
1337 | }; | |
1338 | ||
1339 | assert!(p.segments.len() == 1, "qualified path for local variable def in arm"); | |
1340 | self.fmt.variable_str(p.span, | |
1341 | Some(p.span), | |
1342 | id, | |
1343 | &path_to_string(p), | |
62682a34 | 1344 | &value, |
d9579d0f AL |
1345 | "") |
1346 | } | |
1347 | def::DefVariant(..) | def::DefTy(..) | def::DefStruct(..) => { | |
1348 | paths_to_process.push((id, p.clone(), Some(ref_kind))) | |
1349 | } | |
1350 | // FIXME(nrc) what are these doing here? | |
1351 | def::DefStatic(_, _) | | |
1352 | def::DefConst(..) | | |
1353 | def::DefAssociatedConst(..) => {} | |
1354 | _ => error!("unexpected definition kind when processing collected paths: {:?}", | |
1355 | def) | |
1356 | } | |
1357 | } | |
1358 | for &(id, ref path, ref_kind) in &paths_to_process { | |
1359 | self.process_path(id, path.span, path, ref_kind); | |
1360 | } | |
1361 | visit::walk_expr_opt(self, &arm.guard); | |
1362 | self.visit_expr(&*arm.body); | |
1363 | } | |
1364 | ||
1365 | fn visit_stmt(&mut self, s: &ast::Stmt) { | |
1366 | if generated_code(s.span) { | |
1367 | return | |
1368 | } | |
1369 | ||
1370 | visit::walk_stmt(self, s) | |
1371 | } | |
1372 | ||
1373 | fn visit_local(&mut self, l: &ast::Local) { | |
1374 | if generated_code(l.span) { | |
1375 | return | |
1376 | } | |
1377 | ||
1378 | // The local could declare multiple new vars, we must walk the | |
1379 | // pattern and collect them all. | |
1380 | let mut collector = PathCollector::new(); | |
1381 | collector.visit_pat(&l.pat); | |
1382 | self.visit_pat(&l.pat); | |
1383 | ||
1384 | let value = self.span.snippet(l.span); | |
1385 | ||
1386 | for &(id, ref p, immut, _) in &collector.collected_paths { | |
1387 | let value = if immut == ast::MutImmutable { | |
1388 | value.to_string() | |
1389 | } else { | |
1390 | "<mutable>".to_string() | |
1391 | }; | |
62682a34 SL |
1392 | let types = self.tcx.node_types(); |
1393 | let typ = types.get(&id).unwrap().to_string(); | |
d9579d0f AL |
1394 | // Get the span only for the name of the variable (I hope the path |
1395 | // is only ever a variable name, but who knows?). | |
1396 | let sub_span = self.span.span_for_last_ident(p.span); | |
1397 | // Rust uses the id of the pattern for var lookups, so we'll use it too. | |
1398 | self.fmt.variable_str(p.span, | |
1399 | sub_span, | |
1400 | id, | |
1401 | &path_to_string(p), | |
62682a34 SL |
1402 | &value, |
1403 | &typ); | |
d9579d0f AL |
1404 | } |
1405 | ||
1406 | // Just walk the initialiser and type (don't want to walk the pattern again). | |
1407 | visit::walk_ty_opt(self, &l.ty); | |
1408 | visit::walk_expr_opt(self, &l.init); | |
1409 | } | |
1410 | } |