2021-06-13 21:09:03 +03:00
|
|
|
use hir::{db::AstDatabase, InFile};
|
|
|
|
use ide_assists::Assist;
|
|
|
|
use ide_db::base_db::FilePosition;
|
2021-05-17 12:04:17 +03:00
|
|
|
use syntax::AstNode;
|
|
|
|
|
|
|
|
use crate::{
|
2021-06-13 21:09:03 +03:00
|
|
|
diagnostics::{unresolved_fix, Diagnostic, DiagnosticsContext},
|
2021-05-17 12:04:17 +03:00
|
|
|
references::rename::rename_with_semantics,
|
2021-06-13 21:09:03 +03:00
|
|
|
Severity,
|
2021-05-17 12:04:17 +03:00
|
|
|
};
|
|
|
|
|
2021-06-13 21:09:03 +03:00
|
|
|
// Diagnostic: incorrect-ident-case
|
|
|
|
//
|
|
|
|
// This diagnostic is triggered if an item name doesn't follow https://doc.rust-lang.org/1.0.0/style/style/naming/README.html[Rust naming convention].
|
|
|
|
pub(super) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Diagnostic {
|
|
|
|
Diagnostic::new(
|
|
|
|
"incorrect-ident-case",
|
|
|
|
format!(
|
|
|
|
"{} `{}` should have {} name, e.g. `{}`",
|
|
|
|
d.ident_type, d.ident_text, d.expected_case, d.suggested_text
|
|
|
|
),
|
|
|
|
ctx.sema.diagnostics_display_range(InFile::new(d.file, d.ident.clone().into())).range,
|
|
|
|
)
|
|
|
|
.severity(Severity::WeakWarning)
|
|
|
|
.with_fixes(fixes(ctx, d))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option<Vec<Assist>> {
|
|
|
|
let root = ctx.sema.db.parse_or_expand(d.file)?;
|
|
|
|
let name_node = d.ident.to_node(&root);
|
|
|
|
|
|
|
|
let name_node = InFile::new(d.file, name_node.syntax());
|
|
|
|
let frange = name_node.original_file_range(ctx.sema.db);
|
|
|
|
let file_position = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
|
|
|
|
|
|
|
|
let label = format!("Rename to {}", d.suggested_text);
|
|
|
|
let mut res = unresolved_fix("change_case", &label, frange.range);
|
|
|
|
if ctx.resolve.should_resolve(&res.id) {
|
|
|
|
let source_change = rename_with_semantics(&ctx.sema, file_position, &d.suggested_text);
|
|
|
|
res.source_change = Some(source_change.ok().unwrap_or_default());
|
2021-05-17 12:04:17 +03:00
|
|
|
}
|
2021-06-13 21:09:03 +03:00
|
|
|
|
|
|
|
Some(vec![res])
|
2021-05-17 12:04:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod change_case {
|
|
|
|
use crate::{
|
2021-06-13 19:27:14 +03:00
|
|
|
diagnostics::tests::{check_diagnostics, check_fix},
|
2021-05-17 12:04:17 +03:00
|
|
|
fixture, AssistResolveStrategy, DiagnosticsConfig,
|
|
|
|
};
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_rename_incorrect_case() {
|
|
|
|
check_fix(
|
|
|
|
r#"
|
|
|
|
pub struct test_struct$0 { 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 }
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
|
|
|
|
check_fix(
|
|
|
|
r#"
|
|
|
|
pub fn some_fn(NonSnakeCase$0: u8) -> u8 {
|
|
|
|
NonSnakeCase
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
pub fn some_fn(non_snake_case: u8) -> u8 {
|
|
|
|
non_snake_case
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
|
|
|
|
check_fix(
|
|
|
|
r#"
|
|
|
|
pub fn SomeFn$0(val: u8) -> u8 {
|
|
|
|
if val != 0 { SomeFn(val - 1) } else { val }
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
pub fn some_fn(val: u8) -> u8 {
|
|
|
|
if val != 0 { some_fn(val - 1) } else { val }
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
|
|
|
|
check_fix(
|
|
|
|
r#"
|
|
|
|
fn some_fn() {
|
|
|
|
let whatAWeird_Formatting$0 = 10;
|
|
|
|
another_func(whatAWeird_Formatting);
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
fn some_fn() {
|
|
|
|
let what_a_weird_formatting = 10;
|
|
|
|
another_func(what_a_weird_formatting);
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_uppercase_const_no_diagnostics() {
|
2021-06-13 19:27:14 +03:00
|
|
|
check_diagnostics(
|
2021-05-17 12:04:17 +03:00
|
|
|
r#"
|
|
|
|
fn foo() {
|
|
|
|
const ANOTHER_ITEM$0: &str = "some_item";
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_rename_incorrect_case_struct_method() {
|
|
|
|
check_fix(
|
|
|
|
r#"
|
|
|
|
pub struct TestStruct;
|
|
|
|
|
|
|
|
impl TestStruct {
|
|
|
|
pub fn SomeFn$0() -> TestStruct {
|
|
|
|
TestStruct
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
pub struct TestStruct;
|
|
|
|
|
|
|
|
impl TestStruct {
|
|
|
|
pub fn some_fn() -> TestStruct {
|
|
|
|
TestStruct
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_single_incorrect_case_diagnostic_in_function_name_issue_6970() {
|
|
|
|
let input = r#"fn FOO$0() {}"#;
|
|
|
|
let expected = r#"fn foo() {}"#;
|
|
|
|
|
|
|
|
let (analysis, file_position) = fixture::position(input);
|
|
|
|
let diagnostics = analysis
|
|
|
|
.diagnostics(
|
|
|
|
&DiagnosticsConfig::default(),
|
|
|
|
AssistResolveStrategy::All,
|
|
|
|
file_position.file_id,
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
assert_eq!(diagnostics.len(), 1);
|
|
|
|
|
|
|
|
check_fix(input, expected);
|
|
|
|
}
|
|
|
|
}
|