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