From e24e22f288eba33928a9e579f13653d6f04fcdfa Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Sat, 3 Oct 2020 17:34:52 +0300 Subject: Add fix for incorrect case diagnostic --- crates/ide/src/diagnostics.rs | 64 +++++++++++++++++++++++++++++++++++++ crates/ide/src/diagnostics/fixes.rs | 20 ++++++++++-- crates/ide/src/references.rs | 2 +- crates/ide/src/references/rename.rs | 7 ++++ 4 files changed, 90 insertions(+), 3 deletions(-) (limited to 'crates/ide/src') 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( .on::(|d| { res.borrow_mut().push(diagnostic_with_fix(d, &sema)); }) + .on::(|d| { + res.borrow_mut().push(warning_with_fix(d, &sema)); + }) // Only collect experimental diagnostics when they're enabled. .filter(|diag| !(diag.is_experimental() && config.disable_experimental)) .filter(|diag| !config.disabled.contains(diag.code().as_str())); @@ -130,6 +133,16 @@ fn diagnostic_with_fix(d: &D, sema: &Semantics(d: &D, sema: &Semantics) -> Diagnostic { + Diagnostic { + // name: Some(d.name().into()), + range: sema.diagnostics_display_range(d).range, + message: d.message(), + severity: Severity::WeakWarning, + fix: d.fix(&sema), + } +} + fn check_unnecessary_braces_in_use_statement( acc: &mut Vec, file_id: FileId, @@ -253,6 +266,37 @@ mod tests { ); } + /// Similar to `check_fix`, but applies all the available fixes. + fn check_fixes(ra_fixture_before: &str, ra_fixture_after: &str) { + let after = trim_indent(ra_fixture_after); + + let (analysis, file_position) = fixture::position(ra_fixture_before); + let diagnostic = analysis + .diagnostics(&DiagnosticsConfig::default(), file_position.file_id) + .unwrap() + .pop() + .unwrap(); + let fix = diagnostic.fix.unwrap(); + let target_file_contents = analysis.file_text(file_position.file_id).unwrap(); + let actual = { + let mut actual = target_file_contents.to_string(); + // Go from the last one to the first one, so that ranges won't be affected by previous edits. + for edit in fix.source_change.source_file_edits.iter().rev() { + edit.edit.apply(&mut actual); + } + actual + }; + + assert_eq_text!(&after, &actual); + assert!( + fix.fix_trigger_range.start() <= file_position.offset + && fix.fix_trigger_range.end() >= file_position.offset, + "diagnostic fix range {:?} does not touch cursor position {:?}", + fix.fix_trigger_range, + file_position.offset + ); + } + /// Checks that a diagnostic applies to the file containing the `<|>` cursor marker /// which has a fix that can apply to other files. fn check_apply_diagnostic_fix_in_other_file(ra_fixture_before: &str, ra_fixture_after: &str) { @@ -790,4 +834,24 @@ struct Foo { let diagnostics = analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap(); assert!(!diagnostics.is_empty()); } + + #[test] + fn test_rename_incorrect_case() { + check_fixes( + r#" +pub struct test_struct<|> { one: i32 } + +pub fn some_fn(val: test_struct) -> test_struct { + test_struct { one: val.one + 1 } +} +"#, + r#" +pub struct TestStruct { one: i32 } + +pub fn some_fn(val: TestStruct) -> TestStruct { + TestStruct { one: val.one + 1 } +} +"#, + ); + } } 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 @@ use base_db::FileId; use hir::{ db::AstDatabase, - diagnostics::{Diagnostic, MissingFields, MissingOkInTailExpr, NoSuchField, UnresolvedModule}, + diagnostics::{ + Diagnostic, IncorrectCase, MissingFields, MissingOkInTailExpr, NoSuchField, + UnresolvedModule, + }, HasSource, HirDisplay, Semantics, VariantDef, }; use ide_db::{ @@ -17,7 +20,7 @@ use syntax::{ }; use text_edit::TextEdit; -use crate::diagnostics::Fix; +use crate::{diagnostics::Fix, references::rename::rename_with_semantics, FilePosition}; /// A [Diagnostic] that potentially has a fix available. /// @@ -99,6 +102,19 @@ impl DiagnosticWithFix for MissingOkInTailExpr { } } +impl DiagnosticWithFix for IncorrectCase { + fn fix(&self, sema: &Semantics) -> Option { + let file_id = self.file.original_file(sema.db); + let offset = self.ident.text_range().start(); + let file_position = FilePosition { file_id, offset }; + + let rename_changes = rename_with_semantics(sema, file_position, &self.suggested_text)?; + + let label = format!("Rename to {}", self.suggested_text); + Some(Fix::new(&label, rename_changes.info, rename_changes.range)) + } +} + fn missing_record_expr_field_fix( sema: &Semantics, 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 @@ //! at the index that the match starts at and its tree parent is //! resolved to the search element definition, we get a reference. -mod rename; +pub(crate) mod rename; use hir::Semantics; 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( new_name: &str, ) -> Result, RenameError> { let sema = Semantics::new(db); + rename_with_semantics(&sema, position, new_name) +} +pub(crate) fn rename_with_semantics( + sema: &Semantics, + position: FilePosition, + new_name: &str, +) -> Result, RenameError> { match lex_single_syntax_kind(new_name) { Some(res) => match res { (SyntaxKind::IDENT, _) => (), -- cgit v1.2.3