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