From c7dfc89f854f629816253f84ac0cc15d7792d63f Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 29 Aug 2016 13:29:12 +1200 Subject: [PATCH] JsonApiDumper --- src/librustc_save_analysis/json_api_dumper.rs | 356 ++++++++++++++++++ src/librustc_save_analysis/lib.rs | 4 +- 2 files changed, 359 insertions(+), 1 deletion(-) create mode 100644 src/librustc_save_analysis/json_api_dumper.rs diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs new file mode 100644 index 0000000000000..e92c23d7d7c5a --- /dev/null +++ b/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 or the MIT license +// , 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, + imports: Vec, + defs: Vec, +} + +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 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 for Option { + fn from(data: UseData) -> Option { + Some(Import { + kind: ImportKind::Use, + id: From::from(data.id), + span: data.span, + name: data.name, + value: String::new(), + }) + } +} +impl From for Option { + fn from(data: UseGlobData) -> Option { + 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, + children: Vec, + decl_id: Option, +} + +#[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 for Option { + fn from(data: EnumData) -> Option { + 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 for Option { + fn from(data: TupleVariantData) -> Option { + 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 for Option { + fn from(data: StructVariantData) -> Option { + 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 for Option { + fn from(data: StructData) -> Option { + 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 for Option { + fn from(data: TraitData) -> Option { + 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 for Option { + fn from(data: FunctionData) -> Option { + 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 for Option { + fn from(data: MethodData) -> Option { + 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 for Option { + fn from(data: MacroData) -> Option { + 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 for Option { + fn from(data:ModData) -> Option { + 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 for Option { + fn from(data: TypeDefData) -> Option { + 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 for Option { + fn from(data: VariableData) -> Option { + 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, + }) + } +} diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 77273bd3f2ed2..5aa8bec3d36c2 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -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; @@ -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; @@ -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)), } }