mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-08-20 02:20:21 +00:00
Merge #10543
10543: Narrow add_missing_match_arms assist range r=Veykril a=antonfirsov Contributes to #10220 with logic borrowed from #10267. Note: if anyone has recommendations for further analyzers to check, I'm happy to (hard to do it on my own, I'm completely new to the language). Co-authored-by: Anton Firszov <antonfir@gmail.com>
This commit is contained in:
commit
c67db1b952
1 changed files with 118 additions and 8 deletions
|
@ -5,7 +5,8 @@ use hir::{Adt, HasSource, ModuleDef, Semantics};
|
||||||
use ide_db::helpers::{mod_path_to_ast, FamousDefs};
|
use ide_db::helpers::{mod_path_to_ast, FamousDefs};
|
||||||
use ide_db::RootDatabase;
|
use ide_db::RootDatabase;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use syntax::ast::{self, make, AstNode, HasName, MatchArm, Pat};
|
use syntax::ast::{self, make, AstNode, HasName, MatchArm, MatchArmList, MatchExpr, Pat};
|
||||||
|
use syntax::TextRange;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
utils::{self, render_snippet, Cursor},
|
utils::{self, render_snippet, Cursor},
|
||||||
|
@ -39,6 +40,22 @@ use crate::{
|
||||||
pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
||||||
let match_expr = ctx.find_node_at_offset_with_descend::<ast::MatchExpr>()?;
|
let match_expr = ctx.find_node_at_offset_with_descend::<ast::MatchExpr>()?;
|
||||||
let match_arm_list = match_expr.match_arm_list()?;
|
let match_arm_list = match_expr.match_arm_list()?;
|
||||||
|
let target_range: TextRange;
|
||||||
|
|
||||||
|
if let None = cursor_at_trivial_match_arm_list(&ctx, &match_expr, &match_arm_list) {
|
||||||
|
target_range = TextRange::new(
|
||||||
|
ctx.sema.original_range(match_expr.syntax()).range.start(),
|
||||||
|
ctx.sema.original_range(match_arm_list.syntax()).range.start(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let cursor_in_range = target_range.contains_range(ctx.selection_trimmed());
|
||||||
|
if !cursor_in_range {
|
||||||
|
cov_mark::hit!(not_applicable_outside_of_range_right);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target_range = ctx.sema.original_range(match_expr.syntax()).range;
|
||||||
|
}
|
||||||
|
|
||||||
let expr = match_expr.expr()?;
|
let expr = match_expr.expr()?;
|
||||||
|
|
||||||
|
@ -121,11 +138,10 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext) ->
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let target = ctx.sema.original_range(match_expr.syntax()).range;
|
|
||||||
acc.add(
|
acc.add(
|
||||||
AssistId("add_missing_match_arms", AssistKind::QuickFix),
|
AssistId("add_missing_match_arms", AssistKind::QuickFix),
|
||||||
"Fill match arms",
|
"Fill match arms",
|
||||||
target,
|
target_range,
|
||||||
|builder| {
|
|builder| {
|
||||||
let new_match_arm_list = match_arm_list.clone_for_update();
|
let new_match_arm_list = match_arm_list.clone_for_update();
|
||||||
let missing_arms = missing_pats
|
let missing_arms = missing_pats
|
||||||
|
@ -177,6 +193,29 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext) ->
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cursor_at_trivial_match_arm_list(
|
||||||
|
ctx: &AssistContext,
|
||||||
|
match_expr: &MatchExpr,
|
||||||
|
match_arm_list: &MatchArmList,
|
||||||
|
) -> Option<()> {
|
||||||
|
// match x { $0 }
|
||||||
|
if match_arm_list.arms().next() == None {
|
||||||
|
cov_mark::hit!(add_missing_match_arms_empty_body);
|
||||||
|
return Some(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// match { _$0 => {...} }
|
||||||
|
let wild_pat = ctx.find_node_at_offset_with_descend::<ast::WildcardPat>()?;
|
||||||
|
let arm = wild_pat.syntax().parent().and_then(ast::MatchArm::cast)?;
|
||||||
|
let arm_match_expr = arm.syntax().ancestors().nth(2).and_then(ast::MatchExpr::cast)?;
|
||||||
|
if arm_match_expr == *match_expr {
|
||||||
|
cov_mark::hit!(add_missing_match_arms_trivial_arm);
|
||||||
|
return Some(());
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn is_variant_missing(existing_pats: &[Pat], var: &Pat) -> bool {
|
fn is_variant_missing(existing_pats: &[Pat], var: &Pat) -> bool {
|
||||||
!existing_pats.iter().any(|pat| does_pat_match_variant(pat, var))
|
!existing_pats.iter().any(|pat| does_pat_match_variant(pat, var))
|
||||||
}
|
}
|
||||||
|
@ -306,6 +345,39 @@ fn main() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn not_applicable_outside_of_range_left() {
|
||||||
|
check_assist_not_applicable(
|
||||||
|
add_missing_match_arms,
|
||||||
|
r#"
|
||||||
|
enum A { X, Y }
|
||||||
|
|
||||||
|
fn foo(a: A) {
|
||||||
|
$0 match a {
|
||||||
|
A::X => { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn not_applicable_outside_of_range_right() {
|
||||||
|
cov_mark::check!(not_applicable_outside_of_range_right);
|
||||||
|
check_assist_not_applicable(
|
||||||
|
add_missing_match_arms,
|
||||||
|
r#"
|
||||||
|
enum A { X, Y }
|
||||||
|
|
||||||
|
fn foo(a: A) {
|
||||||
|
match a {$0
|
||||||
|
A::X => { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn all_boolean_match_arms_provided() {
|
fn all_boolean_match_arms_provided() {
|
||||||
check_assist_not_applicable(
|
check_assist_not_applicable(
|
||||||
|
@ -583,6 +655,7 @@ fn main() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add_missing_match_arms_empty_body() {
|
fn add_missing_match_arms_empty_body() {
|
||||||
|
cov_mark::check!(add_missing_match_arms_empty_body);
|
||||||
check_assist(
|
check_assist(
|
||||||
add_missing_match_arms,
|
add_missing_match_arms,
|
||||||
r#"
|
r#"
|
||||||
|
@ -590,7 +663,7 @@ enum A { As, Bs, Cs(String), Ds(String, String), Es { x: usize, y: usize } }
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let a = A::As;
|
let a = A::As;
|
||||||
match a$0 {}
|
match a {$0}
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
r#"
|
r#"
|
||||||
|
@ -853,7 +926,7 @@ fn foo(a: &mut A) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add_missing_match_arms_target() {
|
fn add_missing_match_arms_target_simple() {
|
||||||
check_assist_target(
|
check_assist_target(
|
||||||
add_missing_match_arms,
|
add_missing_match_arms,
|
||||||
r#"
|
r#"
|
||||||
|
@ -867,8 +940,26 @@ fn main() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_missing_match_arms_target_complex() {
|
||||||
|
check_assist_target(
|
||||||
|
add_missing_match_arms,
|
||||||
|
r#"
|
||||||
|
enum E { X, Y }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match E::X$0 {
|
||||||
|
E::X => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
"match E::X ",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add_missing_match_arms_trivial_arm() {
|
fn add_missing_match_arms_trivial_arm() {
|
||||||
|
cov_mark::check!(add_missing_match_arms_trivial_arm);
|
||||||
check_assist(
|
check_assist(
|
||||||
add_missing_match_arms,
|
add_missing_match_arms,
|
||||||
r#"
|
r#"
|
||||||
|
@ -893,6 +984,25 @@ fn main() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn wildcard_inside_expression_not_applicable() {
|
||||||
|
check_assist_not_applicable(
|
||||||
|
add_missing_match_arms,
|
||||||
|
r#"
|
||||||
|
enum E { X, Y }
|
||||||
|
|
||||||
|
fn foo(e : E) {
|
||||||
|
match e {
|
||||||
|
_ => {
|
||||||
|
println!("1");$0
|
||||||
|
println!("2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add_missing_match_arms_qualifies_path() {
|
fn add_missing_match_arms_qualifies_path() {
|
||||||
check_assist(
|
check_assist(
|
||||||
|
@ -928,8 +1038,8 @@ fn main() {
|
||||||
r#"
|
r#"
|
||||||
enum A { One, Two }
|
enum A { One, Two }
|
||||||
fn foo(a: A) {
|
fn foo(a: A) {
|
||||||
match a {
|
match a $0 {
|
||||||
// foo bar baz$0
|
// foo bar baz
|
||||||
A::One => {}
|
A::One => {}
|
||||||
// This is where the rest should be
|
// This is where the rest should be
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue