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