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