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