rust/src/librustc_save_analysis/json_dumper.rs

605 lines
16 KiB
Rust
Raw Normal View History

2016-04-25 03:54:00 -05:00
// 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;
2016-04-25 03:54:00 -05:00
use rustc_serialize::json::as_json;
use external_data::*;
2016-11-21 15:05:25 -06:00
use data::{VariableKind, SigElement};
use dump::Dump;
use super::Format;
2016-04-25 03:54:00 -05:00
pub struct JsonDumper<'b, W: Write + 'b> {
2016-04-25 03:54:00 -05:00
output: &'b mut W,
result: Analysis,
2016-04-25 03:54:00 -05:00
}
impl<'b, W: Write> JsonDumper<'b, W> {
pub fn new(writer: &'b mut W) -> JsonDumper<'b, W> {
JsonDumper { output: writer, result: Analysis::new() }
}
}
impl<'b, W: Write> Drop for JsonDumper<'b, W> {
fn drop(&mut self) {
if let Err(_) = write!(self.output, "{}", as_json(&self.result)) {
error!("Error writing output");
}
2016-04-25 03:54:00 -05:00
}
}
macro_rules! impl_fn {
2016-05-12 18:29:07 -05:00
($fn_name: ident, $data_type: ident, $bucket: ident) => {
fn $fn_name(&mut self, data: $data_type) {
2016-05-12 18:29:07 -05:00
self.result.$bucket.push(From::from(data));
}
2016-04-25 03:54:00 -05:00
}
}
impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> {
fn crate_prelude(&mut self, data: CratePreludeData) {
self.result.prelude = Some(data)
}
impl_fn!(extern_crate, ExternCrateData, imports);
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!(typedef, TypeDefData, defs);
impl_fn!(variable, VariableData, defs);
impl_fn!(function_ref, FunctionRefData, refs);
impl_fn!(function_call, FunctionCallData, refs);
impl_fn!(method_call, MethodCallData, refs);
impl_fn!(mod_ref, ModRefData, refs);
impl_fn!(type_ref, TypeRefData, refs);
impl_fn!(variable_ref, VariableRefData, refs);
impl_fn!(macro_use, MacroUseData, macro_refs);
fn mod_data(&mut self, data: ModData) {
let id: Id = From::from(data.id);
let mut def = Def {
kind: DefKind::Mod,
id: id,
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.filename,
children: data.items.into_iter().map(|id| From::from(id)).collect(),
decl_id: None,
docs: data.docs,
sig: Some(From::from(data.sig)),
attributes: data.attributes,
};
if def.span.file_name != def.value {
// If the module is an out-of-line defintion, then we'll make the
// defintion the first character in the module's file and turn the
// the declaration into a reference to it.
let rf = Ref {
kind: RefKind::Mod,
span: def.span,
ref_id: id,
};
self.result.refs.push(rf);
def.span = SpanData {
file_name: def.value.clone(),
byte_start: 0,
byte_end: 0,
line_start: 1,
line_end: 1,
column_start: 1,
column_end: 1,
}
}
self.result.defs.push(def);
}
fn impl_data(&mut self, data: ImplData) {
if data.self_ref.is_some() {
self.result.relations.push(From::from(data));
}
}
fn inheritance(&mut self, data: InheritanceData) {
self.result.relations.push(From::from(data));
}
}
// FIXME do we want to change ExternalData to this mode? It will break DXR.
// 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 {
kind: Format,
prelude: Option<CratePreludeData>,
imports: Vec<Import>,
defs: Vec<Def>,
refs: Vec<Ref>,
macro_refs: Vec<MacroRef>,
relations: Vec<Relation>,
}
impl Analysis {
fn new() -> Analysis {
Analysis {
kind: Format::Json,
prelude: None,
imports: vec![],
defs: vec![],
refs: vec![],
macro_refs: vec![],
relations: vec![],
}
}
}
2016-05-12 18:29:07 -05:00
// 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(Clone, Copy, Debug, RustcEncodable)]
2016-05-12 18:29:07 -05:00
struct Id {
krate: u32,
index: u32,
}
impl From<DefId> for Id {
fn from(id: DefId) -> Id {
Id {
krate: id.krate.as_u32(),
2016-05-12 18:29:07 -05:00
index: id.index.as_u32(),
}
}
}
#[derive(Debug, RustcEncodable)]
struct Import {
kind: ImportKind,
ref_id: Option<Id>,
span: SpanData,
name: String,
value: String,
}
#[derive(Debug, RustcEncodable)]
enum ImportKind {
ExternCrate,
Use,
GlobUse,
}
impl From<ExternCrateData> for Import {
fn from(data: ExternCrateData) -> Import {
Import {
kind: ImportKind::ExternCrate,
ref_id: None,
span: data.span,
name: data.name,
value: String::new(),
}
}
}
impl From<UseData> for Import {
fn from(data: UseData) -> Import {
Import {
kind: ImportKind::Use,
ref_id: data.mod_id.map(|id| From::from(id)),
span: data.span,
name: data.name,
value: String::new(),
}
}
}
impl From<UseGlobData> for Import {
fn from(data: UseGlobData) -> Import {
Import {
kind: ImportKind::GlobUse,
ref_id: None,
span: data.span,
name: "*".to_owned(),
value: data.names.join(", "),
}
}
}
#[derive(Debug, RustcEncodable)]
struct Def {
kind: DefKind,
2016-05-12 18:29:07 -05:00
id: Id,
span: SpanData,
name: String,
qualname: String,
value: String,
children: Vec<Id>,
decl_id: Option<Id>,
2016-09-06 18:23:49 -05:00
docs: String,
2016-11-21 15:05:25 -06:00
sig: Option<JsonSignature>,
attributes: Vec<Attribute>,
}
#[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).
Local,
Static,
Const,
Field,
}
impl From<EnumData> for Def {
fn from(data: EnumData) -> Def {
Def {
kind: DefKind::Enum,
2016-05-12 18:29:07 -05:00
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
children: data.variants.into_iter().map(|id| From::from(id)).collect(),
decl_id: None,
2016-09-06 18:23:49 -05:00
docs: data.docs,
sig: Some(From::from(data.sig)),
attributes: data.attributes,
}
}
}
impl From<TupleVariantData> for Def {
fn from(data: TupleVariantData) -> Def {
Def {
kind: DefKind::Tuple,
2016-05-12 18:29:07 -05:00
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
children: vec![],
decl_id: None,
2016-09-06 18:23:49 -05:00
docs: data.docs,
sig: Some(From::from(data.sig)),
attributes: data.attributes,
}
}
}
impl From<StructVariantData> for Def {
fn from(data: StructVariantData) -> Def {
Def {
kind: DefKind::Struct,
2016-05-12 18:29:07 -05:00
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
children: vec![],
decl_id: None,
2016-09-06 18:23:49 -05:00
docs: data.docs,
sig: Some(From::from(data.sig)),
attributes: data.attributes,
}
}
}
impl From<StructData> for Def {
fn from(data: StructData) -> Def {
Def {
kind: DefKind::Struct,
2016-05-12 18:29:07 -05:00
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
children: data.fields.into_iter().map(|id| From::from(id)).collect(),
decl_id: None,
2016-09-06 18:23:49 -05:00
docs: data.docs,
2016-11-21 15:05:25 -06:00
sig: Some(From::from(data.sig)),
attributes: data.attributes,
}
}
}
impl From<TraitData> for Def {
fn from(data: TraitData) -> Def {
Def {
kind: DefKind::Trait,
2016-05-12 18:29:07 -05:00
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(),
decl_id: None,
2016-09-06 18:23:49 -05:00
docs: data.docs,
sig: Some(From::from(data.sig)),
attributes: data.attributes,
}
}
}
impl From<FunctionData> for Def {
fn from(data: FunctionData) -> Def {
Def {
kind: DefKind::Function,
2016-05-12 18:29:07 -05:00
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
children: vec![],
decl_id: None,
2016-09-06 18:23:49 -05:00
docs: data.docs,
sig: Some(From::from(data.sig)),
attributes: data.attributes,
}
}
}
impl From<MethodData> for Def {
fn from(data: MethodData) -> Def {
Def {
kind: DefKind::Method,
2016-05-12 18:29:07 -05:00
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
children: vec![],
decl_id: data.decl_id.map(|id| From::from(id)),
2016-09-06 18:23:49 -05:00
docs: data.docs,
sig: Some(From::from(data.sig)),
attributes: data.attributes,
}
}
}
impl From<MacroData> for Def {
fn from(data: MacroData) -> Def {
Def {
kind: DefKind::Macro,
2016-05-12 18:29:07 -05:00
id: From::from(null_def_id()),
span: data.span,
name: data.name,
qualname: data.qualname,
value: String::new(),
children: vec![],
decl_id: None,
2016-09-06 18:23:49 -05:00
docs: data.docs,
sig: None,
attributes: vec![],
}
}
}
impl From<TypeDefData> for Def {
fn from(data: TypeDefData) -> Def {
Def {
kind: DefKind::Type,
2016-05-12 18:29:07 -05:00
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
children: vec![],
decl_id: None,
2016-09-06 18:23:49 -05:00
docs: String::new(),
sig: data.sig.map(|s| From::from(s)),
attributes: data.attributes,
}
}
}
impl From<VariableData> for Def {
fn from(data: VariableData) -> Def {
Def {
kind: match data.kind {
VariableKind::Static => DefKind::Static,
VariableKind::Const => DefKind::Const,
VariableKind::Local => DefKind::Local,
VariableKind::Field => DefKind::Field,
},
2016-05-12 18:29:07 -05:00
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.type_value,
children: vec![],
decl_id: None,
2016-09-06 18:23:49 -05:00
docs: data.docs,
sig: None,
attributes: data.attributes,
}
}
}
#[derive(Debug, RustcEncodable)]
enum RefKind {
Function,
Mod,
Type,
Variable,
}
#[derive(Debug, RustcEncodable)]
struct Ref {
kind: RefKind,
span: SpanData,
2016-05-12 18:29:07 -05:00
ref_id: Id,
}
impl From<FunctionRefData> for Ref {
fn from(data: FunctionRefData) -> Ref {
Ref {
kind: RefKind::Function,
span: data.span,
2016-05-12 18:29:07 -05:00
ref_id: From::from(data.ref_id),
}
}
}
impl From<FunctionCallData> for Ref {
fn from(data: FunctionCallData) -> Ref {
Ref {
kind: RefKind::Function,
span: data.span,
2016-05-12 18:29:07 -05:00
ref_id: From::from(data.ref_id),
}
}
}
impl From<MethodCallData> for Ref {
fn from(data: MethodCallData) -> Ref {
Ref {
kind: RefKind::Function,
span: data.span,
2016-05-12 18:29:07 -05:00
ref_id: From::from(data.ref_id.or(data.decl_id).unwrap_or(null_def_id())),
}
}
}
impl From<ModRefData> for Ref {
fn from(data: ModRefData) -> Ref {
Ref {
kind: RefKind::Mod,
span: data.span,
2016-05-12 18:29:07 -05:00
ref_id: From::from(data.ref_id.unwrap_or(null_def_id())),
}
}
}
impl From<TypeRefData> for Ref {
fn from(data: TypeRefData) -> Ref {
Ref {
kind: RefKind::Type,
span: data.span,
2016-05-12 18:29:07 -05:00
ref_id: From::from(data.ref_id.unwrap_or(null_def_id())),
}
}
}
impl From<VariableRefData> for Ref {
fn from(data: VariableRefData) -> Ref {
Ref {
kind: RefKind::Variable,
span: data.span,
2016-05-12 18:29:07 -05:00
ref_id: From::from(data.ref_id),
}
}
}
#[derive(Debug, RustcEncodable)]
struct MacroRef {
span: SpanData,
qualname: String,
callee_span: SpanData,
}
impl From<MacroUseData> for MacroRef {
fn from(data: MacroUseData) -> MacroRef {
MacroRef {
span: data.span,
qualname: data.qualname,
callee_span: data.callee_span,
}
}
2016-04-25 03:54:00 -05:00
}
2016-11-21 15:05:25 -06:00
#[derive(Debug, RustcEncodable)]
struct Relation {
span: SpanData,
kind: RelationKind,
from: Id,
to: Id,
}
#[derive(Debug, RustcEncodable)]
enum RelationKind {
Impl,
SuperTrait,
}
impl From<ImplData> for Relation {
fn from(data: ImplData) -> Relation {
Relation {
span: data.span,
kind: RelationKind::Impl,
from: From::from(data.self_ref.unwrap_or(null_def_id())),
to: From::from(data.trait_ref.unwrap_or(null_def_id())),
}
}
}
impl From<InheritanceData> for Relation {
fn from(data: InheritanceData) -> Relation {
Relation {
span: data.span,
kind: RelationKind::SuperTrait,
from: From::from(data.base_id),
to: From::from(data.deriv_id),
}
}
}
2016-11-21 15:05:25 -06:00
#[derive(Debug, RustcEncodable)]
pub struct JsonSignature {
span: SpanData,
text: String,
ident_start: usize,
ident_end: usize,
defs: Vec<JsonSigElement>,
refs: Vec<JsonSigElement>,
}
impl From<Signature> for JsonSignature {
fn from(data: Signature) -> JsonSignature {
JsonSignature {
span: data.span,
text: data.text,
ident_start: data.ident_start,
ident_end: data.ident_end,
defs: data.defs.into_iter().map(|s| From::from(s)).collect(),
refs: data.refs.into_iter().map(|s| From::from(s)).collect(),
}
}
}
#[derive(Debug, RustcEncodable)]
pub struct JsonSigElement {
id: Id,
start: usize,
end: usize,
}
impl From<SigElement> for JsonSigElement {
fn from(data: SigElement) -> JsonSigElement {
JsonSigElement {
id: From::from(data.id),
start: data.start,
end: data.end,
}
}
}