Avoid adding a RecordFieldPat variant to the Pat enum

This commit is contained in:
Geoffrey Copin 2020-04-11 17:04:25 +02:00
parent 21443f1b48
commit 270bcfdfc2
4 changed files with 48 additions and 49 deletions

View file

@ -4,71 +4,79 @@ use itertools::Itertools;
use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct}; use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct};
use ra_ide_db::RootDatabase; use ra_ide_db::RootDatabase;
use ra_syntax::ast::{Name, Pat};
use ra_syntax::{ use ra_syntax::{
ast, algo, ast,
ast::{Path, RecordField, RecordLit, RecordPat}, ast::{Name, Path, RecordLit, RecordPat},
AstNode, AstNode, SyntaxKind, SyntaxNode,
}; };
use crate::{ use crate::{
assist_ctx::{Assist, AssistCtx}, assist_ctx::{Assist, AssistCtx},
AssistId, AssistId,
}; };
use ra_syntax::ast::{Expr, NameRef};
pub(crate) fn reorder_fields(ctx: AssistCtx) -> Option<Assist> { pub(crate) fn reorder_fields(ctx: AssistCtx) -> Option<Assist> {
reorder_struct(ctx.clone()).or_else(|| reorder_struct_pat(ctx)) reorder::<RecordLit>(ctx.clone()).or_else(|| reorder::<RecordPat>(ctx))
} }
fn reorder_struct(ctx: AssistCtx) -> Option<Assist> { fn reorder<R: AstNode>(ctx: AssistCtx) -> Option<Assist> {
let record: RecordLit = ctx.find_node_at_offset()?; let record = ctx.find_node_at_offset::<R>()?;
reorder(ctx, &record, &record.path()?, field_name) let path = record.syntax().children().find_map(Path::cast)?;
}
fn field_name(r: &RecordField) -> String { let ranks = compute_fields_ranks(&path, &ctx)?;
r.name_ref()
.map(|name| name.syntax().text().to_string())
.or_else(|| r.expr().map(|e| e.syntax().text().to_string()))
.unwrap_or_default()
}
fn reorder_struct_pat(ctx: AssistCtx) -> Option<Assist> { let fields = get_fields(&record.syntax());
let record: RecordPat = ctx.find_node_at_offset()?; let sorted_fields = sorted_by_rank(&fields, |node| {
reorder(ctx, &record, &record.path()?, field_pat_name) *ranks.get(&get_field_name(node)).unwrap_or(&usize::max_value())
} });
fn field_pat_name(field: &Pat) -> String {
field.syntax().children().find_map(Name::cast).map(|n| n.to_string()).unwrap_or_default()
}
fn reorder<R: AstNode, F: AstNode + Eq + Clone>(
ctx: AssistCtx,
record: &R,
path: &Path,
field_name: fn(&F) -> String,
) -> Option<Assist> {
let ranks = compute_fields_ranks(path, &ctx)?;
let fields: Vec<F> = get_fields(record);
let sorted_fields: Vec<F> =
sort_by_rank(&fields, |f| *ranks.get(&field_name(f)).unwrap_or(&usize::max_value()));
if sorted_fields == fields { if sorted_fields == fields {
return None; return None;
} }
ctx.add_assist(AssistId("reorder_fields"), "Reorder record fields", |edit| { ctx.add_assist(AssistId("reorder_fields"), "Reorder record fields", |edit| {
for (old, new) in fields.into_iter().zip(sorted_fields) { for (old, new) in fields.iter().zip(&sorted_fields) {
edit.replace_ast(old, new); algo::diff(old, new).into_text_edit(edit.text_edit_builder());
} }
edit.target(record.syntax().text_range()) edit.target(record.syntax().text_range())
}) })
} }
fn get_fields<R: AstNode, F: AstNode>(record: &R) -> Vec<F> { fn get_fields_kind(node: &SyntaxNode) -> Vec<SyntaxKind> {
record.syntax().children().flat_map(|n1| n1.children()).filter_map(|n3| F::cast(n3)).collect() use SyntaxKind::*;
match node.kind() {
RECORD_LIT => vec![RECORD_FIELD],
RECORD_PAT => vec![RECORD_FIELD_PAT, BIND_PAT],
_ => vec![],
}
} }
fn sort_by_rank<F: AstNode + Clone>(fields: &[F], get_rank: impl FnMut(&F) -> usize) -> Vec<F> { fn get_field_name(node: &SyntaxNode) -> String {
use SyntaxKind::*;
match node.kind() {
RECORD_FIELD => {
if let Some(name) = node.children().find_map(NameRef::cast) {
return name.to_string();
}
node.children().find_map(Expr::cast).map(|expr| expr.to_string()).unwrap_or_default()
}
BIND_PAT | RECORD_FIELD_PAT => {
node.children().find_map(Name::cast).map(|n| n.to_string()).unwrap_or_default()
}
_ => String::new(),
}
}
fn get_fields(record: &SyntaxNode) -> Vec<SyntaxNode> {
let kinds = get_fields_kind(record);
record.children().flat_map(|n| n.children()).filter(|n| kinds.contains(&n.kind())).collect()
}
fn sorted_by_rank(
fields: &[SyntaxNode],
get_rank: impl Fn(&SyntaxNode) -> usize,
) -> Vec<SyntaxNode> {
fields.iter().cloned().sorted_by_key(get_rank).collect() fields.iter().cloned().sorted_by_key(get_rank).collect()
} }

View file

@ -691,8 +691,6 @@ impl ExprCollector<'_> {
} }
// FIXME: implement // FIXME: implement
ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing,
// FIXME: implement
ast::Pat::RecordFieldPat(_) => Pat::Missing,
}; };
let ptr = AstPtr::new(&pat); let ptr = AstPtr::new(&pat);
self.alloc_pat(pattern, Either::Left(ptr)) self.alloc_pat(pattern, Either::Left(ptr))

View file

@ -3256,7 +3256,6 @@ pub enum Pat {
RangePat(RangePat), RangePat(RangePat),
LiteralPat(LiteralPat), LiteralPat(LiteralPat),
MacroPat(MacroPat), MacroPat(MacroPat),
RecordFieldPat(RecordFieldPat),
} }
impl From<OrPat> for Pat { impl From<OrPat> for Pat {
fn from(node: OrPat) -> Pat { Pat::OrPat(node) } fn from(node: OrPat) -> Pat { Pat::OrPat(node) }
@ -3303,15 +3302,12 @@ impl From<LiteralPat> for Pat {
impl From<MacroPat> for Pat { impl From<MacroPat> for Pat {
fn from(node: MacroPat) -> Pat { Pat::MacroPat(node) } fn from(node: MacroPat) -> Pat { Pat::MacroPat(node) }
} }
impl From<RecordFieldPat> for Pat {
fn from(node: RecordFieldPat) -> Pat { Pat::RecordFieldPat(node) }
}
impl AstNode for Pat { impl AstNode for Pat {
fn can_cast(kind: SyntaxKind) -> bool { fn can_cast(kind: SyntaxKind) -> bool {
match kind { match kind {
OR_PAT | PAREN_PAT | REF_PAT | BOX_PAT | BIND_PAT | PLACEHOLDER_PAT | DOT_DOT_PAT OR_PAT | PAREN_PAT | REF_PAT | BOX_PAT | BIND_PAT | PLACEHOLDER_PAT | DOT_DOT_PAT
| PATH_PAT | RECORD_PAT | TUPLE_STRUCT_PAT | TUPLE_PAT | SLICE_PAT | RANGE_PAT | PATH_PAT | RECORD_PAT | TUPLE_STRUCT_PAT | TUPLE_PAT | SLICE_PAT | RANGE_PAT
| LITERAL_PAT | MACRO_PAT | RECORD_FIELD_PAT => true, | LITERAL_PAT | MACRO_PAT => true,
_ => false, _ => false,
} }
} }
@ -3332,7 +3328,6 @@ impl AstNode for Pat {
RANGE_PAT => Pat::RangePat(RangePat { syntax }), RANGE_PAT => Pat::RangePat(RangePat { syntax }),
LITERAL_PAT => Pat::LiteralPat(LiteralPat { syntax }), LITERAL_PAT => Pat::LiteralPat(LiteralPat { syntax }),
MACRO_PAT => Pat::MacroPat(MacroPat { syntax }), MACRO_PAT => Pat::MacroPat(MacroPat { syntax }),
RECORD_FIELD_PAT => Pat::RecordFieldPat(RecordFieldPat { syntax }),
_ => return None, _ => return None,
}; };
Some(res) Some(res)
@ -3354,7 +3349,6 @@ impl AstNode for Pat {
Pat::RangePat(it) => &it.syntax, Pat::RangePat(it) => &it.syntax,
Pat::LiteralPat(it) => &it.syntax, Pat::LiteralPat(it) => &it.syntax,
Pat::MacroPat(it) => &it.syntax, Pat::MacroPat(it) => &it.syntax,
Pat::RecordFieldPat(it) => &it.syntax,
} }
} }
} }

View file

@ -741,7 +741,6 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
RangePat, RangePat,
LiteralPat, LiteralPat,
MacroPat, MacroPat,
RecordFieldPat,
} }
enum RecordInnerPat { enum RecordInnerPat {