]> git.lizzy.rs Git - rust.git/blob - src/librustc_save_analysis/json_api_dumper.rs
d56aae18a7cd1f65e49a64d55bacc1acbf47082b
[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};
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
79 // FIXME methods. The defs have information about possible overriding and the
80 // refs have decl information (e.g., a trait method where we know the required
81 // method, but not the supplied method). In both cases, we are currently
82 // ignoring it.
83
84 #[derive(Debug, RustcEncodable)]
85 struct Analysis {
86     kind: Format,
87     prelude: Option<CratePreludeData>,
88     imports: Vec<Import>,
89     defs: Vec<Def>,
90     // These two fields are dummies so that clients can parse the two kinds of
91     // JSON data in the same way.
92     refs: Vec<()>,
93     macro_refs: Vec<()>,
94 }
95
96 impl Analysis {
97     fn new() -> Analysis {
98         Analysis {
99             kind: Format::JsonApi,
100             prelude: None,
101             imports: vec![],
102             defs: vec![],
103             refs: vec![],
104             macro_refs: vec![],
105         }
106     }
107 }
108
109 // DefId::index is a newtype and so the JSON serialisation is ugly. Therefore
110 // we use our own Id which is the same, but without the newtype.
111 #[derive(Debug, RustcEncodable)]
112 struct Id {
113     krate: u32,
114     index: u32,
115 }
116
117 impl From<DefId> for Id {
118     fn from(id: DefId) -> Id {
119         Id {
120             krate: id.krate.as_u32(),
121             index: id.index.as_u32(),
122         }
123     }
124 }
125
126 #[derive(Debug, RustcEncodable)]
127 struct Import {
128     kind: ImportKind,
129     id: Id,
130     span: SpanData,
131     name: String,
132     value: String,
133 }
134
135 #[derive(Debug, RustcEncodable)]
136 enum ImportKind {
137     Use,
138     GlobUse,
139 }
140
141 impl From<UseData> for Option<Import> {
142     fn from(data: UseData) -> Option<Import> {
143         match data.visibility {
144             Visibility::Public => Some(Import {
145                 kind: ImportKind::Use,
146                 id: From::from(data.id),
147                 span: data.span,
148                 name: data.name,
149                 value: String::new(),
150             }),
151             _ => None,
152         }
153     }
154 }
155 impl From<UseGlobData> for Option<Import> {
156     fn from(data: UseGlobData) -> Option<Import> {
157         match data.visibility {
158             Visibility::Public => Some(Import {
159                 kind: ImportKind::GlobUse,
160                 id: From::from(data.id),
161                 span: data.span,
162                 name: "*".to_owned(),
163                 value: data.names.join(", "),
164             }),
165             _ => None,
166         }
167     }
168 }
169
170 #[derive(Debug, RustcEncodable)]
171 struct Def {
172     kind: DefKind,
173     id: Id,
174     span: SpanData,
175     name: String,
176     qualname: String,
177     value: String,
178     parent: Option<Id>,
179     children: Vec<Id>,
180     decl_id: Option<Id>,
181     docs: String,
182 }
183
184 #[derive(Debug, RustcEncodable)]
185 enum DefKind {
186     // value = variant names
187     Enum,
188     // value = enum name + variant name + types
189     Tuple,
190     // value = [enum name +] name + fields
191     Struct,
192     // value = signature
193     Trait,
194     // value = type + generics
195     Function,
196     // value = type + generics
197     Method,
198     // No id, no value.
199     Macro,
200     // value = file_name
201     Mod,
202     // value = aliased type
203     Type,
204     // value = type and init expression (for all variable kinds).
205     Static,
206     Const,
207     Field,
208 }
209
210 impl From<EnumData> for Option<Def> {
211     fn from(data: EnumData) -> Option<Def> {
212         match data.visibility {
213             Visibility::Public => Some(Def {
214                 kind: DefKind::Enum,
215                 id: From::from(data.id),
216                 span: data.span,
217                 name: data.name,
218                 qualname: data.qualname,
219                 value: data.value,
220                 parent: None,
221                 children: data.variants.into_iter().map(|id| From::from(id)).collect(),
222                 decl_id: None,
223                 docs: data.docs,
224             }),
225             _ => None,
226         }
227     }
228 }
229
230 impl From<TupleVariantData> for Option<Def> {
231     fn from(data: TupleVariantData) -> Option<Def> {
232         Some(Def {
233             kind: DefKind::Tuple,
234             id: From::from(data.id),
235             span: data.span,
236             name: data.name,
237             qualname: data.qualname,
238             value: data.value,
239             parent: data.parent.map(|id| From::from(id)),
240             children: vec![],
241             decl_id: None,
242             docs: data.docs,
243         })
244     }
245 }
246 impl From<StructVariantData> for Option<Def> {
247     fn from(data: StructVariantData) -> Option<Def> {
248         Some(Def {
249             kind: DefKind::Struct,
250             id: From::from(data.id),
251             span: data.span,
252             name: data.name,
253             qualname: data.qualname,
254             value: data.value,
255             parent: data.parent.map(|id| From::from(id)),
256             children: vec![],
257             decl_id: None,
258             docs: data.docs,
259         })
260     }
261 }
262 impl From<StructData> for Option<Def> {
263     fn from(data: StructData) -> Option<Def> {
264         match data.visibility {
265             Visibility::Public => Some(Def {
266             kind: DefKind::Struct,
267             id: From::from(data.id),
268             span: data.span,
269             name: data.name,
270             qualname: data.qualname,
271             value: data.value,
272             parent: None,
273             children: data.fields.into_iter().map(|id| From::from(id)).collect(),
274             decl_id: None,
275             docs: data.docs,
276         }),
277             _ => None,
278         }
279     }
280 }
281 impl From<TraitData> for Option<Def> {
282     fn from(data: TraitData) -> Option<Def> {
283         match data.visibility {
284             Visibility::Public => Some(Def {
285                 kind: DefKind::Trait,
286                 id: From::from(data.id),
287                 span: data.span,
288                 name: data.name,
289                 qualname: data.qualname,
290                 value: data.value,
291                 children: data.items.into_iter().map(|id| From::from(id)).collect(),
292                 parent: None,
293                 decl_id: None,
294                 docs: data.docs,
295             }),
296             _ => None,
297         }
298     }
299 }
300 impl From<FunctionData> for Option<Def> {
301     fn from(data: FunctionData) -> Option<Def> {
302         match data.visibility {
303             Visibility::Public => Some(Def {
304                 kind: DefKind::Function,
305                 id: From::from(data.id),
306                 span: data.span,
307                 name: data.name,
308                 qualname: data.qualname,
309                 value: data.value,
310                 children: vec![],
311                 parent: data.parent.map(|id| From::from(id)),
312                 decl_id: None,
313                 docs: data.docs,
314             }),
315             _ => None,
316         }
317     }
318 }
319 impl From<MethodData> for Option<Def> {
320     fn from(data: MethodData) -> Option<Def> {
321         match data.visibility {
322             Visibility::Public => Some(Def {
323                 kind: DefKind::Method,
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: data.decl_id.map(|id| From::from(id)),
332                 docs: data.docs,
333             }),
334             _ => None,
335         }
336     }
337 }
338 impl From<MacroData> for Option<Def> {
339     fn from(data: MacroData) -> Option<Def> {
340         Some(Def {
341             kind: DefKind::Macro,
342             id: From::from(null_def_id()),
343             span: data.span,
344             name: data.name,
345             qualname: data.qualname,
346             value: String::new(),
347             children: vec![],
348             parent: None,
349             decl_id: None,
350             docs: data.docs,
351         })
352     }
353 }
354 impl From<ModData> for Option<Def> {
355     fn from(data:ModData) -> Option<Def> {
356         match data.visibility {
357             Visibility::Public => Some(Def {
358                 kind: DefKind::Mod,
359                 id: From::from(data.id),
360                 span: data.span,
361                 name: data.name,
362                 qualname: data.qualname,
363                 value: data.filename,
364                 children: data.items.into_iter().map(|id| From::from(id)).collect(),
365                 parent: None,
366                 decl_id: None,
367                 docs: data.docs,
368             }),
369             _ => None,
370         }
371     }
372 }
373 impl From<TypeDefData> for Option<Def> {
374     fn from(data: TypeDefData) -> Option<Def> {
375         match data.visibility {
376             Visibility::Public => Some(Def {
377                 kind: DefKind::Type,
378                 id: From::from(data.id),
379                 span: data.span,
380                 name: data.name,
381                 qualname: data.qualname,
382                 value: data.value,
383                 children: vec![],
384                 parent: data.parent.map(|id| From::from(id)),
385                 decl_id: None,
386                 docs: String::new(),
387             }),
388             _ => None,
389         }
390     }
391 }
392 impl From<VariableData> for Option<Def> {
393     fn from(data: VariableData) -> Option<Def> {
394         match data.visibility {
395             Visibility::Public => Some(Def {
396                 kind: match data.kind {
397                     VariableKind::Static => DefKind::Static,
398                     VariableKind::Const => DefKind::Const,
399                     VariableKind::Local => { return None }
400                     VariableKind::Field => DefKind::Field,
401                 },
402                 id: From::from(data.id),
403                 span: data.span,
404                 name: data.name,
405                 qualname: data.qualname,
406                 value: data.value,
407                 children: vec![],
408                 parent: data.parent.map(|id| From::from(id)),
409                 decl_id: None,
410                 docs: data.docs,
411             }),
412             _ => None,
413         }
414     }
415 }