Skip to content

Commit 23aa872

Browse files
committed
refactor hir-ty::diagnostics::decl_check for function bodies
1 parent c0071ac commit 23aa872

File tree

1 file changed

+55
-71
lines changed

1 file changed

+55
-71
lines changed

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

Lines changed: 55 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,9 @@ mod case_conv;
1616
use std::fmt;
1717

1818
use hir_def::{
19-
data::adt::VariantData,
20-
db::DefDatabase,
21-
hir::{Pat, PatId},
22-
src::HasSource,
23-
AdtId, AttrDefId, ConstId, EnumId, FunctionId, ItemContainerId, Lookup, ModuleDefId, ModuleId,
24-
StaticId, StructId, TraitId, TypeAliasId,
19+
data::adt::VariantData, db::DefDatabase, hir::Pat, src::HasSource, AdtId, AttrDefId, ConstId,
20+
EnumId, FunctionId, ItemContainerId, Lookup, ModuleDefId, ModuleId, StaticId, StructId,
21+
TraitId, TypeAliasId,
2522
};
2623
use hir_expand::{
2724
name::{AsName, Name},
@@ -298,11 +295,9 @@ impl<'a> DeclValidator<'a> {
298295
return;
299296
}
300297

301-
// Check whether function is an associated item of a trait implementation
302-
let is_trait_impl_assoc_fn = self.is_trait_impl_container(container);
303-
304298
// Check the function name.
305-
if !is_trait_impl_assoc_fn {
299+
// Skipped if function is an associated item of a trait implementation.
300+
if !self.is_trait_impl_container(container) {
306301
let data = self.db.function_data(func);
307302
self.create_incorrect_case_diagnostic_for_item_name(
308303
func,
@@ -315,91 +310,80 @@ impl<'a> DeclValidator<'a> {
315310
}
316311

317312
// Check the patterns inside the function body.
318-
// This includes function parameters if it's not an associated function
319-
// of a trait implementation.
313+
self.validate_func_body(func);
314+
}
315+
316+
/// Check incorrect names for patterns inside the function body.
317+
/// This includes function parameters except for trait implementation associated functions.
318+
fn validate_func_body(&mut self, func: FunctionId) {
319+
// Check whether function is an associated item of a trait implementation
320+
let container = func.lookup(self.db.upcast()).container;
321+
let is_trait_impl_assoc_fn = self.is_trait_impl_container(container);
322+
320323
let body = self.db.body(func.into());
321-
let pats_replacements = body
324+
let mut pats_replacements = body
322325
.pats
323326
.iter()
324327
.filter_map(|(pat_id, pat)| match pat {
325328
Pat::Bind { id, .. } => {
326-
// Filter out parameters if it's an associated function
327-
// of a trait implementation.
329+
// Filter out parameters for trait implementation associated functions.
328330
if is_trait_impl_assoc_fn
329331
&& body.params.iter().any(|param_id| *param_id == pat_id)
330332
{
331333
cov_mark::hit!(trait_impl_assoc_func_param_incorrect_case_ignored);
332334
None
333335
} else {
334-
Some((pat_id, &body.bindings[*id].name))
336+
let bind_name = &body.bindings[*id].name;
337+
let replacement = Replacement {
338+
current_name: bind_name.clone(),
339+
suggested_text: to_lower_snake_case(&bind_name.to_smol_str())?,
340+
expected_case: CaseType::LowerSnakeCase,
341+
};
342+
Some((pat_id, replacement))
335343
}
336344
}
337345
_ => None,
338346
})
339-
.filter_map(|(id, bind_name)| {
340-
Some((
341-
id,
342-
Replacement {
343-
current_name: bind_name.clone(),
344-
suggested_text: to_lower_snake_case(
345-
&bind_name.display(self.db.upcast()).to_string(),
346-
)?,
347-
expected_case: CaseType::LowerSnakeCase,
348-
},
349-
))
350-
})
351-
.collect();
352-
self.create_incorrect_case_diagnostic_for_func_variables(func, pats_replacements);
353-
}
347+
.peekable();
354348

355-
/// Given the information about incorrect variable names, looks up into the source code
356-
/// for exact locations and adds diagnostics into the sink.
357-
fn create_incorrect_case_diagnostic_for_func_variables(
358-
&mut self,
359-
func: FunctionId,
360-
pats_replacements: Vec<(PatId, Replacement)>,
361-
) {
362349
// XXX: only look at source_map if we do have missing fields
363-
if pats_replacements.is_empty() {
350+
if pats_replacements.peek().is_none() {
364351
return;
365352
}
366353

367354
let (_, source_map) = self.db.body_with_source_map(func.into());
368-
369355
for (id, replacement) in pats_replacements {
370-
if let Ok(source_ptr) = source_map.pat_syntax(id) {
371-
if let Some(ptr) = source_ptr.value.cast::<ast::IdentPat>() {
372-
let root = source_ptr.file_syntax(self.db.upcast());
373-
let ident_pat = ptr.to_node(&root);
374-
let parent = match ident_pat.syntax().parent() {
375-
Some(parent) => parent,
376-
None => continue,
377-
};
378-
379-
let is_param = ast::Param::can_cast(parent.kind());
380-
381-
// We have to check that it's either `let var = ...` or `var @ Variant(_)` statement,
382-
// because e.g. match arms are patterns as well.
383-
// In other words, we check that it's a named variable binding.
384-
let is_binding = ast::LetStmt::can_cast(parent.kind())
385-
|| (ast::MatchArm::can_cast(parent.kind())
386-
&& ident_pat.at_token().is_some());
387-
if !(is_param || is_binding) {
388-
// This pattern is not an actual variable declaration, e.g. `Some(val) => {..}` match arm.
389-
continue;
390-
}
391-
392-
let ident_type =
393-
if is_param { IdentType::Parameter } else { IdentType::Variable };
356+
let Ok(source_ptr) = source_map.pat_syntax(id) else {
357+
continue;
358+
};
359+
let Some(ptr) = source_ptr.value.cast::<ast::IdentPat>() else {
360+
continue;
361+
};
362+
let root = source_ptr.file_syntax(self.db.upcast());
363+
let ident_pat = ptr.to_node(&root);
364+
let Some(parent) = ident_pat.syntax().parent() else {
365+
continue;
366+
};
394367

395-
self.create_incorrect_case_diagnostic_for_ast_node(
396-
replacement,
397-
source_ptr.file_id,
398-
&ident_pat,
399-
ident_type,
400-
);
401-
}
368+
let is_param = ast::Param::can_cast(parent.kind());
369+
// We have to check that it's either `let var = ...` or `var @ Variant(_)` statement,
370+
// because e.g. match arms are patterns as well.
371+
// In other words, we check that it's a named variable binding.
372+
let is_binding = ast::LetStmt::can_cast(parent.kind())
373+
|| (ast::MatchArm::can_cast(parent.kind()) && ident_pat.at_token().is_some());
374+
if !(is_param || is_binding) {
375+
// This pattern is not an actual variable declaration, e.g. `Some(val) => {..}` match arm.
376+
continue;
402377
}
378+
379+
let ident_type = if is_param { IdentType::Parameter } else { IdentType::Variable };
380+
381+
self.create_incorrect_case_diagnostic_for_ast_node(
382+
replacement,
383+
source_ptr.file_id,
384+
&ident_pat,
385+
ident_type,
386+
);
403387
}
404388
}
405389

0 commit comments

Comments
 (0)