]>
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 | ||
c1a9b12d | 31 | use super::{escape, generated_code, recorder, SaveContext, PathCollector, Data}; |
d9579d0f AL |
32 | |
33 | use session::Session; | |
34 | ||
7453a54e | 35 | use middle::def::Def; |
e9174d1e | 36 | use middle::def_id::DefId; |
9cc50fc6 | 37 | use middle::ty; |
d9579d0f | 38 | |
d9579d0f | 39 | use std::fs::File; |
7453a54e SL |
40 | use std::hash::*; |
41 | use std::collections::HashSet; | |
d9579d0f | 42 | |
7453a54e | 43 | use syntax::ast::{self, NodeId, PatKind}; |
d9579d0f | 44 | use syntax::codemap::*; |
c1a9b12d | 45 | use syntax::parse::token::{self, keywords}; |
d9579d0f AL |
46 | use syntax::visit::{self, Visitor}; |
47 | use syntax::print::pprust::{path_to_string, ty_to_string}; | |
48 | use syntax::ptr::P; | |
49 | ||
b039eaaf | 50 | use rustc_front::lowering::{lower_expr, LoweringContext}; |
e9174d1e | 51 | |
d9579d0f AL |
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)); | |
b039eaaf | 61 | } |
62682a34 SL |
62 | }; |
63 | } | |
d9579d0f AL |
64 | |
65 | pub struct DumpCsvVisitor<'l, 'tcx: 'l> { | |
66 | save_ctxt: SaveContext<'l, 'tcx>, | |
67 | sess: &'l Session, | |
62682a34 | 68 | tcx: &'l ty::ctxt<'tcx>, |
b039eaaf | 69 | analysis: &'l ty::CrateAnalysis<'l>, |
d9579d0f AL |
70 | |
71 | span: SpanUtils<'l>, | |
b039eaaf | 72 | fmt: FmtStrs<'l, 'tcx>, |
d9579d0f | 73 | |
e9174d1e | 74 | cur_scope: NodeId, |
7453a54e SL |
75 | |
76 | // Set of macro definition (callee) spans, and the set | |
77 | // of macro use (callsite) spans. We store these to ensure | |
78 | // we only write one macro def per unique macro definition, and | |
79 | // one macro use per unique callsite span. | |
80 | mac_defs: HashSet<Span>, | |
81 | mac_uses: HashSet<Span>, | |
82 | ||
d9579d0f AL |
83 | } |
84 | ||
85 | impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { | |
62682a34 | 86 | pub fn new(tcx: &'l ty::ctxt<'tcx>, |
b039eaaf SL |
87 | lcx: &'l LoweringContext<'l>, |
88 | analysis: &'l ty::CrateAnalysis<'l>, | |
e9174d1e SL |
89 | output_file: Box<File>) |
90 | -> DumpCsvVisitor<'l, 'tcx> { | |
c1a9b12d | 91 | let span_utils = SpanUtils::new(&tcx.sess); |
d9579d0f | 92 | DumpCsvVisitor { |
62682a34 SL |
93 | sess: &tcx.sess, |
94 | tcx: tcx, | |
b039eaaf | 95 | save_ctxt: SaveContext::from_span_utils(tcx, lcx, span_utils.clone()), |
d9579d0f | 96 | analysis: analysis, |
62682a34 | 97 | span: span_utils.clone(), |
b039eaaf SL |
98 | fmt: FmtStrs::new(box Recorder { |
99 | out: output_file, | |
100 | dump_spans: false, | |
101 | }, | |
102 | span_utils, | |
103 | tcx), | |
e9174d1e | 104 | cur_scope: 0, |
7453a54e SL |
105 | mac_defs: HashSet::new(), |
106 | mac_uses: HashSet::new(), | |
d9579d0f AL |
107 | } |
108 | } | |
109 | ||
e9174d1e SL |
110 | fn nest<F>(&mut self, scope_id: NodeId, f: F) |
111 | where F: FnOnce(&mut DumpCsvVisitor<'l, 'tcx>) | |
d9579d0f AL |
112 | { |
113 | let parent_scope = self.cur_scope; | |
114 | self.cur_scope = scope_id; | |
115 | f(self); | |
116 | self.cur_scope = parent_scope; | |
117 | } | |
118 | ||
119 | pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) { | |
92a42be0 SL |
120 | let source_file = self.tcx.sess.local_crate_source_file.as_ref(); |
121 | let crate_root = match source_file { | |
122 | Some(source_file) => match source_file.file_name() { | |
123 | Some(_) => source_file.parent().unwrap().display().to_string(), | |
124 | None => source_file.display().to_string(), | |
125 | }, | |
126 | None => "<no source>".to_owned(), | |
127 | }; | |
128 | ||
d9579d0f | 129 | // The current crate. |
92a42be0 | 130 | self.fmt.crate_str(krate.span, name, &crate_root); |
d9579d0f AL |
131 | |
132 | // Dump info about all the external crates referenced from this crate. | |
133 | for c in &self.save_ctxt.get_external_crates() { | |
134 | self.fmt.external_crate_str(krate.span, &c.name, c.number); | |
135 | } | |
136 | self.fmt.recorder.record("end_external_crates\n"); | |
137 | } | |
138 | ||
139 | // Return all non-empty prefixes of a path. | |
140 | // For each prefix, we return the span for the last segment in the prefix and | |
141 | // a str representation of the entire prefix. | |
142 | fn process_path_prefixes(&self, path: &ast::Path) -> Vec<(Span, String)> { | |
143 | let spans = self.span.spans_for_path_segments(path); | |
144 | ||
145 | // Paths to enums seem to not match their spans - the span includes all the | |
146 | // variants too. But they seem to always be at the end, so I hope we can cope with | |
147 | // always using the first ones. So, only error out if we don't have enough spans. | |
148 | // What could go wrong...? | |
149 | if spans.len() < path.segments.len() { | |
7453a54e SL |
150 | if generated_code(path.span) { |
151 | return vec!(); | |
152 | } | |
b039eaaf SL |
153 | error!("Mis-calculated spans for path '{}'. Found {} spans, expected {}. Found spans:", |
154 | path_to_string(path), | |
155 | spans.len(), | |
156 | path.segments.len()); | |
d9579d0f AL |
157 | for s in &spans { |
158 | let loc = self.sess.codemap().lookup_char_pos(s.lo); | |
159 | error!(" '{}' in {}, line {}", | |
b039eaaf SL |
160 | self.span.snippet(*s), |
161 | loc.file.name, | |
162 | loc.line); | |
d9579d0f AL |
163 | } |
164 | return vec!(); | |
165 | } | |
166 | ||
167 | let mut result: Vec<(Span, String)> = vec!(); | |
168 | ||
169 | let mut segs = vec!(); | |
62682a34 | 170 | for (i, (seg, span)) in path.segments.iter().zip(&spans).enumerate() { |
d9579d0f | 171 | segs.push(seg.clone()); |
e9174d1e SL |
172 | let sub_path = ast::Path { |
173 | span: *span, // span for the last segment | |
174 | global: path.global, | |
175 | segments: segs, | |
176 | }; | |
d9579d0f AL |
177 | let qualname = if i == 0 && path.global { |
178 | format!("::{}", path_to_string(&sub_path)) | |
179 | } else { | |
180 | path_to_string(&sub_path) | |
181 | }; | |
182 | result.push((*span, qualname)); | |
183 | segs = sub_path.segments; | |
184 | } | |
185 | ||
186 | result | |
187 | } | |
188 | ||
189 | // The global arg allows us to override the global-ness of the path (which | |
190 | // actually means 'does the path start with `::`', rather than 'is the path | |
191 | // semantically global). We use the override for `use` imports (etc.) where | |
192 | // the syntax is non-global, but the semantics are global. | |
193 | fn write_sub_paths(&mut self, path: &ast::Path, global: bool) { | |
194 | let sub_paths = self.process_path_prefixes(path); | |
195 | for (i, &(ref span, ref qualname)) in sub_paths.iter().enumerate() { | |
196 | let qualname = if i == 0 && global && !path.global { | |
197 | format!("::{}", qualname) | |
198 | } else { | |
199 | qualname.clone() | |
200 | }; | |
b039eaaf | 201 | self.fmt.sub_mod_ref_str(path.span, *span, &qualname, self.cur_scope); |
d9579d0f AL |
202 | } |
203 | } | |
204 | ||
205 | // As write_sub_paths, but does not process the last ident in the path (assuming it | |
206 | // will be processed elsewhere). See note on write_sub_paths about global. | |
207 | fn write_sub_paths_truncated(&mut self, path: &ast::Path, global: bool) { | |
208 | let sub_paths = self.process_path_prefixes(path); | |
209 | let len = sub_paths.len(); | |
210 | if len <= 1 { | |
211 | return; | |
212 | } | |
213 | ||
214 | let sub_paths = &sub_paths[..len-1]; | |
215 | for (i, &(ref span, ref qualname)) in sub_paths.iter().enumerate() { | |
216 | let qualname = if i == 0 && global && !path.global { | |
217 | format!("::{}", qualname) | |
218 | } else { | |
219 | qualname.clone() | |
220 | }; | |
b039eaaf | 221 | self.fmt.sub_mod_ref_str(path.span, *span, &qualname, self.cur_scope); |
d9579d0f AL |
222 | } |
223 | } | |
224 | ||
225 | // As write_sub_paths, but expects a path of the form module_path::trait::method | |
226 | // Where trait could actually be a struct too. | |
227 | fn write_sub_path_trait_truncated(&mut self, path: &ast::Path) { | |
228 | let sub_paths = self.process_path_prefixes(path); | |
229 | let len = sub_paths.len(); | |
230 | if len <= 1 { | |
231 | return; | |
232 | } | |
233 | let sub_paths = &sub_paths[.. (len-1)]; | |
234 | ||
235 | // write the trait part of the sub-path | |
236 | let (ref span, ref qualname) = sub_paths[len-2]; | |
b039eaaf | 237 | self.fmt.sub_type_ref_str(path.span, *span, &qualname); |
d9579d0f AL |
238 | |
239 | // write the other sub-paths | |
240 | if len <= 2 { | |
241 | return; | |
242 | } | |
243 | let sub_paths = &sub_paths[..len-2]; | |
244 | for &(ref span, ref qualname) in sub_paths { | |
b039eaaf | 245 | self.fmt.sub_mod_ref_str(path.span, *span, &qualname, self.cur_scope); |
d9579d0f AL |
246 | } |
247 | } | |
248 | ||
249 | // looks up anything, not just a type | |
250 | fn lookup_type_ref(&self, ref_id: NodeId) -> Option<DefId> { | |
62682a34 | 251 | if !self.tcx.def_map.borrow().contains_key(&ref_id) { |
d9579d0f | 252 | self.sess.bug(&format!("def_map has no key for {} in lookup_type_ref", |
b039eaaf | 253 | ref_id)); |
d9579d0f | 254 | } |
62682a34 | 255 | let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def(); |
d9579d0f | 256 | match def { |
7453a54e SL |
257 | Def::PrimTy(..) => None, |
258 | Def::SelfTy(..) => None, | |
d9579d0f AL |
259 | _ => Some(def.def_id()), |
260 | } | |
261 | } | |
262 | ||
263 | fn lookup_def_kind(&self, ref_id: NodeId, span: Span) -> Option<recorder::Row> { | |
62682a34 | 264 | let def_map = self.tcx.def_map.borrow(); |
d9579d0f | 265 | if !def_map.contains_key(&ref_id) { |
b039eaaf SL |
266 | self.sess.span_bug(span, |
267 | &format!("def_map has no key for {} in lookup_def_kind", | |
268 | ref_id)); | |
d9579d0f AL |
269 | } |
270 | let def = def_map.get(&ref_id).unwrap().full_def(); | |
271 | match def { | |
7453a54e SL |
272 | Def::Mod(_) | |
273 | Def::ForeignMod(_) => Some(recorder::ModRef), | |
274 | Def::Struct(..) => Some(recorder::TypeRef), | |
275 | Def::Enum(..) | | |
276 | Def::TyAlias(..) | | |
277 | Def::AssociatedTy(..) | | |
278 | Def::Trait(_) => Some(recorder::TypeRef), | |
279 | Def::Static(_, _) | | |
280 | Def::Const(_) | | |
281 | Def::AssociatedConst(..) | | |
282 | Def::Local(..) | | |
283 | Def::Variant(..) | | |
284 | Def::Upvar(..) => Some(recorder::VarRef), | |
285 | ||
286 | Def::Fn(..) => Some(recorder::FnRef), | |
287 | ||
288 | Def::SelfTy(..) | | |
289 | Def::Label(_) | | |
290 | Def::TyParam(..) | | |
291 | Def::Method(..) | | |
292 | Def::PrimTy(_) | | |
293 | Def::Err => { | |
b039eaaf SL |
294 | self.sess.span_bug(span, |
295 | &format!("lookup_def_kind for unexpected item: {:?}", def)); | |
e9174d1e | 296 | } |
d9579d0f AL |
297 | } |
298 | } | |
299 | ||
300 | fn process_formals(&mut self, formals: &Vec<ast::Arg>, qualname: &str) { | |
301 | for arg in formals { | |
302 | self.visit_pat(&arg.pat); | |
303 | let mut collector = PathCollector::new(); | |
304 | collector.visit_pat(&arg.pat); | |
305 | let span_utils = self.span.clone(); | |
306 | for &(id, ref p, _, _) in &collector.collected_paths { | |
62682a34 | 307 | let typ = self.tcx.node_types().get(&id).unwrap().to_string(); |
d9579d0f AL |
308 | // get the span only for the name of the variable (I hope the path is only ever a |
309 | // variable name, but who knows?) | |
310 | self.fmt.formal_str(p.span, | |
311 | span_utils.span_for_last_ident(p.span), | |
312 | id, | |
313 | qualname, | |
314 | &path_to_string(p), | |
62682a34 | 315 | &typ); |
d9579d0f AL |
316 | } |
317 | } | |
318 | } | |
319 | ||
c1a9b12d SL |
320 | fn process_method(&mut self, |
321 | sig: &ast::MethodSig, | |
d9579d0f | 322 | body: Option<&ast::Block>, |
c1a9b12d SL |
323 | id: ast::NodeId, |
324 | name: ast::Name, | |
d9579d0f | 325 | span: Span) { |
c1a9b12d | 326 | debug!("process_method: {}:{}", id, name); |
d9579d0f | 327 | |
7453a54e | 328 | if let Some(method_data) = self.save_ctxt.get_method_data(id, name, span) { |
d9579d0f | 329 | |
7453a54e SL |
330 | if body.is_some() { |
331 | self.fmt.method_str(span, | |
332 | Some(method_data.span), | |
333 | method_data.id, | |
334 | &method_data.qualname, | |
335 | method_data.declaration, | |
336 | method_data.scope); | |
337 | self.process_formals(&sig.decl.inputs, &method_data.qualname); | |
338 | } else { | |
339 | self.fmt.method_decl_str(span, | |
340 | Some(method_data.span), | |
341 | method_data.id, | |
342 | &method_data.qualname, | |
343 | method_data.scope); | |
344 | } | |
345 | self.process_generic_params(&sig.generics, span, &method_data.qualname, id); | |
d9579d0f AL |
346 | } |
347 | ||
348 | // walk arg and return types | |
349 | for arg in &sig.decl.inputs { | |
350 | self.visit_ty(&arg.ty); | |
351 | } | |
352 | ||
7453a54e | 353 | if let ast::FunctionRetTy::Ty(ref ret_ty) = sig.decl.output { |
d9579d0f AL |
354 | self.visit_ty(ret_ty); |
355 | } | |
356 | ||
357 | // walk the fn body | |
358 | if let Some(body) = body { | |
359 | self.nest(id, |v| v.visit_block(body)); | |
360 | } | |
d9579d0f AL |
361 | } |
362 | ||
62682a34 SL |
363 | fn process_trait_ref(&mut self, trait_ref: &ast::TraitRef) { |
364 | let trait_ref_data = self.save_ctxt.get_trait_ref_data(trait_ref, self.cur_scope); | |
365 | if let Some(trait_ref_data) = trait_ref_data { | |
366 | self.fmt.ref_str(recorder::TypeRef, | |
367 | trait_ref.path.span, | |
368 | Some(trait_ref_data.span), | |
369 | trait_ref_data.ref_id, | |
370 | trait_ref_data.scope); | |
371 | visit::walk_path(self, &trait_ref.path); | |
d9579d0f AL |
372 | } |
373 | } | |
374 | ||
e9174d1e | 375 | fn process_struct_field_def(&mut self, field: &ast::StructField, parent_id: NodeId) { |
62682a34 SL |
376 | let field_data = self.save_ctxt.get_field_data(field, parent_id); |
377 | if let Some(field_data) = field_data { | |
62682a34 SL |
378 | self.fmt.field_str(field.span, |
379 | Some(field_data.span), | |
380 | field_data.id, | |
381 | &field_data.name, | |
382 | &field_data.qualname, | |
383 | &field_data.type_value, | |
384 | field_data.scope); | |
d9579d0f AL |
385 | } |
386 | } | |
387 | ||
388 | // Dump generic params bindings, then visit_generics | |
389 | fn process_generic_params(&mut self, | |
e9174d1e | 390 | generics: &ast::Generics, |
d9579d0f AL |
391 | full_span: Span, |
392 | prefix: &str, | |
393 | id: NodeId) { | |
394 | // We can't only use visit_generics since we don't have spans for param | |
395 | // bindings, so we reparse the full_span to get those sub spans. | |
396 | // However full span is the entire enum/fn/struct block, so we only want | |
397 | // the first few to match the number of generics we're looking for. | |
398 | let param_sub_spans = self.span.spans_for_ty_params(full_span, | |
b039eaaf | 399 | (generics.ty_params.len() as isize)); |
62682a34 | 400 | for (param, param_ss) in generics.ty_params.iter().zip(param_sub_spans) { |
d9579d0f AL |
401 | // Append $id to name to make sure each one is unique |
402 | let name = format!("{}::{}${}", | |
403 | prefix, | |
62682a34 | 404 | escape(self.span.snippet(param_ss)), |
d9579d0f | 405 | id); |
b039eaaf | 406 | self.fmt.typedef_str(full_span, Some(param_ss), param.id, &name, ""); |
d9579d0f AL |
407 | } |
408 | self.visit_generics(generics); | |
409 | } | |
410 | ||
411 | fn process_fn(&mut self, | |
412 | item: &ast::Item, | |
413 | decl: &ast::FnDecl, | |
414 | ty_params: &ast::Generics, | |
415 | body: &ast::Block) { | |
7453a54e SL |
416 | if let Some(fn_data) = self.save_ctxt.get_item_data(item) { |
417 | down_cast_data!(fn_data, FunctionData, self, item.span); | |
418 | self.fmt.fn_str(item.span, | |
419 | Some(fn_data.span), | |
420 | fn_data.id, | |
421 | &fn_data.qualname, | |
422 | fn_data.scope); | |
423 | ||
424 | self.process_formals(&decl.inputs, &fn_data.qualname); | |
425 | self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id); | |
426 | } | |
d9579d0f AL |
427 | |
428 | for arg in &decl.inputs { | |
429 | self.visit_ty(&arg.ty); | |
430 | } | |
431 | ||
7453a54e | 432 | if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output { |
d9579d0f AL |
433 | self.visit_ty(&ret_ty); |
434 | } | |
435 | ||
436 | self.nest(item.id, |v| v.visit_block(&body)); | |
437 | } | |
438 | ||
e9174d1e | 439 | fn process_static_or_const_item(&mut self, item: &ast::Item, typ: &ast::Ty, expr: &ast::Expr) { |
7453a54e SL |
440 | if let Some(var_data) = self.save_ctxt.get_item_data(item) { |
441 | down_cast_data!(var_data, VariableData, self, item.span); | |
442 | self.fmt.static_str(item.span, | |
443 | Some(var_data.span), | |
444 | var_data.id, | |
445 | &var_data.name, | |
446 | &var_data.qualname, | |
447 | &var_data.value, | |
448 | &var_data.type_value, | |
449 | var_data.scope); | |
450 | } | |
d9579d0f AL |
451 | self.visit_ty(&typ); |
452 | self.visit_expr(expr); | |
453 | } | |
454 | ||
455 | fn process_const(&mut self, | |
456 | id: ast::NodeId, | |
b039eaaf | 457 | name: ast::Name, |
d9579d0f AL |
458 | span: Span, |
459 | typ: &ast::Ty, | |
e9174d1e | 460 | expr: &ast::Expr) { |
62682a34 | 461 | let qualname = format!("::{}", self.tcx.map.path_to_string(id)); |
d9579d0f | 462 | |
b039eaaf | 463 | let sub_span = self.span.sub_span_after_keyword(span, keywords::Const); |
d9579d0f AL |
464 | |
465 | self.fmt.static_str(span, | |
466 | sub_span, | |
467 | id, | |
b039eaaf | 468 | &name.as_str(), |
62682a34 | 469 | &qualname, |
d9579d0f | 470 | &self.span.snippet(expr.span), |
7453a54e | 471 | &ty_to_string(&typ), |
d9579d0f AL |
472 | self.cur_scope); |
473 | ||
474 | // walk type and init value | |
475 | self.visit_ty(typ); | |
476 | self.visit_expr(expr); | |
477 | } | |
478 | ||
479 | fn process_struct(&mut self, | |
480 | item: &ast::Item, | |
b039eaaf | 481 | def: &ast::VariantData, |
d9579d0f | 482 | ty_params: &ast::Generics) { |
62682a34 | 483 | let qualname = format!("::{}", self.tcx.map.path_to_string(item.id)); |
d9579d0f | 484 | |
d9579d0f AL |
485 | let val = self.span.snippet(item.span); |
486 | let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct); | |
487 | self.fmt.struct_str(item.span, | |
488 | sub_span, | |
489 | item.id, | |
b039eaaf | 490 | def.id(), |
62682a34 | 491 | &qualname, |
d9579d0f | 492 | self.cur_scope, |
62682a34 | 493 | &val); |
d9579d0f AL |
494 | |
495 | // fields | |
b039eaaf | 496 | for field in def.fields() { |
62682a34 SL |
497 | self.process_struct_field_def(field, item.id); |
498 | self.visit_ty(&field.node.ty); | |
d9579d0f AL |
499 | } |
500 | ||
62682a34 | 501 | self.process_generic_params(ty_params, item.span, &qualname, item.id); |
d9579d0f AL |
502 | } |
503 | ||
504 | fn process_enum(&mut self, | |
505 | item: &ast::Item, | |
506 | enum_definition: &ast::EnumDef, | |
507 | ty_params: &ast::Generics) { | |
62682a34 | 508 | let enum_data = self.save_ctxt.get_item_data(item); |
7453a54e SL |
509 | let enum_data = match enum_data { |
510 | None => return, | |
511 | Some(data) => data, | |
512 | }; | |
62682a34 SL |
513 | down_cast_data!(enum_data, EnumData, self, item.span); |
514 | self.fmt.enum_str(item.span, | |
515 | Some(enum_data.span), | |
516 | enum_data.id, | |
517 | &enum_data.qualname, | |
518 | enum_data.scope, | |
519 | &enum_data.value); | |
520 | ||
d9579d0f | 521 | for variant in &enum_definition.variants { |
c1a9b12d | 522 | let name = &variant.node.name.name.as_str(); |
62682a34 | 523 | let mut qualname = enum_data.qualname.clone(); |
d9579d0f AL |
524 | qualname.push_str("::"); |
525 | qualname.push_str(name); | |
526 | let val = self.span.snippet(variant.span); | |
b039eaaf | 527 | |
7453a54e SL |
528 | match variant.node.data { |
529 | ast::VariantData::Struct(..) => { | |
530 | self.fmt.struct_variant_str(variant.span, | |
531 | self.span.span_for_first_ident(variant.span), | |
532 | variant.node.data.id(), | |
533 | &qualname, | |
534 | &enum_data.qualname, | |
535 | &val, | |
536 | enum_data.scope); | |
537 | } | |
538 | _ => { | |
539 | self.fmt.tuple_variant_str(variant.span, | |
540 | self.span.span_for_first_ident(variant.span), | |
541 | variant.node.data.id(), | |
542 | name, | |
543 | &qualname, | |
544 | &enum_data.qualname, | |
545 | &val, | |
546 | enum_data.scope); | |
547 | } | |
548 | } | |
549 | ||
b039eaaf SL |
550 | |
551 | for field in variant.node.data.fields() { | |
552 | self.process_struct_field_def(field, variant.node.data.id()); | |
7453a54e | 553 | self.visit_ty(&field.node.ty); |
d9579d0f AL |
554 | } |
555 | } | |
62682a34 | 556 | self.process_generic_params(ty_params, item.span, &enum_data.qualname, enum_data.id); |
d9579d0f AL |
557 | } |
558 | ||
559 | fn process_impl(&mut self, | |
560 | item: &ast::Item, | |
561 | type_parameters: &ast::Generics, | |
562 | trait_ref: &Option<ast::TraitRef>, | |
563 | typ: &ast::Ty, | |
7453a54e SL |
564 | impl_items: &[ast::ImplItem]) { |
565 | let mut has_self_ref = false; | |
566 | if let Some(impl_data) = self.save_ctxt.get_item_data(item) { | |
567 | down_cast_data!(impl_data, ImplData, self, item.span); | |
568 | if let Some(ref self_ref) = impl_data.self_ref { | |
569 | has_self_ref = true; | |
62682a34 SL |
570 | self.fmt.ref_str(recorder::TypeRef, |
571 | item.span, | |
572 | Some(self_ref.span), | |
573 | self_ref.ref_id, | |
574 | self_ref.scope); | |
575 | } | |
7453a54e SL |
576 | if let Some(ref trait_ref_data) = impl_data.trait_ref { |
577 | self.fmt.ref_str(recorder::TypeRef, | |
578 | item.span, | |
579 | Some(trait_ref_data.span), | |
580 | trait_ref_data.ref_id, | |
581 | trait_ref_data.scope); | |
582 | visit::walk_path(self, &trait_ref.as_ref().unwrap().path); | |
d9579d0f | 583 | } |
7453a54e SL |
584 | |
585 | self.fmt.impl_str(item.span, | |
586 | Some(impl_data.span), | |
587 | impl_data.id, | |
588 | impl_data.self_ref.map(|data| data.ref_id), | |
589 | impl_data.trait_ref.map(|data| data.ref_id), | |
590 | impl_data.scope); | |
d9579d0f | 591 | } |
7453a54e SL |
592 | if !has_self_ref { |
593 | self.visit_ty(&typ); | |
d9579d0f | 594 | } |
d9579d0f AL |
595 | self.process_generic_params(type_parameters, item.span, "", item.id); |
596 | for impl_item in impl_items { | |
597 | self.visit_impl_item(impl_item); | |
598 | } | |
599 | } | |
600 | ||
601 | fn process_trait(&mut self, | |
602 | item: &ast::Item, | |
603 | generics: &ast::Generics, | |
9cc50fc6 | 604 | trait_refs: &ast::TyParamBounds, |
7453a54e | 605 | methods: &[ast::TraitItem]) { |
62682a34 | 606 | let qualname = format!("::{}", self.tcx.map.path_to_string(item.id)); |
d9579d0f AL |
607 | let val = self.span.snippet(item.span); |
608 | let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait); | |
609 | self.fmt.trait_str(item.span, | |
610 | sub_span, | |
611 | item.id, | |
62682a34 | 612 | &qualname, |
d9579d0f | 613 | self.cur_scope, |
62682a34 | 614 | &val); |
d9579d0f AL |
615 | |
616 | // super-traits | |
62682a34 | 617 | for super_bound in trait_refs.iter() { |
d9579d0f AL |
618 | let trait_ref = match *super_bound { |
619 | ast::TraitTyParamBound(ref trait_ref, _) => { | |
620 | trait_ref | |
621 | } | |
622 | ast::RegionTyParamBound(..) => { | |
623 | continue; | |
624 | } | |
625 | }; | |
626 | ||
627 | let trait_ref = &trait_ref.trait_ref; | |
628 | match self.lookup_type_ref(trait_ref.ref_id) { | |
629 | Some(id) => { | |
630 | let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span); | |
631 | self.fmt.ref_str(recorder::TypeRef, | |
632 | trait_ref.path.span, | |
633 | sub_span, | |
634 | id, | |
635 | self.cur_scope); | |
b039eaaf | 636 | self.fmt.inherit_str(trait_ref.path.span, sub_span, id, item.id); |
e9174d1e SL |
637 | } |
638 | None => (), | |
d9579d0f AL |
639 | } |
640 | } | |
641 | ||
642 | // walk generics and methods | |
62682a34 | 643 | self.process_generic_params(generics, item.span, &qualname, item.id); |
d9579d0f AL |
644 | for method in methods { |
645 | self.visit_trait_item(method) | |
646 | } | |
647 | } | |
648 | ||
e9174d1e SL |
649 | // `item` is the module in question, represented as an item. |
650 | fn process_mod(&mut self, item: &ast::Item) { | |
7453a54e SL |
651 | if let Some(mod_data) = self.save_ctxt.get_item_data(item) { |
652 | down_cast_data!(mod_data, ModData, self, item.span); | |
653 | self.fmt.mod_str(item.span, | |
654 | Some(mod_data.span), | |
655 | mod_data.id, | |
656 | &mod_data.qualname, | |
657 | mod_data.scope, | |
658 | &mod_data.filename); | |
659 | } | |
d9579d0f AL |
660 | } |
661 | ||
e9174d1e | 662 | fn process_path(&mut self, id: NodeId, path: &ast::Path, ref_kind: Option<recorder::Row>) { |
7453a54e SL |
663 | let path_data = self.save_ctxt.get_path_data(id, path); |
664 | if generated_code(path.span) && path_data.is_none() { | |
c1a9b12d | 665 | return; |
d9579d0f AL |
666 | } |
667 | ||
c1a9b12d SL |
668 | let path_data = match path_data { |
669 | Some(pd) => pd, | |
670 | None => { | |
671 | self.tcx.sess.span_bug(path.span, | |
b039eaaf SL |
672 | &format!("Unexpected def kind while looking up path in \ |
673 | `{}`", | |
c1a9b12d SL |
674 | self.span.snippet(path.span))) |
675 | } | |
676 | }; | |
677 | match path_data { | |
678 | Data::VariableRefData(ref vrd) => { | |
679 | self.fmt.ref_str(ref_kind.unwrap_or(recorder::VarRef), | |
b039eaaf SL |
680 | path.span, |
681 | Some(vrd.span), | |
682 | vrd.ref_id, | |
683 | vrd.scope); | |
c1a9b12d SL |
684 | |
685 | } | |
686 | Data::TypeRefData(ref trd) => { | |
687 | self.fmt.ref_str(recorder::TypeRef, | |
688 | path.span, | |
689 | Some(trd.span), | |
690 | trd.ref_id, | |
691 | trd.scope); | |
692 | } | |
693 | Data::MethodCallData(ref mcd) => { | |
694 | self.fmt.meth_call_str(path.span, | |
695 | Some(mcd.span), | |
696 | mcd.ref_id, | |
697 | mcd.decl_id, | |
698 | mcd.scope); | |
699 | } | |
700 | Data::FunctionCallData(fcd) => { | |
b039eaaf | 701 | self.fmt.fn_call_str(path.span, Some(fcd.span), fcd.ref_id, fcd.scope); |
c1a9b12d SL |
702 | } |
703 | _ => { | |
704 | self.sess.span_bug(path.span, | |
705 | &format!("Unexpected data: {:?}", path_data)); | |
d9579d0f | 706 | } |
d9579d0f | 707 | } |
c1a9b12d SL |
708 | |
709 | // Modules or types in the path prefix. | |
710 | let def_map = self.tcx.def_map.borrow(); | |
711 | let def = def_map.get(&id).unwrap().full_def(); | |
d9579d0f | 712 | match def { |
7453a54e | 713 | Def::Method(did) => { |
c1a9b12d | 714 | let ti = self.tcx.impl_or_trait_item(did); |
d9579d0f | 715 | if let ty::MethodTraitItem(m) = ti { |
9cc50fc6 | 716 | if m.explicit_self == ty::ExplicitSelfCategory::Static { |
d9579d0f AL |
717 | self.write_sub_path_trait_truncated(path); |
718 | } | |
719 | } | |
720 | } | |
7453a54e SL |
721 | Def::Local(..) | |
722 | Def::Static(_,_) | | |
723 | Def::Const(..) | | |
724 | Def::AssociatedConst(..) | | |
725 | Def::Struct(..) | | |
726 | Def::Variant(..) | | |
727 | Def::Fn(..) => self.write_sub_paths_truncated(path, false), | |
e9174d1e | 728 | _ => {} |
d9579d0f AL |
729 | } |
730 | } | |
731 | ||
732 | fn process_struct_lit(&mut self, | |
733 | ex: &ast::Expr, | |
734 | path: &ast::Path, | |
735 | fields: &Vec<ast::Field>, | |
e9174d1e | 736 | variant: ty::VariantDef, |
d9579d0f | 737 | base: &Option<P<ast::Expr>>) { |
d9579d0f AL |
738 | self.write_sub_paths_truncated(path, false); |
739 | ||
62682a34 SL |
740 | if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) { |
741 | down_cast_data!(struct_lit_data, TypeRefData, self, ex.span); | |
742 | self.fmt.ref_str(recorder::TypeRef, | |
743 | ex.span, | |
744 | Some(struct_lit_data.span), | |
745 | struct_lit_data.ref_id, | |
746 | struct_lit_data.scope); | |
c1a9b12d | 747 | let scope = self.save_ctxt.enclosing_scope(ex.id); |
62682a34 SL |
748 | |
749 | for field in fields { | |
7453a54e SL |
750 | if let Some(field_data) = self.save_ctxt |
751 | .get_field_ref_data(field, variant, scope) { | |
d9579d0f | 752 | |
7453a54e SL |
753 | self.fmt.ref_str(recorder::VarRef, |
754 | field.ident.span, | |
755 | Some(field_data.span), | |
756 | field_data.ref_id, | |
757 | field_data.scope); | |
758 | } | |
62682a34 SL |
759 | |
760 | self.visit_expr(&field.expr) | |
761 | } | |
d9579d0f | 762 | } |
62682a34 | 763 | |
b039eaaf | 764 | walk_list!(self, visit_expr, base); |
d9579d0f AL |
765 | } |
766 | ||
e9174d1e | 767 | fn process_method_call(&mut self, ex: &ast::Expr, args: &Vec<P<ast::Expr>>) { |
c1a9b12d SL |
768 | if let Some(call_data) = self.save_ctxt.get_expr_data(ex) { |
769 | down_cast_data!(call_data, MethodCallData, self, ex.span); | |
770 | self.fmt.meth_call_str(ex.span, | |
771 | Some(call_data.span), | |
772 | call_data.ref_id, | |
773 | call_data.decl_id, | |
774 | call_data.scope); | |
775 | } | |
d9579d0f AL |
776 | |
777 | // walk receiver and args | |
b039eaaf | 778 | walk_list!(self, visit_expr, args); |
d9579d0f AL |
779 | } |
780 | ||
e9174d1e | 781 | fn process_pat(&mut self, p: &ast::Pat) { |
d9579d0f | 782 | match p.node { |
7453a54e | 783 | PatKind::Struct(ref path, ref fields, _) => { |
d9579d0f | 784 | visit::walk_path(self, path); |
e9174d1e SL |
785 | let adt = self.tcx.node_id_to_type(p.id).ty_adt_def().unwrap(); |
786 | let def = self.tcx.def_map.borrow()[&p.id].full_def(); | |
787 | let variant = adt.variant_of_def(def); | |
d9579d0f | 788 | |
e9174d1e | 789 | for &Spanned { node: ref field, span } in fields { |
e9174d1e SL |
790 | let sub_span = self.span.span_for_first_ident(span); |
791 | if let Some(f) = variant.find_field_named(field.ident.name) { | |
b039eaaf | 792 | self.fmt.ref_str(recorder::VarRef, span, sub_span, f.did, self.cur_scope); |
d9579d0f | 793 | } |
e9174d1e | 794 | self.visit_pat(&field.pat); |
d9579d0f AL |
795 | } |
796 | } | |
e9174d1e | 797 | _ => visit::walk_pat(self, p), |
d9579d0f AL |
798 | } |
799 | } | |
b039eaaf SL |
800 | |
801 | ||
802 | fn process_var_decl(&mut self, p: &ast::Pat, value: String) { | |
803 | // The local could declare multiple new vars, we must walk the | |
804 | // pattern and collect them all. | |
805 | let mut collector = PathCollector::new(); | |
806 | collector.visit_pat(&p); | |
807 | self.visit_pat(&p); | |
808 | ||
809 | for &(id, ref p, immut, _) in &collector.collected_paths { | |
7453a54e | 810 | let value = if immut == ast::Mutability::Immutable { |
b039eaaf SL |
811 | value.to_string() |
812 | } else { | |
813 | "<mutable>".to_string() | |
814 | }; | |
815 | let types = self.tcx.node_types(); | |
7453a54e | 816 | let typ = types.get(&id).map(|t| t.to_string()).unwrap_or(String::new()); |
b039eaaf SL |
817 | // Get the span only for the name of the variable (I hope the path |
818 | // is only ever a variable name, but who knows?). | |
819 | let sub_span = self.span.span_for_last_ident(p.span); | |
820 | // Rust uses the id of the pattern for var lookups, so we'll use it too. | |
821 | self.fmt.variable_str(p.span, | |
822 | sub_span, | |
823 | id, | |
824 | &path_to_string(p), | |
825 | &value, | |
826 | &typ); | |
827 | } | |
828 | } | |
7453a54e SL |
829 | |
830 | /// Extract macro use and definition information from the AST node defined | |
831 | /// by the given NodeId, using the expansion information from the node's | |
832 | /// span. | |
833 | /// | |
834 | /// If the span is not macro-generated, do nothing, else use callee and | |
835 | /// callsite spans to record macro definition and use data, using the | |
836 | /// mac_uses and mac_defs sets to prevent multiples. | |
837 | fn process_macro_use(&mut self, span: Span, id: NodeId) { | |
838 | let data = match self.save_ctxt.get_macro_use_data(span, id) { | |
839 | None => return, | |
840 | Some(data) => data, | |
841 | }; | |
842 | let mut hasher = SipHasher::new(); | |
843 | data.callee_span.hash(&mut hasher); | |
844 | let hash = hasher.finish(); | |
845 | let qualname = format!("{}::{}", data.name, hash); | |
846 | // Don't write macro definition for imported macros | |
847 | if !self.mac_defs.contains(&data.callee_span) | |
848 | && !data.imported { | |
849 | self.mac_defs.insert(data.callee_span); | |
850 | if let Some(sub_span) = self.span.span_for_macro_def_name(data.callee_span) { | |
851 | self.fmt.macro_str(data.callee_span, sub_span, | |
852 | data.name.clone(), qualname.clone()); | |
853 | } | |
854 | } | |
855 | if !self.mac_uses.contains(&data.span) { | |
856 | self.mac_uses.insert(data.span); | |
857 | if let Some(sub_span) = self.span.span_for_macro_use_name(data.span) { | |
858 | self.fmt.macro_use_str(data.span, sub_span, data.name, | |
859 | qualname, data.scope); | |
860 | } | |
861 | } | |
862 | } | |
d9579d0f AL |
863 | } |
864 | ||
865 | impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { | |
866 | fn visit_item(&mut self, item: &ast::Item) { | |
7453a54e SL |
867 | use syntax::ast::ItemKind::*; |
868 | self.process_macro_use(item.span, item.id); | |
d9579d0f | 869 | match item.node { |
7453a54e | 870 | Use(ref use_item) => { |
d9579d0f AL |
871 | match use_item.node { |
872 | ast::ViewPathSimple(ident, ref path) => { | |
873 | let sub_span = self.span.span_for_last_ident(path.span); | |
874 | let mod_id = match self.lookup_type_ref(item.id) { | |
875 | Some(def_id) => { | |
876 | match self.lookup_def_kind(item.id, path.span) { | |
877 | Some(kind) => self.fmt.ref_str(kind, | |
878 | path.span, | |
879 | sub_span, | |
880 | def_id, | |
881 | self.cur_scope), | |
e9174d1e | 882 | None => {} |
d9579d0f AL |
883 | } |
884 | Some(def_id) | |
e9174d1e | 885 | } |
d9579d0f AL |
886 | None => None, |
887 | }; | |
888 | ||
889 | // 'use' always introduces an alias, if there is not an explicit | |
890 | // one, there is an implicit one. | |
b039eaaf SL |
891 | let sub_span = match self.span.sub_span_after_keyword(use_item.span, |
892 | keywords::As) { | |
893 | Some(sub_span) => Some(sub_span), | |
894 | None => sub_span, | |
895 | }; | |
d9579d0f AL |
896 | |
897 | self.fmt.use_alias_str(path.span, | |
898 | sub_span, | |
899 | item.id, | |
900 | mod_id, | |
c1a9b12d | 901 | &ident.name.as_str(), |
d9579d0f AL |
902 | self.cur_scope); |
903 | self.write_sub_paths_truncated(path, true); | |
904 | } | |
905 | ast::ViewPathGlob(ref path) => { | |
906 | // Make a comma-separated list of names of imported modules. | |
907 | let mut name_string = String::new(); | |
908 | let glob_map = &self.analysis.glob_map; | |
909 | let glob_map = glob_map.as_ref().unwrap(); | |
910 | if glob_map.contains_key(&item.id) { | |
911 | for n in glob_map.get(&item.id).unwrap() { | |
912 | if !name_string.is_empty() { | |
913 | name_string.push_str(", "); | |
914 | } | |
c1a9b12d | 915 | name_string.push_str(&n.as_str()); |
d9579d0f AL |
916 | } |
917 | } | |
918 | ||
b039eaaf SL |
919 | let sub_span = self.span |
920 | .sub_span_of_token(path.span, token::BinOp(token::Star)); | |
d9579d0f AL |
921 | self.fmt.use_glob_str(path.span, |
922 | sub_span, | |
923 | item.id, | |
924 | &name_string, | |
925 | self.cur_scope); | |
926 | self.write_sub_paths(path, true); | |
927 | } | |
928 | ast::ViewPathList(ref path, ref list) => { | |
929 | for plid in list { | |
930 | match plid.node { | |
7453a54e | 931 | ast::PathListItemKind::Ident { id, .. } => { |
d9579d0f | 932 | match self.lookup_type_ref(id) { |
e9174d1e SL |
933 | Some(def_id) => match self.lookup_def_kind(id, plid.span) { |
934 | Some(kind) => { | |
b039eaaf SL |
935 | self.fmt.ref_str(kind, |
936 | plid.span, | |
937 | Some(plid.span), | |
938 | def_id, | |
939 | self.cur_scope); | |
e9174d1e SL |
940 | } |
941 | None => (), | |
942 | }, | |
943 | None => (), | |
d9579d0f | 944 | } |
e9174d1e | 945 | } |
7453a54e | 946 | ast::PathListItemKind::Mod { .. } => (), |
d9579d0f AL |
947 | } |
948 | } | |
949 | ||
950 | self.write_sub_paths(path, true); | |
951 | } | |
952 | } | |
953 | } | |
7453a54e | 954 | ExternCrate(ref s) => { |
d9579d0f AL |
955 | let location = match *s { |
956 | Some(s) => s.to_string(), | |
c1a9b12d | 957 | None => item.ident.to_string(), |
d9579d0f AL |
958 | }; |
959 | let alias_span = self.span.span_for_last_ident(item.span); | |
92a42be0 | 960 | let cnum = match self.sess.cstore.extern_mod_stmt_cnum(item.id) { |
d9579d0f AL |
961 | Some(cnum) => cnum, |
962 | None => 0, | |
963 | }; | |
964 | self.fmt.extern_crate_str(item.span, | |
965 | alias_span, | |
966 | item.id, | |
967 | cnum, | |
c1a9b12d | 968 | &item.ident.name.as_str(), |
62682a34 | 969 | &location, |
d9579d0f AL |
970 | self.cur_scope); |
971 | } | |
7453a54e SL |
972 | Fn(ref decl, _, _, _, ref ty_params, ref body) => |
973 | self.process_fn(item, &decl, ty_params, &body), | |
974 | Static(ref typ, _, ref expr) => | |
d9579d0f | 975 | self.process_static_or_const_item(item, typ, expr), |
7453a54e | 976 | Const(ref typ, ref expr) => |
d9579d0f | 977 | self.process_static_or_const_item(item, &typ, &expr), |
7453a54e SL |
978 | Struct(ref def, ref ty_params) => self.process_struct(item, def, ty_params), |
979 | Enum(ref def, ref ty_params) => self.process_enum(item, def, ty_params), | |
980 | Impl(_, _, | |
d9579d0f AL |
981 | ref ty_params, |
982 | ref trait_ref, | |
983 | ref typ, | |
984 | ref impl_items) => { | |
b039eaaf | 985 | self.process_impl(item, ty_params, trait_ref, &typ, impl_items) |
d9579d0f | 986 | } |
7453a54e | 987 | Trait(_, ref generics, ref trait_refs, ref methods) => |
d9579d0f | 988 | self.process_trait(item, generics, trait_refs, methods), |
7453a54e | 989 | Mod(ref m) => { |
62682a34 SL |
990 | self.process_mod(item); |
991 | self.nest(item.id, |v| visit::walk_mod(v, m)); | |
992 | } | |
7453a54e | 993 | Ty(ref ty, ref ty_params) => { |
62682a34 | 994 | let qualname = format!("::{}", self.tcx.map.path_to_string(item.id)); |
7453a54e | 995 | let value = ty_to_string(&ty); |
d9579d0f | 996 | let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type); |
b039eaaf | 997 | self.fmt.typedef_str(item.span, sub_span, item.id, &qualname, &value); |
d9579d0f | 998 | |
7453a54e | 999 | self.visit_ty(&ty); |
d9579d0f | 1000 | self.process_generic_params(ty_params, item.span, &qualname, item.id); |
e9174d1e | 1001 | } |
7453a54e | 1002 | Mac(_) => (), |
d9579d0f AL |
1003 | _ => visit::walk_item(self, item), |
1004 | } | |
1005 | } | |
1006 | ||
1007 | fn visit_generics(&mut self, generics: &ast::Generics) { | |
62682a34 SL |
1008 | for param in generics.ty_params.iter() { |
1009 | for bound in param.bounds.iter() { | |
d9579d0f AL |
1010 | if let ast::TraitTyParamBound(ref trait_ref, _) = *bound { |
1011 | self.process_trait_ref(&trait_ref.trait_ref); | |
1012 | } | |
1013 | } | |
1014 | if let Some(ref ty) = param.default { | |
7453a54e | 1015 | self.visit_ty(&ty); |
d9579d0f AL |
1016 | } |
1017 | } | |
1018 | } | |
1019 | ||
1020 | fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) { | |
7453a54e | 1021 | self.process_macro_use(trait_item.span, trait_item.id); |
d9579d0f | 1022 | match trait_item.node { |
7453a54e | 1023 | ast::TraitItemKind::Const(ref ty, Some(ref expr)) => { |
b039eaaf SL |
1024 | self.process_const(trait_item.id, |
1025 | trait_item.ident.name, | |
1026 | trait_item.span, | |
7453a54e SL |
1027 | &ty, |
1028 | &expr); | |
d9579d0f | 1029 | } |
7453a54e | 1030 | ast::TraitItemKind::Method(ref sig, ref body) => { |
c1a9b12d SL |
1031 | self.process_method(sig, |
1032 | body.as_ref().map(|x| &**x), | |
1033 | trait_item.id, | |
1034 | trait_item.ident.name, | |
1035 | trait_item.span); | |
d9579d0f | 1036 | } |
7453a54e SL |
1037 | ast::TraitItemKind::Const(_, None) | |
1038 | ast::TraitItemKind::Type(..) => {} | |
d9579d0f AL |
1039 | } |
1040 | } | |
1041 | ||
1042 | fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) { | |
7453a54e | 1043 | self.process_macro_use(impl_item.span, impl_item.id); |
d9579d0f | 1044 | match impl_item.node { |
92a42be0 | 1045 | ast::ImplItemKind::Const(ref ty, ref expr) => { |
b039eaaf SL |
1046 | self.process_const(impl_item.id, |
1047 | impl_item.ident.name, | |
1048 | impl_item.span, | |
1049 | &ty, | |
1050 | &expr); | |
d9579d0f | 1051 | } |
92a42be0 | 1052 | ast::ImplItemKind::Method(ref sig, ref body) => { |
c1a9b12d SL |
1053 | self.process_method(sig, |
1054 | Some(body), | |
1055 | impl_item.id, | |
1056 | impl_item.ident.name, | |
1057 | impl_item.span); | |
d9579d0f | 1058 | } |
92a42be0 SL |
1059 | ast::ImplItemKind::Type(_) | |
1060 | ast::ImplItemKind::Macro(_) => {} | |
d9579d0f AL |
1061 | } |
1062 | } | |
1063 | ||
1064 | fn visit_ty(&mut self, t: &ast::Ty) { | |
7453a54e | 1065 | self.process_macro_use(t.span, t.id); |
d9579d0f | 1066 | match t.node { |
7453a54e | 1067 | ast::TyKind::Path(_, ref path) => { |
d9579d0f AL |
1068 | match self.lookup_type_ref(t.id) { |
1069 | Some(id) => { | |
1070 | let sub_span = self.span.sub_span_for_type_name(t.span); | |
b039eaaf | 1071 | self.fmt.ref_str(recorder::TypeRef, t.span, sub_span, id, self.cur_scope); |
e9174d1e SL |
1072 | } |
1073 | None => (), | |
d9579d0f AL |
1074 | } |
1075 | ||
1076 | self.write_sub_paths_truncated(path, false); | |
1077 | ||
1078 | visit::walk_path(self, path); | |
e9174d1e | 1079 | } |
d9579d0f AL |
1080 | _ => visit::walk_ty(self, t), |
1081 | } | |
1082 | } | |
1083 | ||
1084 | fn visit_expr(&mut self, ex: &ast::Expr) { | |
7453a54e | 1085 | self.process_macro_use(ex.span, ex.id); |
d9579d0f | 1086 | match ex.node { |
7453a54e | 1087 | ast::ExprKind::Call(ref _f, ref _args) => { |
d9579d0f AL |
1088 | // Don't need to do anything for function calls, |
1089 | // because just walking the callee path does what we want. | |
1090 | visit::walk_expr(self, ex); | |
1091 | } | |
7453a54e | 1092 | ast::ExprKind::Path(_, ref path) => { |
c1a9b12d | 1093 | self.process_path(ex.id, path, None); |
d9579d0f AL |
1094 | visit::walk_expr(self, ex); |
1095 | } | |
7453a54e | 1096 | ast::ExprKind::Struct(ref path, ref fields, ref base) => { |
b039eaaf | 1097 | let hir_expr = lower_expr(self.save_ctxt.lcx, ex); |
e9174d1e SL |
1098 | let adt = self.tcx.expr_ty(&hir_expr).ty_adt_def().unwrap(); |
1099 | let def = self.tcx.resolve_expr(&hir_expr); | |
b039eaaf | 1100 | self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base) |
e9174d1e | 1101 | } |
7453a54e SL |
1102 | ast::ExprKind::MethodCall(_, _, ref args) => self.process_method_call(ex, args), |
1103 | ast::ExprKind::Field(ref sub_ex, _) => { | |
62682a34 SL |
1104 | self.visit_expr(&sub_ex); |
1105 | ||
1106 | if let Some(field_data) = self.save_ctxt.get_expr_data(ex) { | |
1107 | down_cast_data!(field_data, VariableRefData, self, ex.span); | |
1108 | self.fmt.ref_str(recorder::VarRef, | |
1109 | ex.span, | |
1110 | Some(field_data.span), | |
1111 | field_data.ref_id, | |
1112 | field_data.scope); | |
d9579d0f | 1113 | } |
e9174d1e | 1114 | } |
7453a54e SL |
1115 | ast::ExprKind::TupField(ref sub_ex, idx) => { |
1116 | self.visit_expr(&sub_ex); | |
d9579d0f | 1117 | |
b039eaaf | 1118 | let hir_node = lower_expr(self.save_ctxt.lcx, sub_ex); |
e9174d1e | 1119 | let ty = &self.tcx.expr_ty_adjusted(&hir_node).sty; |
d9579d0f | 1120 | match *ty { |
e9174d1e SL |
1121 | ty::TyStruct(def, _) => { |
1122 | let sub_span = self.span.sub_span_after_token(ex.span, token::Dot); | |
1123 | self.fmt.ref_str(recorder::VarRef, | |
1124 | ex.span, | |
1125 | sub_span, | |
1126 | def.struct_variant().fields[idx.node].did, | |
1127 | self.cur_scope); | |
d9579d0f | 1128 | } |
62682a34 | 1129 | ty::TyTuple(_) => {} |
d9579d0f | 1130 | _ => self.sess.span_bug(ex.span, |
b039eaaf SL |
1131 | &format!("Expected struct or tuple type, found {:?}", |
1132 | ty)), | |
d9579d0f | 1133 | } |
e9174d1e | 1134 | } |
7453a54e | 1135 | ast::ExprKind::Closure(_, ref decl, ref body) => { |
62682a34 | 1136 | let mut id = String::from("$"); |
d9579d0f | 1137 | id.push_str(&ex.id.to_string()); |
62682a34 | 1138 | self.process_formals(&decl.inputs, &id); |
d9579d0f AL |
1139 | |
1140 | // walk arg and return types | |
1141 | for arg in &decl.inputs { | |
7453a54e | 1142 | self.visit_ty(&arg.ty); |
d9579d0f AL |
1143 | } |
1144 | ||
7453a54e SL |
1145 | if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output { |
1146 | self.visit_ty(&ret_ty); | |
d9579d0f AL |
1147 | } |
1148 | ||
1149 | // walk the body | |
7453a54e | 1150 | self.nest(ex.id, |v| v.visit_block(&body)); |
e9174d1e | 1151 | } |
7453a54e SL |
1152 | ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) | |
1153 | ast::ExprKind::WhileLet(ref pattern, ref subexpression, ref block, _) => { | |
b039eaaf SL |
1154 | let value = self.span.snippet(mk_sp(ex.span.lo, subexpression.span.hi)); |
1155 | self.process_var_decl(pattern, value); | |
1156 | visit::walk_expr(self, subexpression); | |
1157 | visit::walk_block(self, block); | |
1158 | } | |
7453a54e | 1159 | ast::ExprKind::IfLet(ref pattern, ref subexpression, ref block, ref opt_else) => { |
b039eaaf SL |
1160 | let value = self.span.snippet(mk_sp(ex.span.lo, subexpression.span.hi)); |
1161 | self.process_var_decl(pattern, value); | |
1162 | visit::walk_expr(self, subexpression); | |
1163 | visit::walk_block(self, block); | |
1164 | opt_else.as_ref().map(|el| visit::walk_expr(self, el)); | |
1165 | } | |
d9579d0f AL |
1166 | _ => { |
1167 | visit::walk_expr(self, ex) | |
1168 | } | |
1169 | } | |
1170 | } | |
1171 | ||
7453a54e SL |
1172 | fn visit_mac(&mut self, mac: &ast::Mac) { |
1173 | // These shouldn't exist in the AST at this point, log a span bug. | |
1174 | self.sess.span_bug(mac.span, "macro invocation should have been expanded out of AST"); | |
d9579d0f AL |
1175 | } |
1176 | ||
1177 | fn visit_pat(&mut self, p: &ast::Pat) { | |
7453a54e | 1178 | self.process_macro_use(p.span, p.id); |
d9579d0f AL |
1179 | self.process_pat(p); |
1180 | } | |
1181 | ||
1182 | fn visit_arm(&mut self, arm: &ast::Arm) { | |
1183 | let mut collector = PathCollector::new(); | |
1184 | for pattern in &arm.pats { | |
1185 | // collect paths from the arm's patterns | |
1186 | collector.visit_pat(&pattern); | |
1187 | self.visit_pat(&pattern); | |
1188 | } | |
1189 | ||
1190 | // This is to get around borrow checking, because we need mut self to call process_path. | |
1191 | let mut paths_to_process = vec![]; | |
c1a9b12d | 1192 | |
d9579d0f AL |
1193 | // process collected paths |
1194 | for &(id, ref p, immut, ref_kind) in &collector.collected_paths { | |
62682a34 | 1195 | let def_map = self.tcx.def_map.borrow(); |
d9579d0f AL |
1196 | if !def_map.contains_key(&id) { |
1197 | self.sess.span_bug(p.span, | |
b039eaaf | 1198 | &format!("def_map has no key for {} in visit_arm", id)); |
d9579d0f AL |
1199 | } |
1200 | let def = def_map.get(&id).unwrap().full_def(); | |
1201 | match def { | |
7453a54e SL |
1202 | Def::Local(_, id) => { |
1203 | let value = if immut == ast::Mutability::Immutable { | |
d9579d0f AL |
1204 | self.span.snippet(p.span).to_string() |
1205 | } else { | |
1206 | "<mutable>".to_string() | |
1207 | }; | |
1208 | ||
b039eaaf SL |
1209 | assert!(p.segments.len() == 1, |
1210 | "qualified path for local variable def in arm"); | |
1211 | self.fmt.variable_str(p.span, Some(p.span), id, &path_to_string(p), &value, "") | |
d9579d0f | 1212 | } |
7453a54e SL |
1213 | Def::Variant(..) | Def::Enum(..) | |
1214 | Def::TyAlias(..) | Def::Struct(..) => { | |
d9579d0f AL |
1215 | paths_to_process.push((id, p.clone(), Some(ref_kind))) |
1216 | } | |
1217 | // FIXME(nrc) what are these doing here? | |
7453a54e SL |
1218 | Def::Static(_, _) | |
1219 | Def::Const(..) | | |
1220 | Def::AssociatedConst(..) => {} | |
d9579d0f | 1221 | _ => error!("unexpected definition kind when processing collected paths: {:?}", |
e9174d1e | 1222 | def), |
d9579d0f AL |
1223 | } |
1224 | } | |
c1a9b12d | 1225 | |
d9579d0f | 1226 | for &(id, ref path, ref_kind) in &paths_to_process { |
c1a9b12d | 1227 | self.process_path(id, path, ref_kind); |
d9579d0f | 1228 | } |
b039eaaf | 1229 | walk_list!(self, visit_expr, &arm.guard); |
c1a9b12d | 1230 | self.visit_expr(&arm.body); |
d9579d0f AL |
1231 | } |
1232 | ||
1233 | fn visit_stmt(&mut self, s: &ast::Stmt) { | |
7453a54e SL |
1234 | let id = s.node.id(); |
1235 | self.process_macro_use(s.span, id.unwrap()); | |
d9579d0f AL |
1236 | visit::walk_stmt(self, s) |
1237 | } | |
1238 | ||
1239 | fn visit_local(&mut self, l: &ast::Local) { | |
7453a54e | 1240 | self.process_macro_use(l.span, l.id); |
d9579d0f | 1241 | let value = self.span.snippet(l.span); |
b039eaaf | 1242 | self.process_var_decl(&l.pat, value); |
d9579d0f AL |
1243 | |
1244 | // Just walk the initialiser and type (don't want to walk the pattern again). | |
b039eaaf SL |
1245 | walk_list!(self, visit_ty, &l.ty); |
1246 | walk_list!(self, visit_expr, &l.init); | |
d9579d0f AL |
1247 | } |
1248 | } |