]> git.lizzy.rs Git - rust.git/blob - src/librustc_save_analysis/json_api_dumper.rs
277535f9e651373318c162830e7c3889a2451bf7
[rust.git] / src / librustc_save_analysis / json_api_dumper.rs
1 // Copyright 2016 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 std::io::Write;
12
13 use rustc::hir::def_id::DefId;
14 use rustc_serialize::json::as_json;
15
16 use external_data::*;
17 use data::{VariableKind, Visibility, SigElement};
18 use dump::Dump;
19 use super::Format;
20
21
22 // A dumper to dump a restricted set of JSON information, designed for use with
23 // libraries distributed without their source. Clients are likely to use type
24 // information here, and (for example) generate Rustdoc URLs, but don't need
25 // information for navigating the source of the crate.
26 // Relative to the regular JSON save-analysis info, this form is filtered to
27 // remove non-visible items, but includes some extra info for items (e.g., the
28 // parent field for finding the struct to which a field belongs).
29 pub struct JsonApiDumper<'b, W: Write + 'b> {
30     output: &'b mut W,
31     result: Analysis,
32 }
33
34 impl<'b, W: Write> JsonApiDumper<'b, W> {
35     pub fn new(writer: &'b mut W) -> JsonApiDumper<'b, W> {
36         JsonApiDumper { output: writer, result: Analysis::new() }
37     }
38 }
39
40 impl<'b, W: Write> Drop for JsonApiDumper<'b, W> {
41     fn drop(&mut self) {
42         if let Err(_) = write!(self.output, "{}", as_json(&self.result)) {
43             error!("Error writing output");
44         }
45     }
46 }
47
48 macro_rules! impl_fn {
49     ($fn_name: ident, $data_type: ident, $bucket: ident) => {
50         fn $fn_name(&mut self, data: $data_type) {
51             if let Some(datum) = From::from(data) {
52                 self.result.$bucket.push(datum);
53             }
54         }
55     }
56 }
57
58 impl<'b, W: Write + 'b> Dump for JsonApiDumper<'b, W> {
59     fn crate_prelude(&mut self, data: CratePreludeData) {
60         self.result.prelude = Some(data)
61     }
62
63     impl_fn!(use_data, UseData, imports);
64     impl_fn!(use_glob, UseGlobData, imports);
65
66     impl_fn!(enum_data, EnumData, defs);
67     impl_fn!(tuple_variant, TupleVariantData, defs);
68     impl_fn!(struct_variant, StructVariantData, defs);
69     impl_fn!(struct_data, StructData, defs);
70     impl_fn!(trait_data, TraitData, defs);
71     impl_fn!(function, FunctionData, defs);
72     impl_fn!(method, MethodData, defs);
73     impl_fn!(macro_data, MacroData, defs);
74     impl_fn!(mod_data, ModData, defs);
75     impl_fn!(typedef, TypeDefData, defs);
76     impl_fn!(variable, VariableData, defs);
77
78     fn impl_data(&mut self, data: ImplData) {
79         if data.self_ref.is_some() {
80             self.result.relations.push(From::from(data));
81         }
82     }
83     fn inheritance(&mut self, data: InheritanceData) {
84         self.result.relations.push(From::from(data));
85     }
86 }
87
88 // FIXME methods. The defs have information about possible overriding and the
89 // refs have decl information (e.g., a trait method where we know the required
90 // method, but not the supplied method). In both cases, we are currently
91 // ignoring it.
92
93 #[derive(Debug, RustcEncodable)]
94 struct Analysis {
95     kind: Format,
96     prelude: Option<CratePreludeData>,
97     imports: Vec<Import>,
98     defs: Vec<Def>,
99     relations: Vec<Relation>,
100     // These two fields are dummies so that clients can parse the two kinds of
101     // JSON data in the same way.
102     refs: Vec<()>,
103     macro_refs: Vec<()>,
104 }
105
106 impl Analysis {
107     fn new() -> Analysis {
108         Analysis {
109             kind: Format::JsonApi,
110             prelude: None,
111             imports: vec![],
112             defs: vec![],
113             relations: vec![],
114             refs: vec![],
115             macro_refs: vec![],
116         }
117     }
118 }
119
120 // DefId::index is a newtype and so the JSON serialisation is ugly. Therefore
121 // we use our own Id which is the same, but without the newtype.
122 #[derive(Debug, RustcEncodable)]
123 struct Id {
124     krate: u32,
125     index: u32,
126 }
127
128 impl From<DefId> for Id {
129     fn from(id: DefId) -> Id {
130         Id {
131             krate: id.krate.as_u32(),
132             index: id.index.as_u32(),
133         }
134     }
135 }
136
137 #[derive(Debug, RustcEncodable)]
138 struct Import {
139     kind: ImportKind,
140     id: Id,
141     span: SpanData,
142     name: String,
143     value: String,
144 }
145
146 #[derive(Debug, RustcEncodable)]
147 enum ImportKind {
148     Use,
149     GlobUse,
150 }
151
152 impl From<UseData> for Option<Import> {
153     fn from(data: UseData) -> Option<Import> {
154         match data.visibility {
155             Visibility::Public => Some(Import {
156                 kind: ImportKind::Use,
157                 id: From::from(data.id),
158                 span: data.span,
159                 name: data.name,
160                 value: String::new(),
161             }),
162             _ => None,
163         }
164     }
165 }
166 impl From<UseGlobData> for Option<Import> {
167     fn from(data: UseGlobData) -> Option<Import> {
168         match data.visibility {
169             Visibility::Public => Some(Import {
170                 kind: ImportKind::GlobUse,
171                 id: From::from(data.id),
172                 span: data.span,
173                 name: "*".to_owned(),
174                 value: data.names.join(", "),
175             }),
176             _ => None,
177         }
178     }
179 }
180
181 #[derive(Debug, RustcEncodable)]
182 struct Def {
183     kind: DefKind,
184     id: Id,
185     span: SpanData,
186     name: String,
187     qualname: String,
188     value: String,
189     parent: Option<Id>,
190     children: Vec<Id>,
191     decl_id: Option<Id>,
192     docs: String,
193     sig: Option<JsonSignature>,
194 }
195
196 #[derive(Debug, RustcEncodable)]
197 enum DefKind {
198     // value = variant names
199     Enum,
200     // value = enum name + variant name + types
201     Tuple,
202     // value = [enum name +] name + fields
203     Struct,
204     // value = signature
205     Trait,
206     // value = type + generics
207     Function,
208     // value = type + generics
209     Method,
210     // No id, no value.
211     Macro,
212     // value = file_name
213     Mod,
214     // value = aliased type
215     Type,
216     // value = type and init expression (for all variable kinds).
217     Static,
218     Const,
219     Field,
220 }
221
222 impl From<EnumData> for Option<Def> {
223     fn from(data: EnumData) -> Option<Def> {
224         match data.visibility {
225             Visibility::Public => Some(Def {
226                 kind: DefKind::Enum,
227                 id: From::from(data.id),
228                 span: data.span,
229                 name: data.name,
230                 qualname: data.qualname,
231                 value: data.value,
232                 parent: None,
233                 children: data.variants.into_iter().map(|id| From::from(id)).collect(),
234                 decl_id: None,
235                 docs: data.docs,
236                 sig: Some(From::from(data.sig)),
237             }),
238             _ => None,
239         }
240     }
241 }
242
243 impl From<TupleVariantData> for Option<Def> {
244     fn from(data: TupleVariantData) -> Option<Def> {
245         Some(Def {
246             kind: DefKind::Tuple,
247             id: From::from(data.id),
248             span: data.span,
249             name: data.name,
250             qualname: data.qualname,
251             value: data.value,
252             parent: data.parent.map(|id| From::from(id)),
253             children: vec![],
254             decl_id: None,
255             docs: data.docs,
256             sig: Some(From::from(data.sig)),
257         })
258     }
259 }
260 impl From<StructVariantData> for Option<Def> {
261     fn from(data: StructVariantData) -> Option<Def> {
262         Some(Def {
263             kind: DefKind::Struct,
264             id: From::from(data.id),
265             span: data.span,
266             name: data.name,
267             qualname: data.qualname,
268             value: data.value,
269             parent: data.parent.map(|id| From::from(id)),
270             children: vec![],
271             decl_id: None,
272             docs: data.docs,
273             sig: Some(From::from(data.sig)),
274         })
275     }
276 }
277 impl From<StructData> for Option<Def> {
278     fn from(data: StructData) -> Option<Def> {
279         match data.visibility {
280             Visibility::Public => Some(Def {
281             kind: DefKind::Struct,
282             id: From::from(data.id),
283             span: data.span,
284             name: data.name,
285             qualname: data.qualname,
286             value: data.value,
287             parent: None,
288             children: data.fields.into_iter().map(|id| From::from(id)).collect(),
289             decl_id: None,
290             docs: data.docs,
291             sig: Some(From::from(data.sig)),
292         }),
293             _ => None,
294         }
295     }
296 }
297 impl From<TraitData> for Option<Def> {
298     fn from(data: TraitData) -> Option<Def> {
299         match data.visibility {
300             Visibility::Public => Some(Def {
301                 kind: DefKind::Trait,
302                 id: From::from(data.id),
303                 span: data.span,
304                 name: data.name,
305                 qualname: data.qualname,
306                 value: data.value,
307                 children: data.items.into_iter().map(|id| From::from(id)).collect(),
308                 parent: None,
309                 decl_id: None,
310                 docs: data.docs,
311                 sig: Some(From::from(data.sig)),
312             }),
313             _ => None,
314         }
315     }
316 }
317 impl From<FunctionData> for Option<Def> {
318     fn from(data: FunctionData) -> Option<Def> {
319         match data.visibility {
320             Visibility::Public => Some(Def {
321                 kind: DefKind::Function,
322                 id: From::from(data.id),
323                 span: data.span,
324                 name: data.name,
325                 qualname: data.qualname,
326                 value: data.value,
327                 children: vec![],
328                 parent: data.parent.map(|id| From::from(id)),
329                 decl_id: None,
330                 docs: data.docs,
331                 sig: Some(From::from(data.sig)),
332             }),
333             _ => None,
334         }
335     }
336 }
337 impl From<MethodData> for Option<Def> {
338     fn from(data: MethodData) -> Option<Def> {
339         match data.visibility {
340             Visibility::Public => Some(Def {
341                 kind: DefKind::Method,
342                 id: From::from(data.id),
343                 span: data.span,
344                 name: data.name,
345                 qualname: data.qualname,
346                 value: data.value,
347                 children: vec![],
348                 parent: data.parent.map(|id| From::from(id)),
349                 decl_id: data.decl_id.map(|id| From::from(id)),
350                 docs: data.docs,
351                 sig: Some(From::from(data.sig)),
352             }),
353             _ => None,
354         }
355     }
356 }
357 impl From<MacroData> for Option<Def> {
358     fn from(data: MacroData) -> Option<Def> {
359         Some(Def {
360             kind: DefKind::Macro,
361             id: From::from(null_def_id()),
362             span: data.span,
363             name: data.name,
364             qualname: data.qualname,
365             value: String::new(),
366             children: vec![],
367             parent: None,
368             decl_id: None,
369             docs: data.docs,
370             sig: None,
371         })
372     }
373 }
374 impl From<ModData> for Option<Def> {
375     fn from(data:ModData) -> Option<Def> {
376         match data.visibility {
377             Visibility::Public => Some(Def {
378                 kind: DefKind::Mod,
379                 id: From::from(data.id),
380                 span: data.span,
381                 name: data.name,
382                 qualname: data.qualname,
383                 value: data.filename,
384                 children: data.items.into_iter().map(|id| From::from(id)).collect(),
385                 parent: None,
386                 decl_id: None,
387                 docs: data.docs,
388                 sig: Some(From::from(data.sig)),
389             }),
390             _ => None,
391         }
392     }
393 }
394 impl From<TypeDefData> for Option<Def> {
395     fn from(data: TypeDefData) -> Option<Def> {
396         match data.visibility {
397             Visibility::Public => Some(Def {
398                 kind: DefKind::Type,
399                 id: From::from(data.id),
400                 span: data.span,
401                 name: data.name,
402                 qualname: data.qualname,
403                 value: data.value,
404                 children: vec![],
405                 parent: data.parent.map(|id| From::from(id)),
406                 decl_id: None,
407                 docs: String::new(),
408                 sig: data.sig.map(|s| From::from(s)),
409             }),
410             _ => None,
411         }
412     }
413 }
414
415 impl From<VariableData> for Option<Def> {
416     fn from(data: VariableData) -> Option<Def> {
417         match data.visibility {
418             Visibility::Public => Some(Def {
419                 kind: match data.kind {
420                     VariableKind::Static => DefKind::Static,
421                     VariableKind::Const => DefKind::Const,
422                     VariableKind::Local => { return None }
423                     VariableKind::Field => DefKind::Field,
424                 },
425                 id: From::from(data.id),
426                 span: data.span,
427                 name: data.name,
428                 qualname: data.qualname,
429                 value: data.value,
430                 children: vec![],
431                 parent: data.parent.map(|id| From::from(id)),
432                 decl_id: None,
433                 docs: data.docs,
434                 sig: data.sig.map(|s| From::from(s)),
435             }),
436             _ => None,
437         }
438     }
439 }
440
441 #[derive(Debug, RustcEncodable)]
442 struct Relation {
443     span: SpanData,
444     kind: RelationKind,
445     from: Id,
446     to: Id,
447 }
448
449 #[derive(Debug, RustcEncodable)]
450 enum RelationKind {
451     Impl,
452     SuperTrait,
453 }
454
455 impl From<ImplData> for Relation {
456     fn from(data: ImplData) -> Relation {
457         Relation {
458             span: data.span,
459             kind: RelationKind::Impl,
460             from: From::from(data.self_ref.unwrap_or(null_def_id())),
461             to: From::from(data.trait_ref.unwrap_or(null_def_id())),
462         }
463     }
464 }
465
466 impl From<InheritanceData> for Relation {
467     fn from(data: InheritanceData) -> Relation {
468         Relation {
469             span: data.span,
470             kind: RelationKind::SuperTrait,
471             from: From::from(data.base_id),
472             to: From::from(data.deriv_id),
473         }
474     }
475 }
476
477 #[derive(Debug, RustcEncodable)]
478 pub struct JsonSignature {
479     span: SpanData,
480     text: String,
481     ident_start: usize,
482     ident_end: usize,
483     defs: Vec<JsonSigElement>,
484     refs: Vec<JsonSigElement>,
485 }
486
487 impl From<Signature> for JsonSignature {
488     fn from(data: Signature) -> JsonSignature {
489         JsonSignature {
490             span: data.span,
491             text: data.text,
492             ident_start: data.ident_start,
493             ident_end: data.ident_end,
494             defs: data.defs.into_iter().map(|s| From::from(s)).collect(),
495             refs: data.refs.into_iter().map(|s| From::from(s)).collect(),
496         }
497     }
498 }
499
500 #[derive(Debug, RustcEncodable)]
501 pub struct JsonSigElement {
502     id: Id,
503     start: usize,
504     end: usize,
505 }
506
507 impl From<SigElement> for JsonSigElement {
508     fn from(data: SigElement) -> JsonSigElement {
509         JsonSigElement {
510             id: From::from(data.id),
511             start: data.start,
512             end: data.end,
513         }
514     }
515 }