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