@@ -11,6 +11,8 @@ extern crate rustc_driver;
11
11
#[ allow( unused_extern_crates) ]
12
12
extern crate rustc_errors;
13
13
#[ allow( unused_extern_crates) ]
14
+ extern crate rustc_interface;
15
+ #[ allow( unused_extern_crates) ]
14
16
extern crate rustc_metadata;
15
17
#[ allow( unused_extern_crates) ]
16
18
extern crate rustc_plugin;
@@ -37,10 +39,10 @@ use crate::build::environment::{Environment, EnvironmentLockFacade};
37
39
use crate :: build:: { BufWriter , BuildResult } ;
38
40
use crate :: build:: plan:: { Crate , Edition } ;
39
41
use crate :: config:: { ClippyPreference , Config } ;
40
- use self :: rustc_driver:: driver:: CompileController ;
41
- use self :: rustc_driver:: { run, run_compiler, CompilerCalls , RustcDefaultCalls } ;
42
+ use self :: rustc_driver:: { run_compiler} ;
42
43
use self :: rustc_save_analysis as save;
43
44
use self :: rustc_save_analysis:: CallbackHandler ;
45
+ use self :: rustc_interface:: interface;
44
46
use self :: rustc:: session:: Session ;
45
47
use self :: rustc:: session:: config:: Input ;
46
48
use self :: syntax:: source_map:: { FileLoader , RealFileLoader } ;
@@ -68,7 +70,7 @@ pub(crate) fn rustc(
68
70
69
71
let mut local_envs = envs. clone ( ) ;
70
72
71
- let clippy_pref = {
73
+ let clippy_preference = {
72
74
let config = rls_config. lock ( ) . unwrap ( ) ;
73
75
if config. clear_env_rust_log {
74
76
local_envs. insert ( String :: from ( "RUST_LOG" ) , None ) ;
@@ -84,11 +86,11 @@ pub(crate) fn rustc(
84
86
85
87
let buf = Arc :: new ( Mutex :: new ( vec ! [ ] ) ) ;
86
88
let err_buf = buf. clone ( ) ;
87
- let args: Vec < _ > = if cfg ! ( feature = "clippy" ) && clippy_pref != ClippyPreference :: Off {
89
+ let args: Vec < _ > = if cfg ! ( feature = "clippy" ) && clippy_preference != ClippyPreference :: Off {
88
90
// Allow feature gating in the same way as `cargo clippy`
89
91
let mut clippy_args = vec ! [ "--cfg" . to_owned( ) , r#"feature="cargo-clippy""# . to_owned( ) ] ;
90
92
91
- if clippy_pref == ClippyPreference :: OptIn {
93
+ if clippy_preference == ClippyPreference :: OptIn {
92
94
// `OptIn`: Require explicit `#![warn(clippy::all)]` annotation in each workspace crate
93
95
clippy_args. push ( "-A" . to_owned ( ) ) ;
94
96
clippy_args. push ( "clippy::all" . to_owned ( ) ) ;
@@ -99,21 +101,20 @@ pub(crate) fn rustc(
99
101
args. to_owned ( )
100
102
} ;
101
103
102
- let analysis = Arc :: default ( ) ;
103
- let input_files = Arc :: default ( ) ;
104
- let controller =
105
- Box :: new ( RlsRustcCalls :: new ( Arc :: clone ( & analysis) , Arc :: clone ( & input_files) , clippy_pref) ) ;
104
+ let mut callbacks = RlsRustcCalls { clippy_preference, ..Default :: default ( ) } ;
105
+ let analysis = Arc :: clone ( & callbacks. analysis ) ;
106
+ let input_files = Arc :: clone ( & callbacks. input_files ) ;
106
107
107
108
// rustc explicitly panics in `run_compiler()` on compile failure, regardless
108
109
// of whether it encounters an ICE (internal compiler error) or not.
109
110
// TODO: Change librustc_driver behaviour to distinguish between ICEs and
110
111
// regular compilation failure with errors?
111
112
let result = :: std:: panic:: catch_unwind ( || {
112
- run ( move || {
113
+ rustc_driver :: report_ices_to_stderr_if_any ( move || {
113
114
// Replace stderr so we catch most errors.
114
115
run_compiler (
115
116
& args,
116
- controller ,
117
+ & mut callbacks ,
117
118
Some ( Box :: new ( ReplacedFileLoader :: new ( changed) ) ) ,
118
119
Some ( Box :: new ( BufWriter ( buf) ) ) ,
119
120
)
@@ -139,36 +140,113 @@ pub(crate) fn rustc(
139
140
140
141
// Our compiler controller. We mostly delegate to the default rustc
141
142
// controller, but use our own callback for save-analysis.
142
- #[ derive( Clone ) ]
143
+ #[ derive( Clone , Default ) ]
143
144
struct RlsRustcCalls {
144
145
analysis : Arc < Mutex < Option < Analysis > > > ,
145
146
input_files : Arc < Mutex < HashMap < PathBuf , HashSet < Crate > > > > ,
146
147
clippy_preference : ClippyPreference ,
147
148
}
148
149
149
- impl RlsRustcCalls {
150
- fn new (
151
- analysis : Arc < Mutex < Option < Analysis > > > ,
152
- input_files : Arc < Mutex < HashMap < PathBuf , HashSet < Crate > > > > ,
153
- clippy_preference : ClippyPreference ,
154
- ) -> RlsRustcCalls {
155
- RlsRustcCalls { analysis, input_files, clippy_preference }
150
+ impl rustc_driver:: Callbacks for RlsRustcCalls {
151
+ fn config ( & mut self , config : & mut interface:: Config ) {
152
+ // This also prevents the compiler from dropping expanded AST, which we
153
+ // still need in the `after_analysis` callback in order to process and
154
+ // pass the computed analysis in-memory.
155
+ config. opts . debugging_opts . save_analysis = true ;
156
+ }
157
+
158
+ fn after_parsing ( & mut self , _compiler : & interface:: Compiler ) -> bool {
159
+ #[ cfg( feature = "clippy" ) ]
160
+ {
161
+ if self . clippy_preference != ClippyPreference :: Off {
162
+ clippy_after_parse_callback ( _compiler) ;
163
+ }
164
+ }
165
+ // Continue execution
166
+ true
167
+ }
168
+
169
+ fn after_analysis ( & mut self , compiler : & interface:: Compiler ) -> bool {
170
+ let sess = compiler. session ( ) ;
171
+ let input = compiler. input ( ) ;
172
+ let crate_name = compiler. crate_name ( ) . unwrap ( ) . peek ( ) . clone ( ) ;
173
+
174
+ let cwd = & sess. working_dir . 0 ;
175
+
176
+ let src_path = match input {
177
+ Input :: File ( ref name) => Some ( name. to_path_buf ( ) ) ,
178
+ Input :: Str { .. } => None ,
179
+ }
180
+ . and_then ( |path| src_path ( Some ( cwd) , path) ) ;
181
+
182
+ let krate = Crate {
183
+ name : crate_name. to_owned ( ) ,
184
+ src_path,
185
+ disambiguator : sess. local_crate_disambiguator ( ) . to_fingerprint ( ) . as_value ( ) ,
186
+ edition : match sess. edition ( ) {
187
+ RustcEdition :: Edition2015 => Edition :: Edition2015 ,
188
+ RustcEdition :: Edition2018 => Edition :: Edition2018 ,
189
+ } ,
190
+ } ;
191
+ let files = fetch_input_files ( sess) ;
192
+
193
+ let mut input_files = self . input_files . lock ( ) . unwrap ( ) ;
194
+ for file in & files {
195
+ input_files. entry ( file. to_path_buf ( ) ) . or_default ( ) . insert ( krate. clone ( ) ) ;
196
+ }
197
+
198
+ // Guaranteed to not be dropped yet in the pipeline thanks to the
199
+ // `config.opts.debugging_opts.save_analysis` value being set to `true`.
200
+ let expanded_crate = & compiler. expansion ( ) . unwrap ( ) . peek ( ) . 0 ;
201
+ compiler. global_ctxt ( ) . unwrap ( ) . peek_mut ( ) . enter ( |tcx| {
202
+ // There are two ways to move the data from rustc to the RLS, either
203
+ // directly or by serialising and deserialising. We only want to do
204
+ // the latter when there are compatibility issues between crates.
205
+
206
+ // This version passes via JSON, it is more easily backwards compatible.
207
+ // save::process_crate(state.tcx.unwrap(),
208
+ // state.expanded_crate.unwrap(),
209
+ // state.analysis.unwrap(),
210
+ // state.crate_name.unwrap(),
211
+ // state.input,
212
+ // None,
213
+ // save::DumpHandler::new(state.out_dir,
214
+ // state.crate_name.unwrap()));
215
+ // This version passes directly, it is more efficient.
216
+ save:: process_crate (
217
+ tcx,
218
+ & expanded_crate,
219
+ & crate_name,
220
+ & input,
221
+ None ,
222
+ CallbackHandler {
223
+ callback : & mut |a| {
224
+ let mut analysis = self . analysis . lock ( ) . unwrap ( ) ;
225
+ let a = unsafe { :: std:: mem:: transmute ( a. clone ( ) ) } ;
226
+ * analysis = Some ( a) ;
227
+ } ,
228
+ } ,
229
+ ) ;
230
+ } ) ;
231
+
232
+ true
156
233
}
157
234
}
158
235
159
236
#[ cfg( feature = "clippy" ) ]
160
- fn clippy_after_parse_callback ( state : & mut rustc_driver :: driver :: CompileState < ' _ , ' _ > ) {
237
+ fn clippy_after_parse_callback ( compiler : & interface :: Compiler ) {
161
238
use self :: rustc_plugin:: registry:: Registry ;
162
239
240
+ let sess = compiler. session ( ) ;
163
241
let mut registry = Registry :: new (
164
- state. session ,
165
- state
166
- . krate
167
- . as_ref ( )
242
+ sess,
243
+ compiler
244
+ . parse ( )
168
245
. expect (
169
246
"at this compilation stage \
170
247
the crate must be parsed",
171
248
)
249
+ . peek ( )
172
250
. span ,
173
251
) ;
174
252
registry. args_hidden = Some ( Vec :: new ( ) ) ;
@@ -179,7 +257,6 @@ fn clippy_after_parse_callback(state: &mut rustc_driver::driver::CompileState<'_
179
257
let Registry {
180
258
early_lint_passes, late_lint_passes, lint_groups, llvm_passes, attributes, ..
181
259
} = registry;
182
- let sess = & state. session ;
183
260
let mut ls = sess. lint_store . borrow_mut ( ) ;
184
261
for pass in early_lint_passes {
185
262
ls. register_early_pass ( Some ( sess) , true , false , pass) ;
@@ -198,93 +275,6 @@ fn clippy_after_parse_callback(state: &mut rustc_driver::driver::CompileState<'_
198
275
sess. plugin_attributes . borrow_mut ( ) . extend ( attributes) ;
199
276
}
200
277
201
- impl < ' a > CompilerCalls < ' a > for RlsRustcCalls {
202
- #[ allow( clippy:: boxed_local) ] // https://github.com/rust-lang/rust-clippy/issues/1123
203
- fn build_controller (
204
- self : Box < Self > ,
205
- sess : & Session ,
206
- matches : & getopts:: Matches ,
207
- ) -> CompileController < ' a > {
208
- let analysis = self . analysis . clone ( ) ;
209
- let input_files = self . input_files . clone ( ) ;
210
- #[ cfg( feature = "clippy" ) ]
211
- let clippy_preference = self . clippy_preference ;
212
- let mut result = Box :: new ( RustcDefaultCalls ) . build_controller ( sess, matches) ;
213
- result. keep_ast = true ;
214
-
215
- #[ cfg( feature = "clippy" ) ]
216
- {
217
- if clippy_preference != ClippyPreference :: Off {
218
- result. after_parse . callback = Box :: new ( clippy_after_parse_callback) ;
219
- }
220
- }
221
-
222
- result. after_expand . callback = Box :: new ( move |state| {
223
- let cwd = & state. session . working_dir . 0 ;
224
-
225
- let src_path = match state. input {
226
- Input :: File ( ref name) => Some ( name. to_path_buf ( ) ) ,
227
- Input :: Str { .. } => None ,
228
- }
229
- . and_then ( |path| src_path ( Some ( cwd) , path) ) ;
230
-
231
- let krate = Crate {
232
- name : state. crate_name . expect ( "missing crate name" ) . to_owned ( ) ,
233
- src_path,
234
- disambiguator : state
235
- . session
236
- . local_crate_disambiguator ( )
237
- . to_fingerprint ( )
238
- . as_value ( ) ,
239
- edition : match state. session . edition ( ) {
240
- RustcEdition :: Edition2015 => Edition :: Edition2015 ,
241
- RustcEdition :: Edition2018 => Edition :: Edition2018 ,
242
- } ,
243
- } ;
244
- let files = fetch_input_files ( state. session ) ;
245
-
246
- let mut input_files = input_files. lock ( ) . unwrap ( ) ;
247
- for file in & files {
248
- input_files. entry ( file. to_path_buf ( ) ) . or_default ( ) . insert ( krate. clone ( ) ) ;
249
- }
250
- } ) ;
251
-
252
- result. after_analysis . callback = Box :: new ( move |state| {
253
- // There are two ways to move the data from rustc to the RLS, either
254
- // directly or by serialising and deserialising. We only want to do
255
- // the latter when there are compatibility issues between crates.
256
-
257
- // This version passes via JSON, it is more easily backwards compatible.
258
- // save::process_crate(state.tcx.unwrap(),
259
- // state.expanded_crate.unwrap(),
260
- // state.analysis.unwrap(),
261
- // state.crate_name.unwrap(),
262
- // state.input,
263
- // None,
264
- // save::DumpHandler::new(state.out_dir,
265
- // state.crate_name.unwrap()));
266
- // This version passes directly, it is more efficient.
267
- save:: process_crate (
268
- state. tcx . expect ( "missing tcx" ) ,
269
- state. expanded_crate . expect ( "missing crate" ) ,
270
- state. crate_name . expect ( "missing crate name" ) ,
271
- state. input ,
272
- None ,
273
- CallbackHandler {
274
- callback : & mut |a| {
275
- let mut analysis = analysis. lock ( ) . unwrap ( ) ;
276
- let a = unsafe { :: std:: mem:: transmute ( a. clone ( ) ) } ;
277
- * analysis = Some ( a) ;
278
- } ,
279
- } ,
280
- ) ;
281
- } ) ;
282
- result. after_analysis . run_callback_on_error = true ;
283
-
284
- result
285
- }
286
- }
287
-
288
278
fn fetch_input_files ( sess : & Session ) -> Vec < PathBuf > {
289
279
let cwd = & sess. working_dir . 0 ;
290
280
0 commit comments