diff --git a/crates/hir-ty/src/diagnostics/decl_check.rs b/crates/hir-ty/src/diagnostics/decl_check.rs index 0249f3ba25..82517e6991 100644 --- a/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/crates/hir-ty/src/diagnostics/decl_check.rs @@ -24,6 +24,7 @@ use hir_expand::{ name::{AsName, Name}, HirFileId, HirFileIdExt, }; +use intern::sym; use stdx::{always, never}; use syntax::{ ast::{self, HasName}, @@ -197,12 +198,20 @@ impl<'a> DeclValidator<'a> { // Skipped if function is an associated item of a trait implementation. if !self.is_trait_impl_container(container) { let data = self.db.function_data(func); - self.create_incorrect_case_diagnostic_for_item_name( - func, - &data.name, - CaseType::LowerSnakeCase, - IdentType::Function, - ); + + // Don't run the lint on extern "[not Rust]" fn items with the + // #[no_mangle] attribute. + let no_mangle = data.attrs.by_key(&sym::no_mangle).exists(); + if no_mangle && data.abi.as_ref().is_some_and(|abi| *abi != sym::Rust) { + cov_mark::hit!(extern_func_no_mangle_ignored); + } else { + self.create_incorrect_case_diagnostic_for_item_name( + func, + &data.name, + CaseType::LowerSnakeCase, + IdentType::Function, + ); + } } else { cov_mark::hit!(trait_impl_assoc_func_name_incorrect_case_ignored); } diff --git a/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/crates/ide-diagnostics/src/handlers/incorrect_case.rs index ddc19a0121..ec25c3d52b 100644 --- a/crates/ide-diagnostics/src/handlers/incorrect_case.rs +++ b/crates/ide-diagnostics/src/handlers/incorrect_case.rs @@ -418,6 +418,64 @@ fn f((_O): u8) {} ) } + #[test] + fn ignores_no_mangle_items() { + cov_mark::check!(extern_func_no_mangle_ignored); + check_diagnostics( + r#" +#[no_mangle] +extern "C" fn NonSnakeCaseName(some_var: u8) -> u8; + "#, + ); + } + + #[test] + fn ignores_no_mangle_items_with_no_abi() { + cov_mark::check!(extern_func_no_mangle_ignored); + check_diagnostics( + r#" +#[no_mangle] +extern fn NonSnakeCaseName(some_var: u8) -> u8; + "#, + ); + } + + #[test] + fn no_mangle_items_with_rust_abi() { + check_diagnostics( + r#" +#[no_mangle] +extern "Rust" fn NonSnakeCaseName(some_var: u8) -> u8; + // ^^^^^^^^^^^^^^^^ 💡 warn: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` + "#, + ); + } + + #[test] + fn no_mangle_items_non_extern() { + check_diagnostics( + r#" +#[no_mangle] +fn NonSnakeCaseName(some_var: u8) -> u8; +// ^^^^^^^^^^^^^^^^ 💡 warn: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` + "#, + ); + } + + #[test] + fn extern_fn_name() { + check_diagnostics( + r#" +extern "C" fn NonSnakeCaseName(some_var: u8) -> u8; + // ^^^^^^^^^^^^^^^^ 💡 warn: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` +extern "Rust" fn NonSnakeCaseName(some_var: u8) -> u8; + // ^^^^^^^^^^^^^^^^ 💡 warn: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` +extern fn NonSnakeCaseName(some_var: u8) -> u8; + // ^^^^^^^^^^^^^^^^ 💡 warn: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` + "#, + ); + } + #[test] fn ignores_extern_items() { cov_mark::check!(extern_func_incorrect_case_ignored);