Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 13 additions & 19 deletions crates/ra_assists/src/handlers/reorder_fields.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
use std::collections::HashMap;

use itertools::Itertools;

use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct};
use itertools::Itertools;
use ra_ide_db::RootDatabase;
use ra_syntax::{
algo, ast,
ast::{Name, Path, RecordLit, RecordPat},
AstNode, SyntaxKind, SyntaxNode,
algo,
ast::{self, Path, RecordLit, RecordPat},
match_ast, AstNode, SyntaxKind,
SyntaxKind::*,
SyntaxNode,
};

use crate::{
assist_ctx::{Assist, AssistCtx},
AssistId,
};
use ra_syntax::ast::{Expr, NameRef};

// Assist: reorder_fields
//
Expand Down Expand Up @@ -59,7 +59,6 @@ fn reorder<R: AstNode>(ctx: AssistCtx) -> Option<Assist> {
}

fn get_fields_kind(node: &SyntaxNode) -> Vec<SyntaxKind> {
use SyntaxKind::*;
match node.kind() {
RECORD_LIT => vec![RECORD_FIELD],
RECORD_PAT => vec![RECORD_FIELD_PAT, BIND_PAT],
Expand All @@ -68,19 +67,14 @@ fn get_fields_kind(node: &SyntaxNode) -> Vec<SyntaxKind> {
}

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()
let res = match_ast! {
match node {
ast::RecordField(field) => { field.field_name().map(|it| it.to_string()) },
ast::RecordFieldPat(field) => { field.field_name().map(|it| it.to_string()) },
_ => None,
}
_ => String::new(),
}
};
res.unwrap_or_default()
}

fn get_fields(record: &SyntaxNode) -> Vec<SyntaxNode> {
Expand Down
2 changes: 1 addition & 1 deletion crates/ra_hir_def/src/body/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ impl ExprCollector<'_> {
let iter = record_field_pat_list.record_field_pats().filter_map(|f| {
let ast_pat = f.pat()?;
let pat = self.collect_pat(ast_pat);
let name = f.name()?.as_name();
let name = f.field_name()?.as_name();
Some(RecordFieldPat { name, pat })
});
fields.extend(iter);
Expand Down
9 changes: 9 additions & 0 deletions crates/ra_hir_expand/src/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ impl AsName for ast::Name {
}
}

impl AsName for ast::NameOrNameRef {
fn as_name(&self) -> Name {
match self {
ast::NameOrNameRef::Name(it) => it.as_name(),
ast::NameOrNameRef::NameRef(it) => it.as_name(),
}
}
}

impl AsName for tt::Ident {
fn as_name(&self) -> Name {
Name::resolve(&self.text)
Expand Down
3 changes: 2 additions & 1 deletion crates/ra_hir_ty/src/tests/patterns.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use super::{infer, infer_with_mismatches};
use insta::assert_snapshot;
use test_utils::covers;

use super::{infer, infer_with_mismatches};

#[test]
fn infer_pattern() {
assert_snapshot!(
Expand Down
4 changes: 4 additions & 0 deletions crates/ra_ide/src/completion/complete_pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
if !ctx.is_pat_binding_or_const {
return;
}
if ctx.record_pat_syntax.is_some() {
return;
}

// FIXME: ideally, we should look at the type we are matching against and
// suggest variants + auto-imports
ctx.scope().process_all_names(&mut |name, res| {
Expand Down
2 changes: 1 addition & 1 deletion crates/ra_ide/src/completion/complete_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use crate::completion::{CompletionContext, Completions};

pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
let missing_fields = match (ctx.record_lit_pat.as_ref(), ctx.record_lit_syntax.as_ref()) {
let missing_fields = match (ctx.record_pat_syntax.as_ref(), ctx.record_lit_syntax.as_ref()) {
(None, None) => return None,
(Some(_), Some(_)) => unreachable!("A record cannot be both a literal and a pattern"),
(Some(record_pat), _) => ctx.sema.record_pattern_missing_fields(record_pat),
Expand Down
9 changes: 8 additions & 1 deletion crates/ra_ide/src/completion/complete_unqualified_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@
use crate::completion::{CompletionContext, Completions};

pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
if !(ctx.is_trivial_path && !ctx.is_pat_binding_or_const && !ctx.record_lit_syntax.is_some()) {
if !ctx.is_trivial_path {
return;
}

if ctx.is_pat_binding_or_const
|| ctx.record_lit_syntax.is_some()
|| ctx.record_pat_syntax.is_some()
{
return;
}

Expand Down
12 changes: 9 additions & 3 deletions crates/ra_ide/src/completion/completion_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub(crate) struct CompletionContext<'a> {
pub(super) function_syntax: Option<ast::FnDef>,
pub(super) use_item_syntax: Option<ast::UseItem>,
pub(super) record_lit_syntax: Option<ast::RecordLit>,
pub(super) record_lit_pat: Option<ast::RecordPat>,
pub(super) record_pat_syntax: Option<ast::RecordPat>,
pub(super) impl_def: Option<ast::ImplDef>,
pub(super) is_param: bool,
/// If a name-binding or reference to a const in a pattern.
Expand Down Expand Up @@ -93,7 +93,7 @@ impl<'a> CompletionContext<'a> {
function_syntax: None,
use_item_syntax: None,
record_lit_syntax: None,
record_lit_pat: None,
record_pat_syntax: None,
impl_def: None,
is_param: false,
is_pat_binding_or_const: false,
Expand Down Expand Up @@ -182,6 +182,11 @@ impl<'a> CompletionContext<'a> {
self.is_param = true;
return;
}
// FIXME: remove this (V) duplication and make the check more precise
if name_ref.syntax().ancestors().find_map(ast::RecordFieldPatList::cast).is_some() {
self.record_pat_syntax =
self.sema.find_node_at_offset_with_macros(&original_file, offset);
}
self.classify_name_ref(original_file, name_ref, offset);
}

Expand Down Expand Up @@ -211,8 +216,9 @@ impl<'a> CompletionContext<'a> {
self.is_param = true;
return;
}
// FIXME: remove this (^) duplication and make the check more precise
if name.syntax().ancestors().find_map(ast::RecordFieldPatList::cast).is_some() {
self.record_lit_pat =
self.record_pat_syntax =
self.sema.find_node_at_offset_with_macros(&original_file, offset);
}
}
Expand Down
11 changes: 4 additions & 7 deletions crates/ra_parser/src/grammar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,13 +282,10 @@ fn name_ref(p: &mut Parser) {
}

fn name_ref_or_index(p: &mut Parser) {
if p.at(IDENT) || p.at(INT_NUMBER) {
let m = p.start();
p.bump_any();
m.complete(p, NAME_REF);
} else {
p.err_and_bump("expected identifier");
}
assert!(p.at(IDENT) || p.at(INT_NUMBER));
let m = p.start();
p.bump_any();
m.complete(p, NAME_REF);
}

fn error_block(p: &mut Parser, message: &str) {
Expand Down
50 changes: 23 additions & 27 deletions crates/ra_parser/src/grammar/patterns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,14 +192,30 @@ fn record_field_pat_list(p: &mut Parser) {
match p.current() {
// A trailing `..` is *not* treated as a DOT_DOT_PAT.
T![.] if p.at(T![..]) => p.bump(T![..]),

IDENT | INT_NUMBER if p.nth(1) == T![:] => record_field_pat(p),
T!['{'] => error_block(p, "expected ident"),
T![box] => {
box_pat(p);
}
_ => {
bind_pat(p, false);

c => {
let m = p.start();
match c {
// test record_field_pat
// fn foo() {
// let S { 0: 1 } = ();
// let S { x: 1 } = ();
// }
IDENT | INT_NUMBER if p.nth(1) == T![:] => {
name_ref_or_index(p);
p.bump(T![:]);
pattern(p);
}
T![box] => {
// FIXME: not all box patterns should be allowed
box_pat(p);
}
_ => {
bind_pat(p, false);
}
}
m.complete(p, RECORD_FIELD_PAT);
}
}
if !p.at(T!['}']) {
Expand All @@ -210,26 +226,6 @@ fn record_field_pat_list(p: &mut Parser) {
m.complete(p, RECORD_FIELD_PAT_LIST);
}

// test record_field_pat
// fn foo() {
// let S { 0: 1 } = ();
// let S { x: 1 } = ();
// }
fn record_field_pat(p: &mut Parser) {
assert!(p.at(IDENT) || p.at(INT_NUMBER));
assert!(p.nth(1) == T![:]);

let m = p.start();

if !p.eat(INT_NUMBER) {
name(p)
}

p.bump_any();
pattern(p);
m.complete(p, RECORD_FIELD_PAT);
}

// test placeholder_pat
// fn main() { let _ = (); }
fn placeholder_pat(p: &mut Parser) -> CompletedMarker {
Expand Down
4 changes: 2 additions & 2 deletions crates/ra_syntax/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ use crate::{
pub use self::{
expr_extensions::{ArrayExprKind, BinOp, ElseBranch, LiteralKind, PrefixOp, RangeOp},
extensions::{
AttrKind, FieldKind, PathSegmentKind, SelfParamKind, SlicePatComponents, StructKind,
TypeBoundKind, VisibilityKind,
AttrKind, FieldKind, NameOrNameRef, PathSegmentKind, SelfParamKind, SlicePatComponents,
StructKind, TypeBoundKind, VisibilityKind,
},
generated::{nodes::*, tokens::*},
tokens::*,
Expand Down
30 changes: 30 additions & 0 deletions crates/ra_syntax/src/ast/extensions.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Various extension methods to ast Nodes, which are hard to code-generate.
//! Extensions for various expressions live in a sibling `expr_extensions` module.

use std::fmt;

use itertools::Itertools;
use ra_parser::SyntaxKind;

Expand Down Expand Up @@ -217,6 +219,34 @@ impl ast::RecordField {
}
}

pub enum NameOrNameRef {
Name(ast::Name),
NameRef(ast::NameRef),
}

impl fmt::Display for NameOrNameRef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
NameOrNameRef::Name(it) => fmt::Display::fmt(it, f),
NameOrNameRef::NameRef(it) => fmt::Display::fmt(it, f),
}
}
}

impl ast::RecordFieldPat {
/// Deals with field init shorthand
pub fn field_name(&self) -> Option<NameOrNameRef> {
if let Some(name_ref) = self.name_ref() {
return Some(NameOrNameRef::NameRef(name_ref));
}
if let Some(ast::Pat::BindPat(pat)) = self.pat() {
let name = pat.name()?;
return Some(NameOrNameRef::Name(name));
}
None
}
}

impl ast::EnumVariant {
pub fn parent_enum(&self) -> ast::EnumDef {
self.syntax()
Expand Down
2 changes: 1 addition & 1 deletion crates/ra_syntax/src/ast/generated/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1806,8 +1806,8 @@ impl AstNode for RecordFieldPat {
fn syntax(&self) -> &SyntaxNode { &self.syntax }
}
impl ast::AttrsOwner for RecordFieldPat {}
impl ast::NameOwner for RecordFieldPat {}
impl RecordFieldPat {
pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,20 @@ SOURCE_FILE@[0; 119)
RECORD_FIELD_PAT_LIST@[40; 56)
L_CURLY@[40; 41) "{"
WHITESPACE@[41; 42) " "
BIND_PAT@[42; 43)
NAME@[42; 43)
IDENT@[42; 43) "f"
RECORD_FIELD_PAT@[42; 43)
BIND_PAT@[42; 43)
NAME@[42; 43)
IDENT@[42; 43) "f"
COMMA@[43; 44) ","
WHITESPACE@[44; 45) " "
BIND_PAT@[45; 54)
REF_KW@[45; 48) "ref"
WHITESPACE@[48; 49) " "
MUT_KW@[49; 52) "mut"
WHITESPACE@[52; 53) " "
NAME@[53; 54)
IDENT@[53; 54) "g"
RECORD_FIELD_PAT@[45; 54)
BIND_PAT@[45; 54)
REF_KW@[45; 48) "ref"
WHITESPACE@[48; 49) " "
MUT_KW@[49; 52) "mut"
WHITESPACE@[52; 53) " "
NAME@[53; 54)
IDENT@[53; 54) "g"
WHITESPACE@[54; 55) " "
R_CURLY@[55; 56) "}"
WHITESPACE@[56; 57) " "
Expand All @@ -79,7 +81,7 @@ SOURCE_FILE@[0; 119)
L_CURLY@[73; 74) "{"
WHITESPACE@[74; 75) " "
RECORD_FIELD_PAT@[75; 79)
NAME@[75; 76)
NAME_REF@[75; 76)
IDENT@[75; 76) "h"
COLON@[76; 77) ":"
WHITESPACE@[77; 78) " "
Expand Down Expand Up @@ -110,7 +112,7 @@ SOURCE_FILE@[0; 119)
L_CURLY@[101; 102) "{"
WHITESPACE@[102; 103) " "
RECORD_FIELD_PAT@[103; 107)
NAME@[103; 104)
NAME_REF@[103; 104)
IDENT@[103; 104) "h"
COLON@[104; 105) ":"
WHITESPACE@[105; 106) " "
Expand Down
15 changes: 8 additions & 7 deletions crates/ra_syntax/test_data/parser/inline/ok/0143_box_pat.rast
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,17 @@ SOURCE_FILE@[0; 118)
RECORD_FIELD_PAT_LIST@[50; 81)
L_CURLY@[50; 51) "{"
WHITESPACE@[51; 52) " "
BOX_PAT@[52; 57)
BOX_KW@[52; 55) "box"
WHITESPACE@[55; 56) " "
BIND_PAT@[56; 57)
NAME@[56; 57)
IDENT@[56; 57) "i"
RECORD_FIELD_PAT@[52; 57)
BOX_PAT@[52; 57)
BOX_KW@[52; 55) "box"
WHITESPACE@[55; 56) " "
BIND_PAT@[56; 57)
NAME@[56; 57)
IDENT@[56; 57) "i"
COMMA@[57; 58) ","
WHITESPACE@[58; 59) " "
RECORD_FIELD_PAT@[59; 79)
NAME@[59; 60)
NAME_REF@[59; 60)
IDENT@[59; 60) "j"
COLON@[60; 61) ":"
WHITESPACE@[61; 62) " "
Expand Down
Loading