diff options
author | Igor Aleksanov <[email protected]> | 2020-10-03 15:34:52 +0100 |
---|---|---|
committer | Igor Aleksanov <[email protected]> | 2020-10-12 09:04:59 +0100 |
commit | e24e22f288eba33928a9e579f13653d6f04fcdfa (patch) | |
tree | 4fd9d128cf510dd7478f6a1fd955461cca70d2f4 /crates/ide | |
parent | 17f1026c46e6e3797caf3c69737f66bd612c58e1 (diff) |
Add fix for incorrect case diagnostic
Diffstat (limited to 'crates/ide')
-rw-r--r-- | crates/ide/src/diagnostics.rs | 64 | ||||
-rw-r--r-- | crates/ide/src/diagnostics/fixes.rs | 20 | ||||
-rw-r--r-- | crates/ide/src/references.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/references/rename.rs | 7 |
4 files changed, 90 insertions, 3 deletions
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index f5d627b6e..71ab98c1f 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -96,6 +96,9 @@ pub(crate) fn diagnostics( | |||
96 | .on::<hir::diagnostics::NoSuchField, _>(|d| { | 96 | .on::<hir::diagnostics::NoSuchField, _>(|d| { |
97 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); | 97 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); |
98 | }) | 98 | }) |
99 | .on::<hir::diagnostics::IncorrectCase, _>(|d| { | ||
100 | res.borrow_mut().push(warning_with_fix(d, &sema)); | ||
101 | }) | ||
99 | // Only collect experimental diagnostics when they're enabled. | 102 | // Only collect experimental diagnostics when they're enabled. |
100 | .filter(|diag| !(diag.is_experimental() && config.disable_experimental)) | 103 | .filter(|diag| !(diag.is_experimental() && config.disable_experimental)) |
101 | .filter(|diag| !config.disabled.contains(diag.code().as_str())); | 104 | .filter(|diag| !config.disabled.contains(diag.code().as_str())); |
@@ -130,6 +133,16 @@ fn diagnostic_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabas | |||
130 | } | 133 | } |
131 | } | 134 | } |
132 | 135 | ||
136 | fn warning_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic { | ||
137 | Diagnostic { | ||
138 | // name: Some(d.name().into()), | ||
139 | range: sema.diagnostics_display_range(d).range, | ||
140 | message: d.message(), | ||
141 | severity: Severity::WeakWarning, | ||
142 | fix: d.fix(&sema), | ||
143 | } | ||
144 | } | ||
145 | |||
133 | fn check_unnecessary_braces_in_use_statement( | 146 | fn check_unnecessary_braces_in_use_statement( |
134 | acc: &mut Vec<Diagnostic>, | 147 | acc: &mut Vec<Diagnostic>, |
135 | file_id: FileId, | 148 | file_id: FileId, |
@@ -253,6 +266,37 @@ mod tests { | |||
253 | ); | 266 | ); |
254 | } | 267 | } |
255 | 268 | ||
269 | /// Similar to `check_fix`, but applies all the available fixes. | ||
270 | fn check_fixes(ra_fixture_before: &str, ra_fixture_after: &str) { | ||
271 | let after = trim_indent(ra_fixture_after); | ||
272 | |||
273 | let (analysis, file_position) = fixture::position(ra_fixture_before); | ||
274 | let diagnostic = analysis | ||
275 | .diagnostics(&DiagnosticsConfig::default(), file_position.file_id) | ||
276 | .unwrap() | ||
277 | .pop() | ||
278 | .unwrap(); | ||
279 | let fix = diagnostic.fix.unwrap(); | ||
280 | let target_file_contents = analysis.file_text(file_position.file_id).unwrap(); | ||
281 | let actual = { | ||
282 | let mut actual = target_file_contents.to_string(); | ||
283 | // Go from the last one to the first one, so that ranges won't be affected by previous edits. | ||
284 | for edit in fix.source_change.source_file_edits.iter().rev() { | ||
285 | edit.edit.apply(&mut actual); | ||
286 | } | ||
287 | actual | ||
288 | }; | ||
289 | |||
290 | assert_eq_text!(&after, &actual); | ||
291 | assert!( | ||
292 | fix.fix_trigger_range.start() <= file_position.offset | ||
293 | && fix.fix_trigger_range.end() >= file_position.offset, | ||
294 | "diagnostic fix range {:?} does not touch cursor position {:?}", | ||
295 | fix.fix_trigger_range, | ||
296 | file_position.offset | ||
297 | ); | ||
298 | } | ||
299 | |||
256 | /// Checks that a diagnostic applies to the file containing the `<|>` cursor marker | 300 | /// Checks that a diagnostic applies to the file containing the `<|>` cursor marker |
257 | /// which has a fix that can apply to other files. | 301 | /// which has a fix that can apply to other files. |
258 | fn check_apply_diagnostic_fix_in_other_file(ra_fixture_before: &str, ra_fixture_after: &str) { | 302 | fn check_apply_diagnostic_fix_in_other_file(ra_fixture_before: &str, ra_fixture_after: &str) { |
@@ -790,4 +834,24 @@ struct Foo { | |||
790 | let diagnostics = analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap(); | 834 | let diagnostics = analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap(); |
791 | assert!(!diagnostics.is_empty()); | 835 | assert!(!diagnostics.is_empty()); |
792 | } | 836 | } |
837 | |||
838 | #[test] | ||
839 | fn test_rename_incorrect_case() { | ||
840 | check_fixes( | ||
841 | r#" | ||
842 | pub struct test_struct<|> { one: i32 } | ||
843 | |||
844 | pub fn some_fn(val: test_struct) -> test_struct { | ||
845 | test_struct { one: val.one + 1 } | ||
846 | } | ||
847 | "#, | ||
848 | r#" | ||
849 | pub struct TestStruct { one: i32 } | ||
850 | |||
851 | pub fn some_fn(val: TestStruct) -> TestStruct { | ||
852 | TestStruct { one: val.one + 1 } | ||
853 | } | ||
854 | "#, | ||
855 | ); | ||
856 | } | ||
793 | } | 857 | } |
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs index 68ae1c239..286ef0785 100644 --- a/crates/ide/src/diagnostics/fixes.rs +++ b/crates/ide/src/diagnostics/fixes.rs | |||
@@ -3,7 +3,10 @@ | |||
3 | use base_db::FileId; | 3 | use base_db::FileId; |
4 | use hir::{ | 4 | use hir::{ |
5 | db::AstDatabase, | 5 | db::AstDatabase, |
6 | diagnostics::{Diagnostic, MissingFields, MissingOkInTailExpr, NoSuchField, UnresolvedModule}, | 6 | diagnostics::{ |
7 | Diagnostic, IncorrectCase, MissingFields, MissingOkInTailExpr, NoSuchField, | ||
8 | UnresolvedModule, | ||
9 | }, | ||
7 | HasSource, HirDisplay, Semantics, VariantDef, | 10 | HasSource, HirDisplay, Semantics, VariantDef, |
8 | }; | 11 | }; |
9 | use ide_db::{ | 12 | use ide_db::{ |
@@ -17,7 +20,7 @@ use syntax::{ | |||
17 | }; | 20 | }; |
18 | use text_edit::TextEdit; | 21 | use text_edit::TextEdit; |
19 | 22 | ||
20 | use crate::diagnostics::Fix; | 23 | use crate::{diagnostics::Fix, references::rename::rename_with_semantics, FilePosition}; |
21 | 24 | ||
22 | /// A [Diagnostic] that potentially has a fix available. | 25 | /// A [Diagnostic] that potentially has a fix available. |
23 | /// | 26 | /// |
@@ -99,6 +102,19 @@ impl DiagnosticWithFix for MissingOkInTailExpr { | |||
99 | } | 102 | } |
100 | } | 103 | } |
101 | 104 | ||
105 | impl DiagnosticWithFix for IncorrectCase { | ||
106 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { | ||
107 | let file_id = self.file.original_file(sema.db); | ||
108 | let offset = self.ident.text_range().start(); | ||
109 | let file_position = FilePosition { file_id, offset }; | ||
110 | |||
111 | let rename_changes = rename_with_semantics(sema, file_position, &self.suggested_text)?; | ||
112 | |||
113 | let label = format!("Rename to {}", self.suggested_text); | ||
114 | Some(Fix::new(&label, rename_changes.info, rename_changes.range)) | ||
115 | } | ||
116 | } | ||
117 | |||
102 | fn missing_record_expr_field_fix( | 118 | fn missing_record_expr_field_fix( |
103 | sema: &Semantics<RootDatabase>, | 119 | sema: &Semantics<RootDatabase>, |
104 | usage_file_id: FileId, | 120 | usage_file_id: FileId, |
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index f65a05ea3..88e2f2db3 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs | |||
@@ -9,7 +9,7 @@ | |||
9 | //! at the index that the match starts at and its tree parent is | 9 | //! at the index that the match starts at and its tree parent is |
10 | //! resolved to the search element definition, we get a reference. | 10 | //! resolved to the search element definition, we get a reference. |
11 | 11 | ||
12 | mod rename; | 12 | pub(crate) mod rename; |
13 | 13 | ||
14 | use hir::Semantics; | 14 | use hir::Semantics; |
15 | use ide_db::{ | 15 | use ide_db::{ |
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs index f3b5cfc8c..f9a11e43d 100644 --- a/crates/ide/src/references/rename.rs +++ b/crates/ide/src/references/rename.rs | |||
@@ -42,7 +42,14 @@ pub(crate) fn rename( | |||
42 | new_name: &str, | 42 | new_name: &str, |
43 | ) -> Result<RangeInfo<SourceChange>, RenameError> { | 43 | ) -> Result<RangeInfo<SourceChange>, RenameError> { |
44 | let sema = Semantics::new(db); | 44 | let sema = Semantics::new(db); |
45 | rename_with_semantics(&sema, position, new_name) | ||
46 | } | ||
45 | 47 | ||
48 | pub(crate) fn rename_with_semantics( | ||
49 | sema: &Semantics<RootDatabase>, | ||
50 | position: FilePosition, | ||
51 | new_name: &str, | ||
52 | ) -> Result<RangeInfo<SourceChange>, RenameError> { | ||
46 | match lex_single_syntax_kind(new_name) { | 53 | match lex_single_syntax_kind(new_name) { |
47 | Some(res) => match res { | 54 | Some(res) => match res { |
48 | (SyntaxKind::IDENT, _) => (), | 55 | (SyntaxKind::IDENT, _) => (), |