|
| 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 | +} |
0 commit comments