Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #22734 from A4-Tacks/array-len-fixes
feat: add fixes for array length for type_mismatch
A4-Tacks 4 weeks ago
parent 0e3f6f8 · parent e1ed467 · commit afdf929
-rw-r--r--crates/ide-diagnostics/src/handlers/type_mismatch.rs109
1 files changed, 109 insertions, 0 deletions
diff --git a/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 8950850d4a..295f37ab1d 100644
--- a/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -75,6 +75,7 @@ fn fixes(ctx: &DiagnosticsContext<'_, '_>, d: &hir::TypeMismatch<'_>) -> Option<
remove_semicolon(ctx, d, expr_ptr, &mut fixes);
str_ref_to_owned(ctx, d, expr_ptr, &mut fixes);
add_await(ctx, d, expr_ptr, &mut fixes);
+ array_length(ctx, d, expr_ptr, &mut fixes);
}
if fixes.is_empty() { None } else { Some(fixes) }
@@ -402,6 +403,59 @@ fn add_await(
Some(())
}
+fn array_length(
+ ctx: &DiagnosticsContext<'_, '_>,
+ d: &hir::TypeMismatch<'_>,
+ expr_ptr: &InFile<AstPtr<ast::Expr>>,
+ acc: &mut Vec<Assist>,
+) -> Option<()> {
+ let (ty1, expected) = d.expected.as_array(ctx.db())?;
+ let (ty2, actual) = d.actual.as_array(ctx.db())?;
+
+ if !ty1.could_unify_with(ctx.db(), &ty2) || expected == actual {
+ return None;
+ }
+
+ let root = expr_ptr.file_id.parse_or_expand(ctx.db());
+ let expr = expr_ptr.value.to_node(&root);
+ let container = skip_transparent(expr).syntax().parent()?;
+ let ty = syntax::match_ast! {
+ match container {
+ ast::LetStmt(it) => it.ty()?,
+ ast::Static(it) => it.ty()?,
+ ast::Const(it) => it.ty()?,
+ _ => return None,
+ }
+ };
+ let ast::Type::ArrayType(ty) = ty else { return None };
+ let len = ty.const_arg()?.expr()?;
+ let hir::FileRange { range: len_range, .. } = ctx.sema.original_range_opt(len.syntax())?;
+ let hir::FileRange { range, file_id } = ctx.sema.original_range_opt(&container)?;
+
+ let edit = TextEdit::replace(len_range, actual.to_string());
+ let source_change = SourceChange::from_text_edit(file_id.file_id(ctx.db()), edit);
+ let label = &format!("Change array length to {actual}");
+ acc.push(fix("array_length", label, source_change, range));
+
+ fn skip_transparent(mut expr: Expr) -> Expr {
+ while let Some(parent) = expr.syntax().parent() {
+ if let Some(it) = ast::StmtList::cast(parent.clone())
+ && it.statements().next().is_none()
+ && let Some(parent) = it.syntax().parent().and_then(Expr::cast)
+ {
+ expr = parent;
+ } else if let Some(parent) = ast::ParenExpr::cast(parent) {
+ expr = parent.into();
+ } else {
+ break;
+ }
+ }
+ expr
+ }
+
+ Some(())
+}
+
#[cfg(test)]
mod tests {
use crate::tests::{
@@ -1461,6 +1515,61 @@ identity! {
}
#[test]
+ fn array_length() {
+ check_fix(
+ r#"
+const VALS: [i32; 2$0] = [1, 2, 3];
+ "#,
+ r#"
+const VALS: [i32; 3] = [1, 2, 3];
+ "#,
+ );
+
+ check_fix(
+ r#"
+static VALS: [i32; 2$0] = [1, 2, 3];
+ "#,
+ r#"
+static VALS: [i32; 3] = [1, 2, 3];
+ "#,
+ );
+
+ check_fix(
+ r#"
+static VALS: [i32; 2$0] = {[1, 2, 3]};
+ "#,
+ r#"
+static VALS: [i32; 3] = {[1, 2, 3]};
+ "#,
+ );
+
+ // Convenient trigger range
+ check_fix(
+ r#"
+static VALS: [i32; 2] = [$01, 2, 3];
+ "#,
+ r#"
+static VALS: [i32; 3] = [1, 2, 3];
+ "#,
+ );
+
+ check_fix(
+ r#"
+macro_rules! identity { ($($t:tt)*) => ($($t)*) }
+identity! {
+ const VALS: [i32; 2$0] = [1, 2, 3];
+}
+ "#,
+ r#"
+macro_rules! identity { ($($t:tt)*) => ($($t)*) }
+identity! {
+ const VALS: [i32; 3] = [1, 2, 3];
+}
+ "#,
+ );
+ }
+
+ #[test]
fn type_mismatch_range_adjustment() {
cov_mark::check!(type_mismatch_range_adjustment);
check_diagnostics(