]> git.lizzy.rs Git - rust.git/blob - src/librustc_save_analysis/json_dumper.rs
Rollup merge of #54564 - alexcrichton:new-notes, r=kennytm
[rust.git] / src / librustc_save_analysis / json_dumper.rs
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_serialize::json::as_json;
14
15 use rls_data::config::Config;
16 use rls_data::{self, Analysis, CompilationOptions, CratePreludeData, Def, DefKind, Impl, Import,
17                MacroRef, Ref, RefKind, Relation};
18 use rls_span::{Column, Row};
19
20 #[derive(Debug)]
21 pub struct Access {
22     pub reachable: bool,
23     pub public: bool,
24 }
25
26 pub struct JsonDumper<O: DumpOutput> {
27     result: Analysis,
28     config: Config,
29     output: O,
30 }
31
32 pub trait DumpOutput {
33     fn dump(&mut self, result: &Analysis);
34 }
35
36 pub struct WriteOutput<'b, W: Write + 'b> {
37     output: &'b mut W,
38 }
39
40 impl<'b, W: Write> DumpOutput for WriteOutput<'b, W> {
41     fn dump(&mut self, result: &Analysis) {
42         if write!(self.output, "{}", as_json(&result)).is_err() {
43             error!("Error writing output");
44         }
45     }
46 }
47
48 pub struct CallbackOutput<'b> {
49     callback: &'b mut dyn FnMut(&Analysis),
50 }
51
52 impl<'b> DumpOutput for CallbackOutput<'b> {
53     fn dump(&mut self, result: &Analysis) {
54         (self.callback)(result)
55     }
56 }
57
58 impl<'b, W: Write> JsonDumper<WriteOutput<'b, W>> {
59     pub fn new(writer: &'b mut W, config: Config) -> JsonDumper<WriteOutput<'b, W>> {
60         JsonDumper {
61             output: WriteOutput { output: writer },
62             config: config.clone(),
63             result: Analysis::new(config),
64         }
65     }
66 }
67
68 impl<'b> JsonDumper<CallbackOutput<'b>> {
69     pub fn with_callback(
70         callback: &'b mut dyn FnMut(&Analysis),
71         config: Config,
72     ) -> JsonDumper<CallbackOutput<'b>> {
73         JsonDumper {
74             output: CallbackOutput { callback: callback },
75             config: config.clone(),
76             result: Analysis::new(config),
77         }
78     }
79 }
80
81 impl<O: DumpOutput> Drop for JsonDumper<O> {
82     fn drop(&mut self) {
83         self.output.dump(&self.result);
84     }
85 }
86
87 impl<'b, O: DumpOutput + 'b> JsonDumper<O> {
88     pub fn crate_prelude(&mut self, data: CratePreludeData) {
89         self.result.prelude = Some(data)
90     }
91
92     pub fn compilation_opts(&mut self, data: CompilationOptions) {
93         self.result.compilation = Some(data);
94     }
95
96     pub fn macro_use(&mut self, data: MacroRef) {
97         if self.config.pub_only || self.config.reachable_only {
98             return;
99         }
100         self.result.macro_refs.push(data);
101     }
102
103     pub fn import(&mut self, access: &Access, import: Import) {
104         if !access.public && self.config.pub_only
105             || !access.reachable && self.config.reachable_only {
106             return;
107         }
108         self.result.imports.push(import);
109     }
110
111     pub fn dump_ref(&mut self, data: Ref) {
112         if self.config.pub_only || self.config.reachable_only {
113             return;
114         }
115         self.result.refs.push(data);
116     }
117
118     pub fn dump_def(&mut self, access: &Access, mut data: Def) {
119         if !access.public && self.config.pub_only
120             || !access.reachable && self.config.reachable_only {
121             return;
122         }
123         if data.kind == DefKind::Mod && data.span.file_name.to_str().unwrap() != data.value {
124             // If the module is an out-of-line definition, then we'll make the
125             // definition the first character in the module's file and turn
126             // the declaration into a reference to it.
127             let rf = Ref {
128                 kind: RefKind::Mod,
129                 span: data.span,
130                 ref_id: data.id,
131             };
132             self.result.refs.push(rf);
133             data.span = rls_data::SpanData {
134                 file_name: data.value.clone().into(),
135                 byte_start: 0,
136                 byte_end: 0,
137                 line_start: Row::new_one_indexed(1),
138                 line_end: Row::new_one_indexed(1),
139                 column_start: Column::new_one_indexed(1),
140                 column_end: Column::new_one_indexed(1),
141             }
142         }
143         self.result.defs.push(data);
144     }
145
146     pub fn dump_relation(&mut self, data: Relation) {
147         self.result.relations.push(data);
148     }
149
150     pub fn dump_impl(&mut self, data: Impl) {
151         self.result.impls.push(data);
152     }
153 }