mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 05:45:12 +00:00
feat: filter already present enum variants in match arms
This commit is contained in:
parent
68fd1ce313
commit
794988c53b
8 changed files with 114 additions and 16 deletions
|
@ -23,7 +23,7 @@ pub(crate) mod env_vars;
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use hir::{known, ScopeDef};
|
use hir::{known, ScopeDef, Variant};
|
||||||
use ide_db::{imports::import_assets::LocatedImport, SymbolKind};
|
use ide_db::{imports::import_assets::LocatedImport, SymbolKind};
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
|
||||||
|
@ -538,18 +538,25 @@ fn enum_variants_with_paths(
|
||||||
enum_: hir::Enum,
|
enum_: hir::Enum,
|
||||||
impl_: &Option<ast::Impl>,
|
impl_: &Option<ast::Impl>,
|
||||||
cb: impl Fn(&mut Completions, &CompletionContext<'_>, hir::Variant, hir::ModPath),
|
cb: impl Fn(&mut Completions, &CompletionContext<'_>, hir::Variant, hir::ModPath),
|
||||||
|
missing_variants: Option<Vec<Variant>>,
|
||||||
) {
|
) {
|
||||||
let variants = enum_.variants(ctx.db);
|
let mut process_variant = |variant: Variant| {
|
||||||
|
let self_path = hir::ModPath::from_segments(
|
||||||
|
hir::PathKind::Plain,
|
||||||
|
iter::once(known::SELF_TYPE).chain(iter::once(variant.name(ctx.db))),
|
||||||
|
);
|
||||||
|
|
||||||
|
cb(acc, ctx, variant, self_path);
|
||||||
|
};
|
||||||
|
|
||||||
|
let variants = match missing_variants {
|
||||||
|
Some(missing_variants) => missing_variants,
|
||||||
|
None => enum_.variants(ctx.db),
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(impl_) = impl_.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) {
|
if let Some(impl_) = impl_.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) {
|
||||||
if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_)) {
|
if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_)) {
|
||||||
for &variant in &variants {
|
variants.iter().for_each(|variant| process_variant(*variant));
|
||||||
let self_path = hir::ModPath::from_segments(
|
|
||||||
hir::PathKind::Plain,
|
|
||||||
iter::once(known::SELF_TYPE).chain(iter::once(variant.name(ctx.db))),
|
|
||||||
);
|
|
||||||
cb(acc, ctx, variant, self_path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,6 +208,7 @@ pub(crate) fn complete_expr_path(
|
||||||
|acc, ctx, variant, path| {
|
|acc, ctx, variant, path| {
|
||||||
acc.add_qualified_enum_variant(ctx, path_ctx, variant, path)
|
acc.add_qualified_enum_variant(ctx, path_ctx, variant, path)
|
||||||
},
|
},
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,7 @@ use ide_db::imports::{
|
||||||
insert_use::ImportScope,
|
insert_use::ImportScope,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use syntax::{
|
use syntax::{ast, AstNode, SyntaxNode, T};
|
||||||
ast::{self},
|
|
||||||
AstNode, SyntaxNode, T,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::{
|
context::{
|
||||||
|
|
|
@ -58,6 +58,7 @@ pub(crate) fn complete_pattern(
|
||||||
|acc, ctx, variant, path| {
|
|acc, ctx, variant, path| {
|
||||||
acc.add_qualified_variant_pat(ctx, pattern_ctx, variant, path);
|
acc.add_qualified_variant_pat(ctx, pattern_ctx, variant, path);
|
||||||
},
|
},
|
||||||
|
Some(pattern_ctx.missing_variants.clone()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -220,6 +220,8 @@ pub(super) struct PatternContext {
|
||||||
/// The record pattern this name or ref is a field of
|
/// The record pattern this name or ref is a field of
|
||||||
pub(super) record_pat: Option<ast::RecordPat>,
|
pub(super) record_pat: Option<ast::RecordPat>,
|
||||||
pub(super) impl_: Option<ast::Impl>,
|
pub(super) impl_: Option<ast::Impl>,
|
||||||
|
/// List of missing variants in a match expr
|
||||||
|
pub(super) missing_variants: Vec<hir::Variant>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! Module responsible for analyzing the code surrounding the cursor for completion.
|
//! Module responsible for analyzing the code surrounding the cursor for completion.
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use hir::{Semantics, Type, TypeInfo};
|
use hir::{Semantics, Type, TypeInfo, Variant};
|
||||||
use ide_db::{active_parameter::ActiveParameter, RootDatabase};
|
use ide_db::{active_parameter::ActiveParameter, RootDatabase};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
algo::{find_node_at_offset, non_trivia_sibling},
|
algo::{find_node_at_offset, non_trivia_sibling},
|
||||||
|
@ -1111,6 +1111,9 @@ fn pattern_context_for(
|
||||||
pat: ast::Pat,
|
pat: ast::Pat,
|
||||||
) -> PatternContext {
|
) -> PatternContext {
|
||||||
let mut param_ctx = None;
|
let mut param_ctx = None;
|
||||||
|
|
||||||
|
let mut missing_variants = vec![];
|
||||||
|
|
||||||
let (refutability, has_type_ascription) =
|
let (refutability, has_type_ascription) =
|
||||||
pat
|
pat
|
||||||
.syntax()
|
.syntax()
|
||||||
|
@ -1140,7 +1143,52 @@ fn pattern_context_for(
|
||||||
})();
|
})();
|
||||||
return (PatternRefutability::Irrefutable, has_type_ascription)
|
return (PatternRefutability::Irrefutable, has_type_ascription)
|
||||||
},
|
},
|
||||||
ast::MatchArm(_) => PatternRefutability::Refutable,
|
ast::MatchArm(match_arm) => {
|
||||||
|
let missing_variants_opt = match_arm
|
||||||
|
.syntax()
|
||||||
|
.parent()
|
||||||
|
.and_then(ast::MatchArmList::cast)
|
||||||
|
.and_then(|match_arm_list| {
|
||||||
|
match_arm_list
|
||||||
|
.syntax()
|
||||||
|
.parent()
|
||||||
|
.and_then(ast::MatchExpr::cast)
|
||||||
|
.and_then(|match_expr| {
|
||||||
|
let expr_opt = find_opt_node_in_file(&original_file, match_expr.expr());
|
||||||
|
|
||||||
|
expr_opt.and_then(|expr| {
|
||||||
|
sema.type_of_expr(&expr)?
|
||||||
|
.adjusted()
|
||||||
|
.autoderef(sema.db)
|
||||||
|
.find_map(|ty| match ty.as_adt() {
|
||||||
|
Some(hir::Adt::Enum(e)) => Some(e),
|
||||||
|
_ => None,
|
||||||
|
}).and_then(|enum_| {
|
||||||
|
Some(enum_.variants(sema.db))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}).and_then(|variants| {
|
||||||
|
Some(variants.iter().filter_map(|variant| {
|
||||||
|
let variant_name = variant.name(sema.db).to_string();
|
||||||
|
|
||||||
|
let variant_already_present = match_arm_list.arms().any(|arm| {
|
||||||
|
arm.pat().and_then(|pat| {
|
||||||
|
let pat_already_present = pat.syntax().to_string().contains(&variant_name);
|
||||||
|
pat_already_present.then(|| pat_already_present)
|
||||||
|
}).is_some()
|
||||||
|
});
|
||||||
|
|
||||||
|
(!variant_already_present).then_some(variant.clone())
|
||||||
|
}).collect::<Vec<Variant>>())
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(missing_variants_) = missing_variants_opt {
|
||||||
|
missing_variants = missing_variants_;
|
||||||
|
};
|
||||||
|
|
||||||
|
PatternRefutability::Refutable
|
||||||
|
},
|
||||||
ast::LetExpr(_) => PatternRefutability::Refutable,
|
ast::LetExpr(_) => PatternRefutability::Refutable,
|
||||||
ast::ForExpr(_) => PatternRefutability::Irrefutable,
|
ast::ForExpr(_) => PatternRefutability::Irrefutable,
|
||||||
_ => PatternRefutability::Irrefutable,
|
_ => PatternRefutability::Irrefutable,
|
||||||
|
@ -1162,6 +1210,7 @@ fn pattern_context_for(
|
||||||
ref_token,
|
ref_token,
|
||||||
record_pat: None,
|
record_pat: None,
|
||||||
impl_: fetch_immediate_impl(sema, original_file, pat.syntax()),
|
impl_: fetch_immediate_impl(sema, original_file, pat.syntax()),
|
||||||
|
missing_variants,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ pub(crate) fn render_struct_pat(
|
||||||
let lookup = format_literal_lookup(name.as_str(), kind);
|
let lookup = format_literal_lookup(name.as_str(), kind);
|
||||||
let pat = render_pat(&ctx, pattern_ctx, &escaped_name, kind, &visible_fields, fields_omitted)?;
|
let pat = render_pat(&ctx, pattern_ctx, &escaped_name, kind, &visible_fields, fields_omitted)?;
|
||||||
|
|
||||||
Some(build_completion(ctx, label, lookup, pat, strukt, false))
|
Some(build_completion(ctx, label, lookup, pat, strukt, true))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn render_variant_pat(
|
pub(crate) fn render_variant_pat(
|
||||||
|
|
|
@ -46,6 +46,47 @@ fn foo(s: Struct) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn record_pattern_field_enum() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
enum Baz { FOO, BAR }
|
||||||
|
|
||||||
|
fn foo(baz: Baz) {
|
||||||
|
match baz {
|
||||||
|
Baz::FOO => (),
|
||||||
|
$0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
en Baz
|
||||||
|
bn Baz::BAR Baz::BAR$0
|
||||||
|
kw mut
|
||||||
|
kw ref
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
enum Baz { FOO, BAR }
|
||||||
|
|
||||||
|
fn foo(baz: Baz) {
|
||||||
|
match baz {
|
||||||
|
FOO => (),
|
||||||
|
$0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
en Baz
|
||||||
|
bn Baz::BAR Baz::BAR$0
|
||||||
|
kw mut
|
||||||
|
kw ref
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pattern_enum_variant() {
|
fn pattern_enum_variant() {
|
||||||
check(
|
check(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue