| // 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_serialize::json::as_json; |
| |
| use rls_data::config::Config; |
| use rls_data::{self, Analysis, CompilationOptions, CratePreludeData, Def, DefKind, Impl, Import, |
| MacroRef, Ref, RefKind, Relation}; |
| use rls_span::{Column, Row}; |
| |
| #[derive(Debug)] |
| pub struct Access { |
| pub reachable: bool, |
| pub public: bool, |
| } |
| |
| pub struct JsonDumper<O: DumpOutput> { |
| result: Analysis, |
| config: Config, |
| output: O, |
| } |
| |
| pub trait DumpOutput { |
| fn dump(&mut self, result: &Analysis); |
| } |
| |
| pub struct WriteOutput<'b, W: Write + 'b> { |
| output: &'b mut W, |
| } |
| |
| impl<'b, W: Write> DumpOutput for WriteOutput<'b, W> { |
| fn dump(&mut self, result: &Analysis) { |
| if write!(self.output, "{}", as_json(&result)).is_err() { |
| error!("Error writing output"); |
| } |
| } |
| } |
| |
| pub struct CallbackOutput<'b> { |
| callback: &'b mut dyn FnMut(&Analysis), |
| } |
| |
| impl<'b> DumpOutput for CallbackOutput<'b> { |
| fn dump(&mut self, result: &Analysis) { |
| (self.callback)(result) |
| } |
| } |
| |
| impl<'b, W: Write> JsonDumper<WriteOutput<'b, W>> { |
| pub fn new(writer: &'b mut W, config: Config) -> JsonDumper<WriteOutput<'b, W>> { |
| JsonDumper { |
| output: WriteOutput { output: writer }, |
| config: config.clone(), |
| result: Analysis::new(config), |
| } |
| } |
| } |
| |
| impl<'b> JsonDumper<CallbackOutput<'b>> { |
| pub fn with_callback( |
| callback: &'b mut dyn FnMut(&Analysis), |
| config: Config, |
| ) -> JsonDumper<CallbackOutput<'b>> { |
| JsonDumper { |
| output: CallbackOutput { callback: callback }, |
| config: config.clone(), |
| result: Analysis::new(config), |
| } |
| } |
| } |
| |
| impl<O: DumpOutput> Drop for JsonDumper<O> { |
| fn drop(&mut self) { |
| self.output.dump(&self.result); |
| } |
| } |
| |
| impl<'b, O: DumpOutput + 'b> JsonDumper<O> { |
| pub fn crate_prelude(&mut self, data: CratePreludeData) { |
| self.result.prelude = Some(data) |
| } |
| |
| pub fn compilation_opts(&mut self, data: CompilationOptions) { |
| self.result.compilation = Some(data); |
| } |
| |
| pub fn _macro_use(&mut self, data: MacroRef) { |
| if self.config.pub_only || self.config.reachable_only { |
| return; |
| } |
| self.result.macro_refs.push(data); |
| } |
| |
| pub fn import(&mut self, access: &Access, import: Import) { |
| if !access.public && self.config.pub_only |
| || !access.reachable && self.config.reachable_only { |
| return; |
| } |
| self.result.imports.push(import); |
| } |
| |
| pub fn dump_ref(&mut self, data: Ref) { |
| if self.config.pub_only || self.config.reachable_only { |
| return; |
| } |
| self.result.refs.push(data); |
| } |
| |
| pub fn dump_def(&mut self, access: &Access, mut data: Def) { |
| if !access.public && self.config.pub_only |
| || !access.reachable && self.config.reachable_only { |
| return; |
| } |
| if data.kind == DefKind::Mod && data.span.file_name.to_str().unwrap() != data.value { |
| // If the module is an out-of-line definition, then we'll make the |
| // definition the first character in the module's file and turn |
| // the declaration into a reference to it. |
| let rf = Ref { |
| kind: RefKind::Mod, |
| span: data.span, |
| ref_id: data.id, |
| }; |
| self.result.refs.push(rf); |
| data.span = rls_data::SpanData { |
| file_name: data.value.clone().into(), |
| byte_start: 0, |
| byte_end: 0, |
| line_start: Row::new_one_indexed(1), |
| line_end: Row::new_one_indexed(1), |
| column_start: Column::new_one_indexed(1), |
| column_end: Column::new_one_indexed(1), |
| } |
| } |
| self.result.defs.push(data); |
| } |
| |
| pub fn dump_relation(&mut self, data: Relation) { |
| self.result.relations.push(data); |
| } |
| |
| pub fn dump_impl(&mut self, data: Impl) { |
| self.result.impls.push(data); |
| } |
| } |