Skip to content

Commit

Permalink
JsonApiDumper
Browse files Browse the repository at this point in the history
  • Loading branch information
nrc committed Sep 1, 2016
1 parent cbafc57 commit c7dfc89
Show file tree
Hide file tree
Showing 2 changed files with 359 additions and 1 deletion.
356 changes: 356 additions & 0 deletions src/librustc_save_analysis/json_api_dumper.rs
@@ -0,0 +1,356 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::io::Write;

use rustc::hir::def_id::DefId;
use rustc_serialize::json::as_json;

use external_data::*;
use data::VariableKind;
use dump::Dump;

pub struct JsonApiDumper<'b, W: Write + 'b> {
output: &'b mut W,
result: Analysis,
}

impl<'b, W: Write> JsonApiDumper<'b, W> {
pub fn new(writer: &'b mut W) -> JsonApiDumper<'b, W> {
JsonApiDumper { output: writer, result: Analysis::new() }
}
}

impl<'b, W: Write> Drop for JsonApiDumper<'b, W> {
fn drop(&mut self) {
if let Err(_) = write!(self.output, "{}", as_json(&self.result)) {
error!("Error writing output");
}
}
}

macro_rules! impl_fn {
($fn_name: ident, $data_type: ident, $bucket: ident) => {
fn $fn_name(&mut self, data: $data_type) {
if let Some(datum) = From::from(data) {
self.result.$bucket.push(datum);
}
}
}
}

impl<'b, W: Write + 'b> Dump for JsonApiDumper<'b, W> {
fn crate_prelude(&mut self, data: CratePreludeData) {
self.result.prelude = Some(data)
}

impl_fn!(use_data, UseData, imports);
impl_fn!(use_glob, UseGlobData, imports);

impl_fn!(enum_data, EnumData, defs);
impl_fn!(tuple_variant, TupleVariantData, defs);
impl_fn!(struct_variant, StructVariantData, defs);
impl_fn!(struct_data, StructData, defs);
impl_fn!(trait_data, TraitData, defs);
impl_fn!(function, FunctionData, defs);
impl_fn!(method, MethodData, defs);
impl_fn!(macro_data, MacroData, defs);
impl_fn!(mod_data, ModData, defs);
impl_fn!(typedef, TypeDefData, defs);
impl_fn!(variable, VariableData, defs);
}

// FIXME methods. The defs have information about possible overriding and the
// refs have decl information (e.g., a trait method where we know the required
// method, but not the supplied method). In both cases, we are currently
// ignoring it.

#[derive(Debug, RustcEncodable)]
struct Analysis {
prelude: Option<CratePreludeData>,
imports: Vec<Import>,
defs: Vec<Def>,
}

impl Analysis {
fn new() -> Analysis {
Analysis {
prelude: None,
imports: vec![],
defs: vec![],
}
}
}

// DefId::index is a newtype and so the JSON serialisation is ugly. Therefore
// we use our own Id which is the same, but without the newtype.
#[derive(Debug, RustcEncodable)]
struct Id {
krate: u32,
index: u32,
}

impl From<DefId> for Id {
fn from(id: DefId) -> Id {
Id {
krate: id.krate,
index: id.index.as_u32(),
}
}
}

#[derive(Debug, RustcEncodable)]
struct Import {
kind: ImportKind,
id: Id,
span: SpanData,
name: String,
value: String,
}

#[derive(Debug, RustcEncodable)]
enum ImportKind {
Use,
GlobUse,
}

impl From<UseData> for Option<Import> {
fn from(data: UseData) -> Option<Import> {
Some(Import {
kind: ImportKind::Use,
id: From::from(data.id),
span: data.span,
name: data.name,
value: String::new(),
})
}
}
impl From<UseGlobData> for Option<Import> {
fn from(data: UseGlobData) -> Option<Import> {
Some(Import {
kind: ImportKind::GlobUse,
id: From::from(data.id),
span: data.span,
name: "*".to_owned(),
value: data.names.join(", "),
})
}
}

#[derive(Debug, RustcEncodable)]
struct Def {
kind: DefKind,
id: Id,
span: SpanData,
name: String,
qualname: String,
value: String,
parent: Option<Id>,
children: Vec<Id>,
decl_id: Option<Id>,
}

#[derive(Debug, RustcEncodable)]
enum DefKind {
// value = variant names
Enum,
// value = enum name + variant name + types
Tuple,
// value = [enum name +] name + fields
Struct,
// value = signature
Trait,
// value = type + generics
Function,
// value = type + generics
Method,
// No id, no value.
Macro,
// value = file_name
Mod,
// value = aliased type
Type,
// value = type and init expression (for all variable kinds).
Static,
Const,
Field,
}

impl From<EnumData> for Option<Def> {
fn from(data: EnumData) -> Option<Def> {
Some(Def {
kind: DefKind::Enum,
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
parent: None,
children: data.variants.into_iter().map(|id| From::from(id)).collect(),
decl_id: None,
})
}
}

impl From<TupleVariantData> for Option<Def> {
fn from(data: TupleVariantData) -> Option<Def> {
Some(Def {
kind: DefKind::Tuple,
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
parent: None,
children: vec![],
decl_id: None,
})
}
}
impl From<StructVariantData> for Option<Def> {
fn from(data: StructVariantData) -> Option<Def> {
Some(Def {
kind: DefKind::Struct,
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
parent: None,
children: vec![],
decl_id: None,
})
}
}
impl From<StructData> for Option<Def> {
fn from(data: StructData) -> Option<Def> {
Some(Def {
kind: DefKind::Struct,
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
parent: None,
children: data.fields.into_iter().map(|id| From::from(id)).collect(),
decl_id: None,
})
}
}
impl From<TraitData> for Option<Def> {
fn from(data: TraitData) -> Option<Def> {
Some(Def {
kind: DefKind::Trait,
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
children: data.items.into_iter().map(|id| From::from(id)).collect(),
parent: None,
decl_id: None,
})
}
}
impl From<FunctionData> for Option<Def> {
fn from(data: FunctionData) -> Option<Def> {
Some(Def {
kind: DefKind::Function,
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
children: vec![],
parent: None,
decl_id: None,
})
}
}
impl From<MethodData> for Option<Def> {
fn from(data: MethodData) -> Option<Def> {
Some(Def {
kind: DefKind::Method,
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
children: vec![],
parent: None,
decl_id: data.decl_id.map(|id| From::from(id)),
})
}
}
impl From<MacroData> for Option<Def> {
fn from(data: MacroData) -> Option<Def> {
Some(Def {
kind: DefKind::Macro,
id: From::from(null_def_id()),
span: data.span,
name: data.name,
qualname: data.qualname,
value: String::new(),
children: vec![],
parent: None,
decl_id: None,
})
}
}
impl From<ModData> for Option<Def> {
fn from(data:ModData) -> Option<Def> {
Some(Def {
kind: DefKind::Mod,
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.filename,
children: data.items.into_iter().map(|id| From::from(id)).collect(),
parent: None,
decl_id: None,
})
}
}
impl From<TypeDefData> for Option<Def> {
fn from(data: TypeDefData) -> Option<Def> {
Some(Def {
kind: DefKind::Type,
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
children: vec![],
parent: None,
decl_id: None,
})
}
}
impl From<VariableData> for Option<Def> {
fn from(data: VariableData) -> Option<Def> {
Some(Def {
kind: match data.kind {
VariableKind::Static => DefKind::Static,
VariableKind::Const => DefKind::Const,
VariableKind::Local => { return None }
VariableKind::Field => DefKind::Field,
},
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
children: vec![],
parent: None,
decl_id: None,
})
}
}
4 changes: 3 additions & 1 deletion src/librustc_save_analysis/lib.rs
Expand Up @@ -30,6 +30,7 @@ extern crate serialize as rustc_serialize;
extern crate syntax_pos;

mod csv_dumper;
mod json_api_dumper;
mod json_dumper;
mod data;
mod dump;
Expand Down Expand Up @@ -57,6 +58,7 @@ use syntax::codemap::MacroAttribute;
use syntax_pos::*;

pub use self::csv_dumper::CsvDumper;
pub use self::json_api_dumper::JsonApiDumper;
pub use self::json_dumper::JsonDumper;
pub use self::data::*;
pub use self::dump::Dump;
Expand Down Expand Up @@ -804,7 +806,7 @@ pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>,
match format {
Format::Csv => dump!(CsvDumper::new(output)),
Format::Json => dump!(JsonDumper::new(output)),
Format::JsonApi => /* TODO */ dump!(JsonDumper::new(output)),
Format::JsonApi => dump!(JsonApiDumper::new(output)),
}
}

Expand Down

0 comments on commit c7dfc89

Please sign in to comment.