Skip to content

Commit 59d35d2

Browse files
committed
Auto merge of #15320 - lowr:fix/incorrect-name-case-for-inner-items, r=HKalbasi
Report `incorrect-ident-case` for inner items Fixes #15319 Although we have been collecting the diagnostics for inner items within function bodies, we were discarding them and never reported to the users. This PR makes sure that they are all reported and additionally collects the diagnostics for inner items within const bodies, static bodies, and enum variant bodies.
2 parents 994f4f6 + 33b7b45 commit 59d35d2

File tree

3 files changed

+135
-39
lines changed

3 files changed

+135
-39
lines changed

crates/hir-ty/src/diagnostics/decl_check.rs

+37-32
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,12 @@ mod case_conv;
1414

1515
use std::fmt;
1616

17-
use base_db::CrateId;
1817
use hir_def::{
1918
data::adt::VariantData,
2019
hir::{Pat, PatId},
2120
src::HasSource,
22-
AdtId, AttrDefId, ConstId, EnumId, FunctionId, ItemContainerId, Lookup, ModuleDefId, StaticId,
23-
StructId,
21+
AdtId, AttrDefId, ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, ItemContainerId,
22+
Lookup, ModuleDefId, StaticId, StructId,
2423
};
2524
use hir_expand::{
2625
name::{AsName, Name},
@@ -44,13 +43,9 @@ mod allow {
4443
pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types";
4544
}
4645

47-
pub fn incorrect_case(
48-
db: &dyn HirDatabase,
49-
krate: CrateId,
50-
owner: ModuleDefId,
51-
) -> Vec<IncorrectCase> {
46+
pub fn incorrect_case(db: &dyn HirDatabase, owner: ModuleDefId) -> Vec<IncorrectCase> {
5247
let _p = profile::span("validate_module_item");
53-
let mut validator = DeclValidator::new(db, krate);
48+
let mut validator = DeclValidator::new(db);
5449
validator.validate_item(owner);
5550
validator.sink
5651
}
@@ -120,7 +115,6 @@ pub struct IncorrectCase {
120115

121116
pub(super) struct DeclValidator<'a> {
122117
db: &'a dyn HirDatabase,
123-
krate: CrateId,
124118
pub(super) sink: Vec<IncorrectCase>,
125119
}
126120

@@ -132,8 +126,8 @@ struct Replacement {
132126
}
133127

134128
impl<'a> DeclValidator<'a> {
135-
pub(super) fn new(db: &'a dyn HirDatabase, krate: CrateId) -> DeclValidator<'a> {
136-
DeclValidator { db, krate, sink: Vec::new() }
129+
pub(super) fn new(db: &'a dyn HirDatabase) -> DeclValidator<'a> {
130+
DeclValidator { db, sink: Vec::new() }
137131
}
138132

139133
pub(super) fn validate_item(&mut self, item: ModuleDefId) {
@@ -195,8 +189,7 @@ impl<'a> DeclValidator<'a> {
195189
AttrDefId::TypeAliasId(_) => None,
196190
AttrDefId::GenericParamId(_) => None,
197191
}
198-
.map(|mid| self.allowed(mid, allow_name, true))
199-
.unwrap_or(false)
192+
.is_some_and(|mid| self.allowed(mid, allow_name, true))
200193
}
201194

202195
fn validate_func(&mut self, func: FunctionId) {
@@ -206,17 +199,7 @@ impl<'a> DeclValidator<'a> {
206199
return;
207200
}
208201

209-
let body = self.db.body(func.into());
210-
211-
// Recursively validate inner scope items, such as static variables and constants.
212-
for (_, block_def_map) in body.blocks(self.db.upcast()) {
213-
for (_, module) in block_def_map.modules() {
214-
for def_id in module.scope.declarations() {
215-
let mut validator = DeclValidator::new(self.db, self.krate);
216-
validator.validate_item(def_id);
217-
}
218-
}
219-
}
202+
self.validate_body_inner_items(func.into());
220203

221204
// Check whether non-snake case identifiers are allowed for this function.
222205
if self.allowed(func.into(), allow::NON_SNAKE_CASE, false) {
@@ -231,6 +214,8 @@ impl<'a> DeclValidator<'a> {
231214
expected_case: CaseType::LowerSnakeCase,
232215
});
233216

217+
let body = self.db.body(func.into());
218+
234219
// Check the patterns inside the function body.
235220
// This includes function parameters.
236221
let pats_replacements = body
@@ -496,6 +481,11 @@ impl<'a> DeclValidator<'a> {
496481
fn validate_enum(&mut self, enum_id: EnumId) {
497482
let data = self.db.enum_data(enum_id);
498483

484+
for (local_id, _) in data.variants.iter() {
485+
let variant_id = EnumVariantId { parent: enum_id, local_id };
486+
self.validate_body_inner_items(variant_id.into());
487+
}
488+
499489
// Check whether non-camel case names are allowed for this enum.
500490
if self.allowed(enum_id.into(), allow::NON_CAMEL_CASE_TYPES, false) {
501491
return;
@@ -512,13 +502,11 @@ impl<'a> DeclValidator<'a> {
512502
// Check the field names.
513503
let enum_fields_replacements = data
514504
.variants
515-
.iter()
516-
.filter_map(|(_, variant)| {
505+
.values()
506+
.filter_map(|variant| {
517507
Some(Replacement {
518508
current_name: variant.name.clone(),
519-
suggested_text: to_camel_case(
520-
&variant.name.display(self.db.upcast()).to_string(),
521-
)?,
509+
suggested_text: to_camel_case(&variant.name.to_smol_str())?,
522510
expected_case: CaseType::UpperCamelCase,
523511
})
524512
})
@@ -622,6 +610,8 @@ impl<'a> DeclValidator<'a> {
622610
fn validate_const(&mut self, const_id: ConstId) {
623611
let data = self.db.const_data(const_id);
624612

613+
self.validate_body_inner_items(const_id.into());
614+
625615
if self.allowed(const_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) {
626616
return;
627617
}
@@ -631,7 +621,7 @@ impl<'a> DeclValidator<'a> {
631621
None => return,
632622
};
633623

634-
let const_name = name.display(self.db.upcast()).to_string();
624+
let const_name = name.to_smol_str();
635625
let replacement = if let Some(new_name) = to_upper_snake_case(&const_name) {
636626
Replacement {
637627
current_name: name.clone(),
@@ -670,13 +660,15 @@ impl<'a> DeclValidator<'a> {
670660
return;
671661
}
672662

663+
self.validate_body_inner_items(static_id.into());
664+
673665
if self.allowed(static_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) {
674666
return;
675667
}
676668

677669
let name = &data.name;
678670

679-
let static_name = name.display(self.db.upcast()).to_string();
671+
let static_name = name.to_smol_str();
680672
let replacement = if let Some(new_name) = to_upper_snake_case(&static_name) {
681673
Replacement {
682674
current_name: name.clone(),
@@ -707,4 +699,17 @@ impl<'a> DeclValidator<'a> {
707699

708700
self.sink.push(diagnostic);
709701
}
702+
703+
// FIXME: We don't currently validate names within `DefWithBodyId::InTypeConstId`.
704+
/// Recursively validates inner scope items, such as static variables and constants.
705+
fn validate_body_inner_items(&mut self, body_id: DefWithBodyId) {
706+
let body = self.db.body(body_id);
707+
for (_, block_def_map) in body.blocks(self.db.upcast()) {
708+
for (_, module) in block_def_map.modules() {
709+
for def_id in module.scope.declarations() {
710+
self.validate_item(def_id);
711+
}
712+
}
713+
}
714+
}
710715
}

crates/hir/src/lib.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -378,19 +378,14 @@ impl ModuleDef {
378378
ModuleDef::BuiltinType(_) | ModuleDef::Macro(_) => return Vec::new(),
379379
};
380380

381-
let module = match self.module(db) {
382-
Some(it) => it,
383-
None => return Vec::new(),
384-
};
385-
386381
let mut acc = Vec::new();
387382

388383
match self.as_def_with_body() {
389384
Some(def) => {
390385
def.diagnostics(db, &mut acc);
391386
}
392387
None => {
393-
for diag in hir_ty::diagnostics::incorrect_case(db, module.id.krate(), id) {
388+
for diag in hir_ty::diagnostics::incorrect_case(db, id) {
394389
acc.push(diag.into())
395390
}
396391
}
@@ -1831,7 +1826,7 @@ impl DefWithBody {
18311826
// FIXME: don't ignore diagnostics for in type const
18321827
DefWithBody::InTypeConst(_) => return,
18331828
};
1834-
for diag in hir_ty::diagnostics::incorrect_case(db, krate, def.into()) {
1829+
for diag in hir_ty::diagnostics::incorrect_case(db, def.into()) {
18351830
acc.push(diag.into())
18361831
}
18371832
}

crates/ide-diagnostics/src/handlers/incorrect_case.rs

+96
Original file line numberDiff line numberDiff line change
@@ -545,4 +545,100 @@ pub static SomeStatic: u8 = 10;
545545
"#,
546546
);
547547
}
548+
549+
#[test]
550+
fn fn_inner_items() {
551+
check_diagnostics(
552+
r#"
553+
fn main() {
554+
const foo: bool = true;
555+
//^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
556+
static bar: bool = true;
557+
//^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
558+
fn BAZ() {
559+
//^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
560+
const foo: bool = true;
561+
//^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
562+
static bar: bool = true;
563+
//^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
564+
fn BAZ() {
565+
//^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
566+
let INNER_INNER = 42;
567+
//^^^^^^^^^^^ 💡 warn: Variable `INNER_INNER` should have snake_case name, e.g. `inner_inner`
568+
}
569+
570+
let INNER_LOCAL = 42;
571+
//^^^^^^^^^^^ 💡 warn: Variable `INNER_LOCAL` should have snake_case name, e.g. `inner_local`
572+
}
573+
}
574+
"#,
575+
);
576+
}
577+
578+
#[test]
579+
fn const_body_inner_items() {
580+
check_diagnostics(
581+
r#"
582+
const _: () = {
583+
static bar: bool = true;
584+
//^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
585+
fn BAZ() {}
586+
//^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
587+
588+
const foo: () = {
589+
//^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
590+
const foo: bool = true;
591+
//^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
592+
static bar: bool = true;
593+
//^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
594+
fn BAZ() {}
595+
//^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
596+
};
597+
};
598+
"#,
599+
);
600+
}
601+
602+
#[test]
603+
fn static_body_inner_items() {
604+
check_diagnostics(
605+
r#"
606+
static FOO: () = {
607+
const foo: bool = true;
608+
//^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
609+
fn BAZ() {}
610+
//^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
611+
612+
static bar: () = {
613+
//^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
614+
const foo: bool = true;
615+
//^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
616+
static bar: bool = true;
617+
//^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
618+
fn BAZ() {}
619+
//^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
620+
};
621+
};
622+
"#,
623+
);
624+
}
625+
626+
#[test]
627+
fn enum_variant_body_inner_item() {
628+
check_diagnostics(
629+
r#"
630+
enum E {
631+
A = {
632+
const foo: bool = true;
633+
//^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
634+
static bar: bool = true;
635+
//^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
636+
fn BAZ() {}
637+
//^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
638+
42
639+
},
640+
}
641+
"#,
642+
);
643+
}
548644
}

0 commit comments

Comments
 (0)