Skip to content

Commit c7dfc89

Browse files
committed
JsonApiDumper
1 parent cbafc57 commit c7dfc89

File tree

2 files changed

+359
-1
lines changed

2 files changed

+359
-1
lines changed
Lines changed: 356 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,356 @@
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;
18+
use dump::Dump;
19+
20+
pub struct JsonApiDumper<'b, W: Write + 'b> {
21+
output: &'b mut W,
22+
result: Analysis,
23+
}
24+
25+
impl<'b, W: Write> JsonApiDumper<'b, W> {
26+
pub fn new(writer: &'b mut W) -> JsonApiDumper<'b, W> {
27+
JsonApiDumper { output: writer, result: Analysis::new() }
28+
}
29+
}
30+
31+
impl<'b, W: Write> Drop for JsonApiDumper<'b, W> {
32+
fn drop(&mut self) {
33+
if let Err(_) = write!(self.output, "{}", as_json(&self.result)) {
34+
error!("Error writing output");
35+
}
36+
}
37+
}
38+
39+
macro_rules! impl_fn {
40+
($fn_name: ident, $data_type: ident, $bucket: ident) => {
41+
fn $fn_name(&mut self, data: $data_type) {
42+
if let Some(datum) = From::from(data) {
43+
self.result.$bucket.push(datum);
44+
}
45+
}
46+
}
47+
}
48+
49+
impl<'b, W: Write + 'b> Dump for JsonApiDumper<'b, W> {
50+
fn crate_prelude(&mut self, data: CratePreludeData) {
51+
self.result.prelude = Some(data)
52+
}
53+
54+
impl_fn!(use_data, UseData, imports);
55+
impl_fn!(use_glob, UseGlobData, imports);
56+
57+
impl_fn!(enum_data, EnumData, defs);
58+
impl_fn!(tuple_variant, TupleVariantData, defs);
59+
impl_fn!(struct_variant, StructVariantData, defs);
60+
impl_fn!(struct_data, StructData, defs);
61+
impl_fn!(trait_data, TraitData, defs);
62+
impl_fn!(function, FunctionData, defs);
63+
impl_fn!(method, MethodData, defs);
64+
impl_fn!(macro_data, MacroData, defs);
65+
impl_fn!(mod_data, ModData, defs);
66+
impl_fn!(typedef, TypeDefData, defs);
67+
impl_fn!(variable, VariableData, defs);
68+
}
69+
70+
// FIXME methods. The defs have information about possible overriding and the
71+
// refs have decl information (e.g., a trait method where we know the required
72+
// method, but not the supplied method). In both cases, we are currently
73+
// ignoring it.
74+
75+
#[derive(Debug, RustcEncodable)]
76+
struct Analysis {
77+
prelude: Option<CratePreludeData>,
78+
imports: Vec<Import>,
79+
defs: Vec<Def>,
80+
}
81+
82+
impl Analysis {
83+
fn new() -> Analysis {
84+
Analysis {
85+
prelude: None,
86+
imports: vec![],
87+
defs: vec![],
88+
}
89+
}
90+
}
91+
92+
// DefId::index is a newtype and so the JSON serialisation is ugly. Therefore
93+
// we use our own Id which is the same, but without the newtype.
94+
#[derive(Debug, RustcEncodable)]
95+
struct Id {
96+
krate: u32,
97+
index: u32,
98+
}
99+
100+
impl From<DefId> for Id {
101+
fn from(id: DefId) -> Id {
102+
Id {
103+
krate: id.krate,
104+
index: id.index.as_u32(),
105+
}
106+
}
107+
}
108+
109+
#[derive(Debug, RustcEncodable)]
110+
struct Import {
111+
kind: ImportKind,
112+
id: Id,
113+
span: SpanData,
114+
name: String,
115+
value: String,
116+
}
117+
118+
#[derive(Debug, RustcEncodable)]
119+
enum ImportKind {
120+
Use,
121+
GlobUse,
122+
}
123+
124+
impl From<UseData> for Option<Import> {
125+
fn from(data: UseData) -> Option<Import> {
126+
Some(Import {
127+
kind: ImportKind::Use,
128+
id: From::from(data.id),
129+
span: data.span,
130+
name: data.name,
131+
value: String::new(),
132+
})
133+
}
134+
}
135+
impl From<UseGlobData> for Option<Import> {
136+
fn from(data: UseGlobData) -> Option<Import> {
137+
Some(Import {
138+
kind: ImportKind::GlobUse,
139+
id: From::from(data.id),
140+
span: data.span,
141+
name: "*".to_owned(),
142+
value: data.names.join(", "),
143+
})
144+
}
145+
}
146+
147+
#[derive(Debug, RustcEncodable)]
148+
struct Def {
149+
kind: DefKind,
150+
id: Id,
151+
span: SpanData,
152+
name: String,
153+
qualname: String,
154+
value: String,
155+
parent: Option<Id>,
156+
children: Vec<Id>,
157+
decl_id: Option<Id>,
158+
}
159+
160+
#[derive(Debug, RustcEncodable)]
161+
enum DefKind {
162+
// value = variant names
163+
Enum,
164+
// value = enum name + variant name + types
165+
Tuple,
166+
// value = [enum name +] name + fields
167+
Struct,
168+
// value = signature
169+
Trait,
170+
// value = type + generics
171+
Function,
172+
// value = type + generics
173+
Method,
174+
// No id, no value.
175+
Macro,
176+
// value = file_name
177+
Mod,
178+
// value = aliased type
179+
Type,
180+
// value = type and init expression (for all variable kinds).
181+
Static,
182+
Const,
183+
Field,
184+
}
185+
186+
impl From<EnumData> for Option<Def> {
187+
fn from(data: EnumData) -> Option<Def> {
188+
Some(Def {
189+
kind: DefKind::Enum,
190+
id: From::from(data.id),
191+
span: data.span,
192+
name: data.name,
193+
qualname: data.qualname,
194+
value: data.value,
195+
parent: None,
196+
children: data.variants.into_iter().map(|id| From::from(id)).collect(),
197+
decl_id: None,
198+
})
199+
}
200+
}
201+
202+
impl From<TupleVariantData> for Option<Def> {
203+
fn from(data: TupleVariantData) -> Option<Def> {
204+
Some(Def {
205+
kind: DefKind::Tuple,
206+
id: From::from(data.id),
207+
span: data.span,
208+
name: data.name,
209+
qualname: data.qualname,
210+
value: data.value,
211+
parent: None,
212+
children: vec![],
213+
decl_id: None,
214+
})
215+
}
216+
}
217+
impl From<StructVariantData> for Option<Def> {
218+
fn from(data: StructVariantData) -> Option<Def> {
219+
Some(Def {
220+
kind: DefKind::Struct,
221+
id: From::from(data.id),
222+
span: data.span,
223+
name: data.name,
224+
qualname: data.qualname,
225+
value: data.value,
226+
parent: None,
227+
children: vec![],
228+
decl_id: None,
229+
})
230+
}
231+
}
232+
impl From<StructData> for Option<Def> {
233+
fn from(data: StructData) -> Option<Def> {
234+
Some(Def {
235+
kind: DefKind::Struct,
236+
id: From::from(data.id),
237+
span: data.span,
238+
name: data.name,
239+
qualname: data.qualname,
240+
value: data.value,
241+
parent: None,
242+
children: data.fields.into_iter().map(|id| From::from(id)).collect(),
243+
decl_id: None,
244+
})
245+
}
246+
}
247+
impl From<TraitData> for Option<Def> {
248+
fn from(data: TraitData) -> Option<Def> {
249+
Some(Def {
250+
kind: DefKind::Trait,
251+
id: From::from(data.id),
252+
span: data.span,
253+
name: data.name,
254+
qualname: data.qualname,
255+
value: data.value,
256+
children: data.items.into_iter().map(|id| From::from(id)).collect(),
257+
parent: None,
258+
decl_id: None,
259+
})
260+
}
261+
}
262+
impl From<FunctionData> for Option<Def> {
263+
fn from(data: FunctionData) -> Option<Def> {
264+
Some(Def {
265+
kind: DefKind::Function,
266+
id: From::from(data.id),
267+
span: data.span,
268+
name: data.name,
269+
qualname: data.qualname,
270+
value: data.value,
271+
children: vec![],
272+
parent: None,
273+
decl_id: None,
274+
})
275+
}
276+
}
277+
impl From<MethodData> for Option<Def> {
278+
fn from(data: MethodData) -> Option<Def> {
279+
Some(Def {
280+
kind: DefKind::Method,
281+
id: From::from(data.id),
282+
span: data.span,
283+
name: data.name,
284+
qualname: data.qualname,
285+
value: data.value,
286+
children: vec![],
287+
parent: None,
288+
decl_id: data.decl_id.map(|id| From::from(id)),
289+
})
290+
}
291+
}
292+
impl From<MacroData> for Option<Def> {
293+
fn from(data: MacroData) -> Option<Def> {
294+
Some(Def {
295+
kind: DefKind::Macro,
296+
id: From::from(null_def_id()),
297+
span: data.span,
298+
name: data.name,
299+
qualname: data.qualname,
300+
value: String::new(),
301+
children: vec![],
302+
parent: None,
303+
decl_id: None,
304+
})
305+
}
306+
}
307+
impl From<ModData> for Option<Def> {
308+
fn from(data:ModData) -> Option<Def> {
309+
Some(Def {
310+
kind: DefKind::Mod,
311+
id: From::from(data.id),
312+
span: data.span,
313+
name: data.name,
314+
qualname: data.qualname,
315+
value: data.filename,
316+
children: data.items.into_iter().map(|id| From::from(id)).collect(),
317+
parent: None,
318+
decl_id: None,
319+
})
320+
}
321+
}
322+
impl From<TypeDefData> for Option<Def> {
323+
fn from(data: TypeDefData) -> Option<Def> {
324+
Some(Def {
325+
kind: DefKind::Type,
326+
id: From::from(data.id),
327+
span: data.span,
328+
name: data.name,
329+
qualname: data.qualname,
330+
value: data.value,
331+
children: vec![],
332+
parent: None,
333+
decl_id: None,
334+
})
335+
}
336+
}
337+
impl From<VariableData> for Option<Def> {
338+
fn from(data: VariableData) -> Option<Def> {
339+
Some(Def {
340+
kind: match data.kind {
341+
VariableKind::Static => DefKind::Static,
342+
VariableKind::Const => DefKind::Const,
343+
VariableKind::Local => { return None }
344+
VariableKind::Field => DefKind::Field,
345+
},
346+
id: From::from(data.id),
347+
span: data.span,
348+
name: data.name,
349+
qualname: data.qualname,
350+
value: data.value,
351+
children: vec![],
352+
parent: None,
353+
decl_id: None,
354+
})
355+
}
356+
}

src/librustc_save_analysis/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ extern crate serialize as rustc_serialize;
3030
extern crate syntax_pos;
3131

3232
mod csv_dumper;
33+
mod json_api_dumper;
3334
mod json_dumper;
3435
mod data;
3536
mod dump;
@@ -57,6 +58,7 @@ use syntax::codemap::MacroAttribute;
5758
use syntax_pos::*;
5859

5960
pub use self::csv_dumper::CsvDumper;
61+
pub use self::json_api_dumper::JsonApiDumper;
6062
pub use self::json_dumper::JsonDumper;
6163
pub use self::data::*;
6264
pub use self::dump::Dump;
@@ -804,7 +806,7 @@ pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>,
804806
match format {
805807
Format::Csv => dump!(CsvDumper::new(output)),
806808
Format::Json => dump!(JsonDumper::new(output)),
807-
Format::JsonApi => /* TODO */ dump!(JsonDumper::new(output)),
809+
Format::JsonApi => dump!(JsonApiDumper::new(output)),
808810
}
809811
}
810812

0 commit comments

Comments
 (0)