77use std:: cell:: RefCell ;
88
99use hir:: {
10- diagnostics:: { AstDiagnostic , Diagnostic as _, DiagnosticSink } ,
10+ diagnostics:: { AstDiagnostic , Diagnostic as _, DiagnosticSinkBuilder } ,
1111 HasSource , HirDisplay , Semantics , VariantDef ,
1212} ;
1313use itertools:: Itertools ;
@@ -29,7 +29,11 @@ pub enum Severity {
2929 WeakWarning ,
3030}
3131
32- pub ( crate ) fn diagnostics ( db : & RootDatabase , file_id : FileId ) -> Vec < Diagnostic > {
32+ pub ( crate ) fn diagnostics (
33+ db : & RootDatabase ,
34+ file_id : FileId ,
35+ enable_experimental : bool ,
36+ ) -> Vec < Diagnostic > {
3337 let _p = profile ( "diagnostics" ) ;
3438 let sema = Semantics :: new ( db) ;
3539 let parse = db. parse ( file_id) ;
@@ -48,79 +52,85 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
4852 check_struct_shorthand_initialization ( & mut res, file_id, & node) ;
4953 }
5054 let res = RefCell :: new ( res) ;
51- let mut sink = DiagnosticSink :: new ( |d| {
52- res. borrow_mut ( ) . push ( Diagnostic {
53- message : d. message ( ) ,
54- range : sema. diagnostics_range ( d) . range ,
55- severity : Severity :: Error ,
56- fix : None ,
57- } )
58- } )
59- . on :: < hir:: diagnostics:: UnresolvedModule , _ > ( |d| {
60- let original_file = d. source ( ) . file_id . original_file ( db) ;
61- let fix = Fix :: new (
62- "Create module" ,
63- FileSystemEdit :: CreateFile { anchor : original_file, dst : d. candidate . clone ( ) } . into ( ) ,
64- ) ;
65- res. borrow_mut ( ) . push ( Diagnostic {
66- range : sema. diagnostics_range ( d) . range ,
67- message : d. message ( ) ,
68- severity : Severity :: Error ,
69- fix : Some ( fix) ,
55+ let mut sink = DiagnosticSinkBuilder :: new ( )
56+ . on :: < hir:: diagnostics:: UnresolvedModule , _ > ( |d| {
57+ let original_file = d. source ( ) . file_id . original_file ( db) ;
58+ let fix = Fix :: new (
59+ "Create module" ,
60+ FileSystemEdit :: CreateFile { anchor : original_file, dst : d. candidate . clone ( ) }
61+ . into ( ) ,
62+ ) ;
63+ res. borrow_mut ( ) . push ( Diagnostic {
64+ range : sema. diagnostics_range ( d) . range ,
65+ message : d. message ( ) ,
66+ severity : Severity :: Error ,
67+ fix : Some ( fix) ,
68+ } )
7069 } )
71- } )
72- . on :: < hir:: diagnostics:: MissingFields , _ > ( |d| {
73- // Note that although we could add a diagnostics to
74- // fill the missing tuple field, e.g :
75- // `struct A(usize);`
76- // `let a = A { 0: () }`
77- // but it is uncommon usage and it should not be encouraged.
78- let fix = if d. missed_fields . iter ( ) . any ( |it| it. as_tuple_index ( ) . is_some ( ) ) {
79- None
80- } else {
81- let mut field_list = d. ast ( db) ;
82- for f in d. missed_fields . iter ( ) {
83- let field =
84- make:: record_field ( make:: name_ref ( & f. to_string ( ) ) , Some ( make:: expr_unit ( ) ) ) ;
85- field_list = field_list. append_field ( & field) ;
86- }
87-
88- let edit = {
89- let mut builder = TextEditBuilder :: default ( ) ;
90- algo:: diff ( & d. ast ( db) . syntax ( ) , & field_list. syntax ( ) ) . into_text_edit ( & mut builder) ;
91- builder. finish ( )
70+ . on :: < hir:: diagnostics:: MissingFields , _ > ( |d| {
71+ // Note that although we could add a diagnostics to
72+ // fill the missing tuple field, e.g :
73+ // `struct A(usize);`
74+ // `let a = A { 0: () }`
75+ // but it is uncommon usage and it should not be encouraged.
76+ let fix = if d. missed_fields . iter ( ) . any ( |it| it. as_tuple_index ( ) . is_some ( ) ) {
77+ None
78+ } else {
79+ let mut field_list = d. ast ( db) ;
80+ for f in d. missed_fields . iter ( ) {
81+ let field =
82+ make:: record_field ( make:: name_ref ( & f. to_string ( ) ) , Some ( make:: expr_unit ( ) ) ) ;
83+ field_list = field_list. append_field ( & field) ;
84+ }
85+
86+ let edit = {
87+ let mut builder = TextEditBuilder :: default ( ) ;
88+ algo:: diff ( & d. ast ( db) . syntax ( ) , & field_list. syntax ( ) )
89+ . into_text_edit ( & mut builder) ;
90+ builder. finish ( )
91+ } ;
92+ Some ( Fix :: new ( "Fill struct fields" , SourceFileEdit { file_id, edit } . into ( ) ) )
9293 } ;
93- Some ( Fix :: new ( "Fill struct fields" , SourceFileEdit { file_id, edit } . into ( ) ) )
94- } ;
9594
96- res. borrow_mut ( ) . push ( Diagnostic {
97- range : sema. diagnostics_range ( d) . range ,
98- message : d. message ( ) ,
99- severity : Severity :: Error ,
100- fix,
95+ res. borrow_mut ( ) . push ( Diagnostic {
96+ range : sema. diagnostics_range ( d) . range ,
97+ message : d. message ( ) ,
98+ severity : Severity :: Error ,
99+ fix,
100+ } )
101101 } )
102- } )
103- . on :: < hir :: diagnostics :: MissingOkInTailExpr , _ > ( |d| {
104- let node = d . ast ( db ) ;
105- let replacement = format ! ( "Ok({})" , node. syntax( ) ) ;
106- let edit = TextEdit :: replace ( node . syntax ( ) . text_range ( ) , replacement ) ;
107- let source_change = SourceFileEdit { file_id , edit } . into ( ) ;
108- let fix = Fix :: new ( "Wrap with ok" , source_change ) ;
109- res . borrow_mut ( ) . push ( Diagnostic {
110- range : sema . diagnostics_range ( d ) . range ,
111- message : d . message ( ) ,
112- severity : Severity :: Error ,
113- fix : Some ( fix ) ,
102+ . on :: < hir :: diagnostics :: MissingOkInTailExpr , _ > ( |d| {
103+ let node = d . ast ( db ) ;
104+ let replacement = format ! ( "Ok({})" , node . syntax ( ) ) ;
105+ let edit = TextEdit :: replace ( node. syntax ( ) . text_range ( ) , replacement ) ;
106+ let source_change = SourceFileEdit { file_id , edit } . into ( ) ;
107+ let fix = Fix :: new ( "Wrap with ok" , source_change ) ;
108+ res . borrow_mut ( ) . push ( Diagnostic {
109+ range : sema . diagnostics_range ( d ) . range ,
110+ message : d . message ( ) ,
111+ severity : Severity :: Error ,
112+ fix : Some ( fix ) ,
113+ } )
114114 } )
115- } )
116- . on :: < hir :: diagnostics :: NoSuchField , _ > ( |d| {
117- res . borrow_mut ( ) . push ( Diagnostic {
118- range : sema . diagnostics_range ( d ) . range ,
119- message : d . message ( ) ,
120- severity : Severity :: Error ,
121- fix : missing_struct_field_fix ( & sema , file_id , d ) ,
115+ . on :: < hir :: diagnostics :: NoSuchField , _ > ( |d| {
116+ res . borrow_mut ( ) . push ( Diagnostic {
117+ range : sema . diagnostics_range ( d ) . range ,
118+ message : d . message ( ) ,
119+ severity : Severity :: Error ,
120+ fix : missing_struct_field_fix ( & sema , file_id , d ) ,
121+ } )
122122 } )
123- } ) ;
123+ // Only collect experimental diagnostics when they're enabled.
124+ . filter ( |diag| !diag. is_experimental ( ) || enable_experimental)
125+ // Diagnostics not handled above get no fix and default treatment.
126+ . build ( |d| {
127+ res. borrow_mut ( ) . push ( Diagnostic {
128+ message : d. message ( ) ,
129+ range : sema. diagnostics_range ( d) . range ,
130+ severity : Severity :: Error ,
131+ fix : None ,
132+ } )
133+ } ) ;
124134
125135 if let Some ( m) = sema. to_module_def ( file_id) {
126136 m. diagnostics ( db, & mut sink) ;
@@ -298,7 +308,7 @@ mod tests {
298308 let after = trim_indent ( ra_fixture_after) ;
299309
300310 let ( analysis, file_position) = analysis_and_position ( ra_fixture_before) ;
301- let diagnostic = analysis. diagnostics ( file_position. file_id ) . unwrap ( ) . pop ( ) . unwrap ( ) ;
311+ let diagnostic = analysis. diagnostics ( file_position. file_id , true ) . unwrap ( ) . pop ( ) . unwrap ( ) ;
302312 let mut fix = diagnostic. fix . unwrap ( ) ;
303313 let edit = fix. source_change . source_file_edits . pop ( ) . unwrap ( ) . edit ;
304314 let target_file_contents = analysis. file_text ( file_position. file_id ) . unwrap ( ) ;
@@ -324,7 +334,7 @@ mod tests {
324334 let ra_fixture_after = & trim_indent ( ra_fixture_after) ;
325335 let ( analysis, file_pos) = analysis_and_position ( ra_fixture_before) ;
326336 let current_file_id = file_pos. file_id ;
327- let diagnostic = analysis. diagnostics ( current_file_id) . unwrap ( ) . pop ( ) . unwrap ( ) ;
337+ let diagnostic = analysis. diagnostics ( current_file_id, true ) . unwrap ( ) . pop ( ) . unwrap ( ) ;
328338 let mut fix = diagnostic. fix . unwrap ( ) ;
329339 let edit = fix. source_change . source_file_edits . pop ( ) . unwrap ( ) ;
330340 let changed_file_id = edit. file_id ;
@@ -345,14 +355,14 @@ mod tests {
345355 let analysis = mock. analysis ( ) ;
346356 let diagnostics = files
347357 . into_iter ( )
348- . flat_map ( |file_id| analysis. diagnostics ( file_id) . unwrap ( ) )
358+ . flat_map ( |file_id| analysis. diagnostics ( file_id, true ) . unwrap ( ) )
349359 . collect :: < Vec < _ > > ( ) ;
350360 assert_eq ! ( diagnostics. len( ) , 0 , "unexpected diagnostics:\n {:#?}" , diagnostics) ;
351361 }
352362
353363 fn check_expect ( ra_fixture : & str , expect : Expect ) {
354364 let ( analysis, file_id) = single_file ( ra_fixture) ;
355- let diagnostics = analysis. diagnostics ( file_id) . unwrap ( ) ;
365+ let diagnostics = analysis. diagnostics ( file_id, true ) . unwrap ( ) ;
356366 expect. assert_debug_eq ( & diagnostics)
357367 }
358368
0 commit comments