]> git.proxmox.com Git - rustc.git/blob - src/librustc_trans/save/recorder.rs
Imported Upstream version 1.8.0+dfsg1
[rustc.git] / src / librustc_trans / save / recorder.rs
1 // Copyright 2012-2014 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 pub use self::Row::*;
12
13 use super::escape;
14 use super::span_utils::SpanUtils;
15
16 use middle::cstore::LOCAL_CRATE;
17 use middle::def_id::{CRATE_DEF_INDEX, DefId};
18 use middle::ty;
19
20 use std::io::Write;
21
22 use syntax::ast;
23 use syntax::ast::NodeId;
24 use syntax::codemap::*;
25
26 const CRATE_ROOT_DEF_ID: DefId = DefId {
27 krate: LOCAL_CRATE,
28 index: CRATE_DEF_INDEX,
29 };
30
31 pub struct Recorder {
32 // output file
33 pub out: Box<Write + 'static>,
34 pub dump_spans: bool,
35 }
36
37 impl Recorder {
38 pub fn record(&mut self, info: &str) {
39 match write!(self.out, "{}", info) {
40 Err(_) => error!("Error writing output '{}'", info),
41 _ => (),
42 }
43 }
44
45 pub fn dump_span(&mut self, su: SpanUtils, kind: &str, span: Span, _sub_span: Option<Span>) {
46 assert!(self.dump_spans);
47 let result = format!("span,kind,{},{},text,\"{}\"\n",
48 kind,
49 su.extent_str(span),
50 escape(su.snippet(span)));
51 self.record(&result[..]);
52 }
53 }
54
55 pub struct FmtStrs<'a, 'tcx: 'a> {
56 pub recorder: Box<Recorder>,
57 span: SpanUtils<'a>,
58 tcx: &'a ty::ctxt<'tcx>,
59 }
60
61 macro_rules! s { ($e:expr) => { format!("{}", $e) }}
62 macro_rules! svec {
63 ($($e:expr),*) => ({
64 // leading _ to allow empty construction without a warning.
65 let mut _temp = ::std::vec::Vec::new();
66 $(_temp.push(s!($e));)*
67 _temp
68 })
69 }
70
71 // FIXME recorder should operate on super::Data, rather than lots of ad hoc
72 // data.
73
74 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
75 pub enum Row {
76 Variable,
77 Enum,
78 Variant,
79 VariantStruct,
80 Function,
81 MethodDecl,
82 Struct,
83 Trait,
84 Impl,
85 Module,
86 UseAlias,
87 UseGlob,
88 ExternCrate,
89 Inheritance,
90 MethodCall,
91 Typedef,
92 ExternalCrate,
93 Crate,
94 FnCall,
95 ModRef,
96 VarRef,
97 TypeRef,
98 FnRef,
99 Macro,
100 MacroUse,
101 }
102
103 impl<'a, 'tcx: 'a> FmtStrs<'a, 'tcx> {
104 pub fn new(rec: Box<Recorder>,
105 span: SpanUtils<'a>,
106 tcx: &'a ty::ctxt<'tcx>)
107 -> FmtStrs<'a, 'tcx> {
108 FmtStrs {
109 recorder: rec,
110 span: span,
111 tcx: tcx,
112 }
113 }
114
115 // Emitted ids are used to cross-reference items across crates. DefIds and
116 // NodeIds do not usually correspond in any way. The strategy is to use the
117 // index from the DefId as a crate-local id. However, within a crate, DefId
118 // indices and NodeIds can overlap. So, we must adjust the NodeIds. If an
119 // item can be identified by a DefId as well as a NodeId, then we use the
120 // DefId index as the id. If it can't, then we have to use the NodeId, but
121 // need to adjust it so it will not clash with any possible DefId index.
122 fn normalize_node_id(&self, id: NodeId) -> usize {
123 match self.tcx.map.opt_local_def_id(id) {
124 Some(id) => id.index.as_usize(),
125 None => id as usize + self.tcx.map.num_local_def_ids()
126 }
127 }
128
129 // A map from kind of item to a tuple of
130 // a string representation of the name
131 // a vector of field names
132 // whether this kind requires a span
133 // whether dump_spans should dump for this kind
134 fn lookup_row(r: Row) -> (&'static str, Vec<&'static str>, bool, bool) {
135 match r {
136 Variable => ("variable",
137 vec!("id", "name", "qualname", "value", "type", "scopeid"),
138 true,
139 true),
140 Enum => ("enum",
141 vec!("id", "qualname", "scopeid", "value"),
142 true,
143 true),
144 Variant => ("variant",
145 vec!("id", "name", "qualname", "type", "value", "scopeid"),
146 true,
147 true),
148 VariantStruct => ("variant_struct",
149 vec!("id", "ctor_id", "qualname", "type", "value", "scopeid"),
150 true,
151 true),
152 Function => ("function",
153 vec!("id", "qualname", "declid", "declidcrate", "scopeid"),
154 true,
155 true),
156 MethodDecl => ("method_decl",
157 vec!("id", "qualname", "scopeid"),
158 true,
159 true),
160 Struct => ("struct",
161 vec!("id", "ctor_id", "qualname", "scopeid", "value"),
162 true,
163 true),
164 Trait => ("trait",
165 vec!("id", "qualname", "scopeid", "value"),
166 true,
167 true),
168 Impl => ("impl",
169 vec!("id",
170 "refid",
171 "refidcrate",
172 "traitid",
173 "traitidcrate",
174 "scopeid"),
175 true,
176 true),
177 Module => ("module",
178 vec!("id", "qualname", "scopeid", "def_file"),
179 true,
180 false),
181 UseAlias => ("use_alias",
182 vec!("id", "refid", "refidcrate", "name", "scopeid"),
183 true,
184 true),
185 UseGlob => ("use_glob", vec!("id", "value", "scopeid"), true, true),
186 ExternCrate => ("extern_crate",
187 vec!("id", "name", "location", "crate", "scopeid"),
188 true,
189 true),
190 Inheritance => ("inheritance",
191 vec!("base", "basecrate", "derived", "derivedcrate"),
192 true,
193 false),
194 MethodCall => ("method_call",
195 vec!("refid", "refidcrate", "declid", "declidcrate", "scopeid"),
196 true,
197 true),
198 Typedef => ("typedef", vec!("id", "qualname", "value"), true, true),
199 ExternalCrate => ("external_crate",
200 vec!("name", "crate", "file_name"),
201 false,
202 false),
203 Crate => ("crate", vec!("name", "crate_root"), true, false),
204 FnCall => ("fn_call",
205 vec!("refid", "refidcrate", "qualname", "scopeid"),
206 true,
207 true),
208 ModRef => ("mod_ref",
209 vec!("refid", "refidcrate", "qualname", "scopeid"),
210 true,
211 true),
212 VarRef => ("var_ref",
213 vec!("refid", "refidcrate", "qualname", "scopeid"),
214 true,
215 true),
216 TypeRef => ("type_ref",
217 vec!("refid", "refidcrate", "qualname", "scopeid"),
218 true,
219 true),
220 FnRef => ("fn_ref",
221 vec!("refid", "refidcrate", "qualname", "scopeid"),
222 true,
223 true),
224 Macro => ("macro",
225 vec!("name", "qualname"),
226 true,
227 true),
228 MacroUse => ("macro_use",
229 vec!("callee_name", "qualname", "scopeid"),
230 true,
231 true),
232 }
233 }
234
235 pub fn make_values_str(&self,
236 kind: &'static str,
237 fields: &Vec<&'static str>,
238 values: Vec<String>,
239 span: Span)
240 -> Option<String> {
241 if values.len() != fields.len() {
242 self.span.sess.span_bug(span,
243 &format!("Mismatch between length of fields for '{}', \
244 expected '{}', found '{}'",
245 kind,
246 fields.len(),
247 values.len()));
248 }
249
250 let values = values.iter().map(|s| {
251 // Never take more than 1020 chars
252 if s.len() > 1020 {
253 &s[..1020]
254 } else {
255 &s[..]
256 }
257 });
258
259 let pairs = fields.iter().zip(values);
260 let strs = pairs.map(|(f, v)| format!(",{},\"{}\"", f, escape(String::from(v))));
261 Some(strs.fold(String::new(),
262 |mut s, ss| {
263 s.push_str(&ss[..]);
264 s
265 }))
266 }
267
268 pub fn record_without_span(&mut self, kind: Row, values: Vec<String>, span: Span) {
269 let (label, ref fields, needs_span, dump_spans) = FmtStrs::lookup_row(kind);
270
271 if needs_span {
272 self.span.sess.span_bug(span,
273 &format!("Called record_without_span for '{}' which does \
274 requires a span",
275 label));
276 }
277 assert!(!dump_spans);
278
279 if self.recorder.dump_spans {
280 return;
281 }
282
283 let values_str = match self.make_values_str(label, fields, values, span) {
284 Some(vs) => vs,
285 None => return,
286 };
287
288 let mut result = String::from(label);
289 result.push_str(&values_str[..]);
290 result.push_str("\n");
291 self.recorder.record(&result[..]);
292 }
293
294 pub fn record_with_span(&mut self,
295 kind: Row,
296 span: Span,
297 sub_span: Span,
298 values: Vec<String>) {
299 let (label, ref fields, needs_span, dump_spans) = FmtStrs::lookup_row(kind);
300
301 if self.recorder.dump_spans {
302 if dump_spans {
303 self.recorder.dump_span(self.span.clone(), label, span, Some(sub_span));
304 }
305 return;
306 }
307
308 if !needs_span {
309 self.span.sess.span_bug(span,
310 &format!("Called record_with_span for '{}' which does not \
311 require a span",
312 label));
313 }
314
315 let values_str = match self.make_values_str(label, fields, values, span) {
316 Some(vs) => vs,
317 None => return,
318 };
319 let result = format!("{},{}{}\n",
320 label,
321 self.span.extent_str(sub_span),
322 values_str);
323 self.recorder.record(&result[..]);
324 }
325
326 pub fn check_and_record(&mut self,
327 kind: Row,
328 span: Span,
329 sub_span: Option<Span>,
330 values: Vec<String>) {
331 filter!(self.span, sub_span, span);
332 match sub_span {
333 Some(sub_span) => self.record_with_span(kind, span, sub_span, values),
334 None => {
335 let (label, _, _, _) = FmtStrs::lookup_row(kind);
336 self.span.report_span_err(label, span);
337 }
338 }
339 }
340
341 pub fn variable_str(&mut self,
342 span: Span,
343 sub_span: Option<Span>,
344 id: NodeId,
345 name: &str,
346 value: &str,
347 typ: &str) {
348 // Getting a fully qualified name for a variable is hard because in
349 // the local case they can be overridden in one block and there is no nice way
350 // to refer to such a scope in english, so we just hack it by appending the
351 // variable def's node id
352 let mut qualname = String::from(name);
353 qualname.push_str("$");
354 qualname.push_str(&id.to_string());
355 let id = self.normalize_node_id(id);
356 self.check_and_record(Variable,
357 span,
358 sub_span,
359 svec!(id, name, qualname, value, typ, 0));
360 }
361
362 // formal parameters
363 pub fn formal_str(&mut self,
364 span: Span,
365 sub_span: Option<Span>,
366 id: NodeId,
367 fn_name: &str,
368 name: &str,
369 typ: &str) {
370 let mut qualname = String::from(fn_name);
371 qualname.push_str("::");
372 qualname.push_str(name);
373 let id = self.normalize_node_id(id);
374 self.check_and_record(Variable,
375 span,
376 sub_span,
377 svec!(id, name, qualname, "", typ, 0));
378 }
379
380 // value is the initialising expression of the static if it is not mut, otherwise "".
381 pub fn static_str(&mut self,
382 span: Span,
383 sub_span: Option<Span>,
384 id: NodeId,
385 name: &str,
386 qualname: &str,
387 value: &str,
388 typ: &str,
389 scope_id: NodeId) {
390 let id = self.normalize_node_id(id);
391 let scope_id = self.normalize_node_id(scope_id);
392 self.check_and_record(Variable,
393 span,
394 sub_span,
395 svec!(id, name, qualname, value, typ, scope_id));
396 }
397
398 pub fn field_str(&mut self,
399 span: Span,
400 sub_span: Option<Span>,
401 id: NodeId,
402 name: &str,
403 qualname: &str,
404 typ: &str,
405 scope_id: NodeId) {
406 let id = self.normalize_node_id(id);
407 let scope_id = self.normalize_node_id(scope_id);
408 self.check_and_record(Variable,
409 span,
410 sub_span,
411 svec!(id, name, qualname, "", typ, scope_id));
412 }
413
414 pub fn enum_str(&mut self,
415 span: Span,
416 sub_span: Option<Span>,
417 id: NodeId,
418 name: &str,
419 scope_id: NodeId,
420 value: &str) {
421 let id = self.normalize_node_id(id);
422 let scope_id = self.normalize_node_id(scope_id);
423 self.check_and_record(Enum, span, sub_span, svec!(id, name, scope_id, value));
424 }
425
426 pub fn tuple_variant_str(&mut self,
427 span: Span,
428 sub_span: Option<Span>,
429 id: NodeId,
430 name: &str,
431 qualname: &str,
432 typ: &str,
433 val: &str,
434 scope_id: NodeId) {
435 let id = self.normalize_node_id(id);
436 let scope_id = self.normalize_node_id(scope_id);
437 self.check_and_record(Variant,
438 span,
439 sub_span,
440 svec!(id, name, qualname, typ, val, scope_id));
441 }
442
443 pub fn struct_variant_str(&mut self,
444 span: Span,
445 sub_span: Option<Span>,
446 id: NodeId,
447 name: &str,
448 typ: &str,
449 val: &str,
450 scope_id: NodeId) {
451 let id = self.normalize_node_id(id);
452 let ctor_id = id;
453 let scope_id = self.normalize_node_id(scope_id);
454 self.check_and_record(VariantStruct,
455 span,
456 sub_span,
457 svec!(id, ctor_id, name, typ, val, scope_id));
458 }
459
460 pub fn fn_str(&mut self,
461 span: Span,
462 sub_span: Option<Span>,
463 id: NodeId,
464 name: &str,
465 scope_id: NodeId) {
466 let id = self.normalize_node_id(id);
467 let scope_id = self.normalize_node_id(scope_id);
468 self.check_and_record(Function,
469 span,
470 sub_span,
471 svec!(id, name, "", "", scope_id));
472 }
473
474 pub fn method_str(&mut self,
475 span: Span,
476 sub_span: Option<Span>,
477 id: NodeId,
478 name: &str,
479 decl_id: Option<DefId>,
480 scope_id: NodeId) {
481 let id = self.normalize_node_id(id);
482 let scope_id = self.normalize_node_id(scope_id);
483 let values = match decl_id {
484 Some(decl_id) => svec!(id,
485 name,
486 decl_id.index.as_usize(),
487 decl_id.krate,
488 scope_id),
489 None => svec!(id, name, "", "", scope_id),
490 };
491 self.check_and_record(Function, span, sub_span, values);
492 }
493
494 pub fn method_decl_str(&mut self,
495 span: Span,
496 sub_span: Option<Span>,
497 id: NodeId,
498 name: &str,
499 scope_id: NodeId) {
500 let id = self.normalize_node_id(id);
501 let scope_id = self.normalize_node_id(scope_id);
502 self.check_and_record(MethodDecl, span, sub_span, svec!(id, name, scope_id));
503 }
504
505 pub fn struct_str(&mut self,
506 span: Span,
507 sub_span: Option<Span>,
508 id: NodeId,
509 ctor_id: NodeId,
510 name: &str,
511 scope_id: NodeId,
512 value: &str) {
513 let id = self.normalize_node_id(id);
514 let scope_id = self.normalize_node_id(scope_id);
515 let ctor_id = self.normalize_node_id(ctor_id);
516 self.check_and_record(Struct,
517 span,
518 sub_span,
519 svec!(id, ctor_id, name, scope_id, value));
520 }
521
522 pub fn trait_str(&mut self,
523 span: Span,
524 sub_span: Option<Span>,
525 id: NodeId,
526 name: &str,
527 scope_id: NodeId,
528 value: &str) {
529 let id = self.normalize_node_id(id);
530 let scope_id = self.normalize_node_id(scope_id);
531 self.check_and_record(Trait, span, sub_span, svec!(id, name, scope_id, value));
532 }
533
534 pub fn impl_str(&mut self,
535 span: Span,
536 sub_span: Option<Span>,
537 id: NodeId,
538 ref_id: Option<DefId>,
539 trait_id: Option<DefId>,
540 scope_id: NodeId) {
541 let id = self.normalize_node_id(id);
542 let scope_id = self.normalize_node_id(scope_id);
543 let ref_id = ref_id.unwrap_or(CRATE_ROOT_DEF_ID);
544 let trait_id = trait_id.unwrap_or(CRATE_ROOT_DEF_ID);
545 self.check_and_record(Impl,
546 span,
547 sub_span,
548 svec!(id,
549 ref_id.index.as_usize(),
550 ref_id.krate,
551 trait_id.index.as_usize(),
552 trait_id.krate,
553 scope_id));
554 }
555
556 pub fn mod_str(&mut self,
557 span: Span,
558 sub_span: Option<Span>,
559 id: NodeId,
560 name: &str,
561 parent: NodeId,
562 filename: &str) {
563 let id = self.normalize_node_id(id);
564 let parent = self.normalize_node_id(parent);
565 self.check_and_record(Module,
566 span,
567 sub_span,
568 svec!(id, name, parent, filename));
569 }
570
571 pub fn use_alias_str(&mut self,
572 span: Span,
573 sub_span: Option<Span>,
574 id: NodeId,
575 mod_id: Option<DefId>,
576 name: &str,
577 parent: NodeId) {
578 let id = self.normalize_node_id(id);
579 let parent = self.normalize_node_id(parent);
580 let mod_id = mod_id.unwrap_or(CRATE_ROOT_DEF_ID);
581 self.check_and_record(UseAlias,
582 span,
583 sub_span,
584 svec!(id, mod_id.index.as_usize(), mod_id.krate, name, parent));
585 }
586
587 pub fn use_glob_str(&mut self,
588 span: Span,
589 sub_span: Option<Span>,
590 id: NodeId,
591 values: &str,
592 parent: NodeId) {
593 let id = self.normalize_node_id(id);
594 let parent = self.normalize_node_id(parent);
595 self.check_and_record(UseGlob, span, sub_span, svec!(id, values, parent));
596 }
597
598 pub fn extern_crate_str(&mut self,
599 span: Span,
600 sub_span: Option<Span>,
601 id: NodeId,
602 cnum: ast::CrateNum,
603 name: &str,
604 loc: &str,
605 parent: NodeId) {
606 let id = self.normalize_node_id(id);
607 let parent = self.normalize_node_id(parent);
608 self.check_and_record(ExternCrate,
609 span,
610 sub_span,
611 svec!(id, name, loc, cnum, parent));
612 }
613
614 pub fn inherit_str(&mut self,
615 span: Span,
616 sub_span: Option<Span>,
617 base_id: DefId,
618 deriv_id: NodeId) {
619 let deriv_id = self.normalize_node_id(deriv_id);
620 self.check_and_record(Inheritance,
621 span,
622 sub_span,
623 svec!(base_id.index.as_usize(), base_id.krate, deriv_id, 0));
624 }
625
626 pub fn fn_call_str(&mut self,
627 span: Span,
628 sub_span: Option<Span>,
629 id: DefId,
630 scope_id: NodeId) {
631 let scope_id = self.normalize_node_id(scope_id);
632 self.check_and_record(FnCall,
633 span,
634 sub_span,
635 svec!(id.index.as_usize(), id.krate, "", scope_id));
636 }
637
638 pub fn meth_call_str(&mut self,
639 span: Span,
640 sub_span: Option<Span>,
641 defid: Option<DefId>,
642 declid: Option<DefId>,
643 scope_id: NodeId) {
644 let scope_id = self.normalize_node_id(scope_id);
645 let defid = defid.unwrap_or(CRATE_ROOT_DEF_ID);
646 let (dcn, dck) = match declid {
647 Some(declid) => (s!(declid.index.as_usize()), s!(declid.krate)),
648 None => ("".to_string(), "".to_string()),
649 };
650 self.check_and_record(MethodCall,
651 span,
652 sub_span,
653 svec!(defid.index.as_usize(), defid.krate, dcn, dck, scope_id));
654 }
655
656 pub fn sub_mod_ref_str(&mut self, span: Span, sub_span: Span, qualname: &str, parent: NodeId) {
657 let parent = self.normalize_node_id(parent);
658 self.record_with_span(ModRef, span, sub_span, svec!(0, 0, qualname, parent));
659 }
660
661 pub fn typedef_str(&mut self,
662 span: Span,
663 sub_span: Option<Span>,
664 id: NodeId,
665 qualname: &str,
666 value: &str) {
667 let id = self.normalize_node_id(id);
668 self.check_and_record(Typedef, span, sub_span, svec!(id, qualname, value));
669 }
670
671 pub fn crate_str(&mut self, span: Span, name: &str, crate_root: &str) {
672 self.record_with_span(Crate, span, span, svec!(name, crate_root));
673 }
674
675 pub fn external_crate_str(&mut self, span: Span, name: &str, num: ast::CrateNum) {
676 let lo_loc = self.span.sess.codemap().lookup_char_pos(span.lo);
677 self.record_without_span(ExternalCrate,
678 svec!(name, num, SpanUtils::make_path_string(&lo_loc.file.name)),
679 span);
680 }
681
682 pub fn sub_type_ref_str(&mut self, span: Span, sub_span: Span, qualname: &str) {
683 self.record_with_span(TypeRef, span, sub_span, svec!(0, 0, qualname, 0));
684 }
685
686 // A slightly generic function for a reference to an item of any kind.
687 pub fn ref_str(&mut self,
688 kind: Row,
689 span: Span,
690 sub_span: Option<Span>,
691 id: DefId,
692 scope_id: NodeId) {
693 let scope_id = self.normalize_node_id(scope_id);
694 self.check_and_record(kind,
695 span,
696 sub_span,
697 svec!(id.index.as_usize(), id.krate, "", scope_id));
698 }
699
700 pub fn macro_str(&mut self, span: Span, sub_span: Span, name: String, qualname: String) {
701 self.record_with_span(Macro, span, sub_span, svec!(name, qualname));
702 }
703
704 pub fn macro_use_str(&mut self,
705 span: Span,
706 sub_span: Span,
707 name: String,
708 qualname: String,
709 scope_id: NodeId) {
710 let scope_id = self.normalize_node_id(scope_id);
711 self.record_with_span(MacroUse, span, sub_span,
712 svec!(name, qualname, scope_id));
713 }
714 }