]> git.lizzy.rs Git - rust.git/commitdiff
Unite record completion logic into a single module
authorKirill Bulatov <mail4score@gmail.com>
Tue, 31 Mar 2020 21:50:45 +0000 (00:50 +0300)
committerKirill Bulatov <mail4score@gmail.com>
Wed, 1 Apr 2020 10:03:56 +0000 (13:03 +0300)
crates/ra_ide/src/completion.rs
crates/ra_ide/src/completion/complete_record.rs [new file with mode: 0644]
crates/ra_ide/src/completion/complete_record_literal.rs [deleted file]
crates/ra_ide/src/completion/complete_record_pattern.rs [deleted file]

index 67dfd6f2e6ab07ad14296cbc20e4d7f5c7f1665e..93157bbba63f4879e7a6dfef5fe6cbcb1b705194 100644 (file)
@@ -5,8 +5,7 @@
 mod presentation;
 
 mod complete_dot;
-mod complete_record_literal;
-mod complete_record_pattern;
+mod complete_record;
 mod complete_pattern;
 mod complete_fn_param;
 mod complete_keyword;
 pub use crate::completion::completion_item::{
     CompletionItem, CompletionItemKind, InsertTextFormat,
 };
-use either::Either;
-use hir::{StructField, Type};
-use ra_syntax::{
-    ast::{self, NameOwner},
-    SmolStr,
-};
 
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct CompletionConfig {
@@ -95,8 +88,7 @@ pub(crate) fn completions(
     complete_path::complete_path(&mut acc, &ctx);
     complete_scope::complete_scope(&mut acc, &ctx);
     complete_dot::complete_dot(&mut acc, &ctx);
-    complete_record_literal::complete_record_literal(&mut acc, &ctx);
-    complete_record_pattern::complete_record_pattern(&mut acc, &ctx);
+    complete_record::complete_record(&mut acc, &ctx);
     complete_pattern::complete_pattern(&mut acc, &ctx);
     complete_postfix::complete_postfix(&mut acc, &ctx);
     complete_macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx);
@@ -104,57 +96,3 @@ pub(crate) fn completions(
 
     Some(acc)
 }
-
-pub(crate) fn get_missing_fields(
-    ctx: &CompletionContext,
-    record: Either<&ast::RecordLit, &ast::RecordPat>,
-) -> Option<Vec<(StructField, Type)>> {
-    let (ty, variant) = match record {
-        Either::Left(record_lit) => (
-            ctx.sema.type_of_expr(&record_lit.clone().into())?,
-            ctx.sema.resolve_record_literal(record_lit)?,
-        ),
-        Either::Right(record_pat) => (
-            ctx.sema.type_of_pat(&record_pat.clone().into())?,
-            ctx.sema.resolve_record_pattern(record_pat)?,
-        ),
-    };
-
-    let already_present_names = get_already_present_names(record);
-    Some(
-        ty.variant_fields(ctx.db, variant)
-            .into_iter()
-            .filter(|(field, _)| {
-                !already_present_names.contains(&SmolStr::from(field.name(ctx.db).to_string()))
-            })
-            .collect(),
-    )
-}
-
-fn get_already_present_names(record: Either<&ast::RecordLit, &ast::RecordPat>) -> Vec<SmolStr> {
-    // TODO kb have a single match
-    match record {
-        Either::Left(record_lit) => record_lit
-            .record_field_list()
-            .map(|field_list| field_list.fields())
-            .map(|fields| {
-                fields
-                    .into_iter()
-                    .filter_map(|field| field.name_ref())
-                    .map(|name_ref| name_ref.text().clone())
-                    .collect()
-            })
-            .unwrap_or_default(),
-        Either::Right(record_pat) => record_pat
-            .record_field_pat_list()
-            .map(|pat_list| pat_list.bind_pats())
-            .map(|bind_pats| {
-                bind_pats
-                    .into_iter()
-                    .filter_map(|pat| pat.name())
-                    .map(|name| name.text().clone())
-                    .collect()
-            })
-            .unwrap_or_default(),
-    }
-}
diff --git a/crates/ra_ide/src/completion/complete_record.rs b/crates/ra_ide/src/completion/complete_record.rs
new file mode 100644 (file)
index 0000000..01dd8c6
--- /dev/null
@@ -0,0 +1,411 @@
+//! Complete fields in record literals and patterns.
+use crate::completion::{CompletionContext, Completions};
+use ra_syntax::{ast, ast::NameOwner, SmolStr};
+
+pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
+    let (ty, variant, already_present_fields) =
+        match (ctx.record_lit_pat.as_ref(), ctx.record_lit_syntax.as_ref()) {
+            (None, None) => return None,
+            (Some(_), Some(_)) => panic!("A record cannot be both a literal and a pattern"),
+            (Some(record_pat), _) => (
+                ctx.sema.type_of_pat(&record_pat.clone().into())?,
+                ctx.sema.resolve_record_pattern(record_pat)?,
+                pattern_ascribed_fields(record_pat),
+            ),
+            (_, Some(record_lit)) => (
+                ctx.sema.type_of_expr(&record_lit.clone().into())?,
+                ctx.sema.resolve_record_literal(record_lit)?,
+                literal_ascribed_fields(record_lit),
+            ),
+        };
+
+    for (field, field_ty) in ty.variant_fields(ctx.db, variant).into_iter().filter(|(field, _)| {
+        // FIXME: already_present_names better be `Vec<hir::Name>`
+        !already_present_fields.contains(&SmolStr::from(field.name(ctx.db).to_string()))
+    }) {
+        acc.add_field(ctx, field, &field_ty);
+    }
+    Some(())
+}
+
+fn literal_ascribed_fields(record_lit: &ast::RecordLit) -> Vec<SmolStr> {
+    record_lit
+        .record_field_list()
+        .map(|field_list| field_list.fields())
+        .map(|fields| {
+            fields
+                .into_iter()
+                .filter_map(|field| field.name_ref())
+                .map(|name_ref| name_ref.text().clone())
+                .collect()
+        })
+        .unwrap_or_default()
+}
+
+fn pattern_ascribed_fields(record_pat: &ast::RecordPat) -> Vec<SmolStr> {
+    record_pat
+        .record_field_pat_list()
+        .map(|pat_list| {
+            pat_list
+                .record_field_pats()
+                .filter_map(|fild_pat| fild_pat.name())
+                .chain(pat_list.bind_pats().filter_map(|bind_pat| bind_pat.name()))
+                .map(|name| name.text().clone())
+                .collect()
+        })
+        .unwrap_or_default()
+}
+
+#[cfg(test)]
+mod tests {
+    mod record_lit_tests {
+        use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind};
+        use insta::assert_debug_snapshot;
+
+        fn complete(code: &str) -> Vec<CompletionItem> {
+            do_completion(code, CompletionKind::Reference)
+        }
+
+        #[test]
+        fn test_record_pattern_field() {
+            let completions = complete(
+                r"
+            struct S { foo: u32 }
+
+            fn process(f: S) {
+                match f {
+                    S { f<|>: 92 } => (),
+                }
+            }
+            ",
+            );
+            assert_debug_snapshot!(completions, @r###"
+        [
+            CompletionItem {
+                label: "foo",
+                source_range: [117; 118),
+                delete: [117; 118),
+                insert: "foo",
+                kind: Field,
+                detail: "u32",
+            },
+        ]
+        "###);
+        }
+
+        #[test]
+        fn test_record_pattern_enum_variant() {
+            let completions = complete(
+                r"
+            enum E {
+                S { foo: u32, bar: () }
+            }
+
+            fn process(e: E) {
+                match e {
+                    E::S { <|> } => (),
+                }
+            }
+            ",
+            );
+            assert_debug_snapshot!(completions, @r###"
+        [
+            CompletionItem {
+                label: "bar",
+                source_range: [161; 161),
+                delete: [161; 161),
+                insert: "bar",
+                kind: Field,
+                detail: "()",
+            },
+            CompletionItem {
+                label: "foo",
+                source_range: [161; 161),
+                delete: [161; 161),
+                insert: "foo",
+                kind: Field,
+                detail: "u32",
+            },
+        ]
+        "###);
+        }
+
+        #[test]
+        fn test_record_pattern_field_in_simple_macro() {
+            let completions = complete(
+                r"
+            macro_rules! m { ($e:expr) => { $e } }
+            struct S { foo: u32 }
+
+            fn process(f: S) {
+                m!(match f {
+                    S { f<|>: 92 } => (),
+                })
+            }
+            ",
+            );
+            assert_debug_snapshot!(completions, @r###"
+        [
+            CompletionItem {
+                label: "foo",
+                source_range: [171; 172),
+                delete: [171; 172),
+                insert: "foo",
+                kind: Field,
+                detail: "u32",
+            },
+        ]
+        "###);
+        }
+
+        #[test]
+        fn only_missing_fields_are_completed_in_destruct_pats() {
+            let completions = complete(
+                r"
+            struct S {
+                foo1: u32,
+                foo2: u32,
+                bar: u32,
+                baz: u32,
+            }
+
+            fn main() {
+                let s = S {
+                    foo1: 1,
+                    foo2: 2,
+                    bar: 3,
+                    baz: 4,
+                };
+                if let S { foo1, foo2: a, <|> } = s {}
+            }
+            ",
+            );
+            assert_debug_snapshot!(completions, @r###"
+        [
+            CompletionItem {
+                label: "bar",
+                source_range: [372; 372),
+                delete: [372; 372),
+                insert: "bar",
+                kind: Field,
+                detail: "u32",
+            },
+            CompletionItem {
+                label: "baz",
+                source_range: [372; 372),
+                delete: [372; 372),
+                insert: "baz",
+                kind: Field,
+                detail: "u32",
+            },
+        ]
+        "###);
+        }
+    }
+
+    mod record_pat_tests {
+        use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind};
+        use insta::assert_debug_snapshot;
+
+        fn complete(code: &str) -> Vec<CompletionItem> {
+            do_completion(code, CompletionKind::Reference)
+        }
+
+        #[test]
+        fn test_record_literal_deprecated_field() {
+            let completions = complete(
+                r"
+            struct A {
+                #[deprecated]
+                the_field: u32,
+            }
+            fn foo() {
+               A { the<|> }
+            }
+            ",
+            );
+            assert_debug_snapshot!(completions, @r###"
+        [
+            CompletionItem {
+                label: "the_field",
+                source_range: [142; 145),
+                delete: [142; 145),
+                insert: "the_field",
+                kind: Field,
+                detail: "u32",
+                deprecated: true,
+            },
+        ]
+        "###);
+        }
+
+        #[test]
+        fn test_record_literal_field() {
+            let completions = complete(
+                r"
+            struct A { the_field: u32 }
+            fn foo() {
+               A { the<|> }
+            }
+            ",
+            );
+            assert_debug_snapshot!(completions, @r###"
+        [
+            CompletionItem {
+                label: "the_field",
+                source_range: [83; 86),
+                delete: [83; 86),
+                insert: "the_field",
+                kind: Field,
+                detail: "u32",
+            },
+        ]
+        "###);
+        }
+
+        #[test]
+        fn test_record_literal_enum_variant() {
+            let completions = complete(
+                r"
+            enum E {
+                A { a: u32 }
+            }
+            fn foo() {
+                let _ = E::A { <|> }
+            }
+            ",
+            );
+            assert_debug_snapshot!(completions, @r###"
+        [
+            CompletionItem {
+                label: "a",
+                source_range: [119; 119),
+                delete: [119; 119),
+                insert: "a",
+                kind: Field,
+                detail: "u32",
+            },
+        ]
+        "###);
+        }
+
+        #[test]
+        fn test_record_literal_two_structs() {
+            let completions = complete(
+                r"
+            struct A { a: u32 }
+            struct B { b: u32 }
+
+            fn foo() {
+               let _: A = B { <|> }
+            }
+            ",
+            );
+            assert_debug_snapshot!(completions, @r###"
+        [
+            CompletionItem {
+                label: "b",
+                source_range: [119; 119),
+                delete: [119; 119),
+                insert: "b",
+                kind: Field,
+                detail: "u32",
+            },
+        ]
+        "###);
+        }
+
+        #[test]
+        fn test_record_literal_generic_struct() {
+            let completions = complete(
+                r"
+            struct A<T> { a: T }
+
+            fn foo() {
+               let _: A<u32> = A { <|> }
+            }
+            ",
+            );
+            assert_debug_snapshot!(completions, @r###"
+        [
+            CompletionItem {
+                label: "a",
+                source_range: [93; 93),
+                delete: [93; 93),
+                insert: "a",
+                kind: Field,
+                detail: "u32",
+            },
+        ]
+        "###);
+        }
+
+        #[test]
+        fn test_record_literal_field_in_simple_macro() {
+            let completions = complete(
+                r"
+            macro_rules! m { ($e:expr) => { $e } }
+            struct A { the_field: u32 }
+            fn foo() {
+               m!(A { the<|> })
+            }
+            ",
+            );
+            assert_debug_snapshot!(completions, @r###"
+        [
+            CompletionItem {
+                label: "the_field",
+                source_range: [137; 140),
+                delete: [137; 140),
+                insert: "the_field",
+                kind: Field,
+                detail: "u32",
+            },
+        ]
+        "###);
+        }
+
+        #[test]
+        fn only_missing_fields_are_completed() {
+            let completions = complete(
+                r"
+            struct S {
+                foo1: u32,
+                foo2: u32,
+                bar: u32,
+                baz: u32,
+            }
+
+            fn main() {
+                let foo1 = 1;
+                let s = S {
+                    foo1,
+                    foo2: 5,
+                    <|>
+                }
+            }
+            ",
+            );
+            assert_debug_snapshot!(completions, @r###"
+        [
+            CompletionItem {
+                label: "bar",
+                source_range: [302; 302),
+                delete: [302; 302),
+                insert: "bar",
+                kind: Field,
+                detail: "u32",
+            },
+            CompletionItem {
+                label: "baz",
+                source_range: [302; 302),
+                delete: [302; 302),
+                insert: "baz",
+                kind: Field,
+                detail: "u32",
+            },
+        ]
+        "###);
+        }
+    }
+}
diff --git a/crates/ra_ide/src/completion/complete_record_literal.rs b/crates/ra_ide/src/completion/complete_record_literal.rs
deleted file mode 100644 (file)
index 8b67d3b..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-//! FIXME: write short doc here
-
-use super::get_missing_fields;
-use crate::completion::{CompletionContext, Completions};
-use either::Either;
-
-/// Complete fields in fields literals.
-pub(super) fn complete_record_literal(
-    acc: &mut Completions,
-    ctx: &CompletionContext,
-) -> Option<()> {
-    let record_lit = ctx.record_lit_syntax.as_ref()?;
-    for (field, field_ty) in get_missing_fields(ctx, Either::Left(record_lit))? {
-        acc.add_field(ctx, field, &field_ty);
-    }
-    Some(())
-}
-
-#[cfg(test)]
-mod tests {
-    use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind};
-    use insta::assert_debug_snapshot;
-
-    fn complete(code: &str) -> Vec<CompletionItem> {
-        do_completion(code, CompletionKind::Reference)
-    }
-
-    #[test]
-    fn test_record_literal_deprecated_field() {
-        let completions = complete(
-            r"
-            struct A {
-                #[deprecated]
-                the_field: u32,
-            }
-            fn foo() {
-               A { the<|> }
-            }
-            ",
-        );
-        assert_debug_snapshot!(completions, @r###"
-        [
-            CompletionItem {
-                label: "the_field",
-                source_range: [142; 145),
-                delete: [142; 145),
-                insert: "the_field",
-                kind: Field,
-                detail: "u32",
-                deprecated: true,
-            },
-        ]
-        "###);
-    }
-
-    #[test]
-    fn test_record_literal_field() {
-        let completions = complete(
-            r"
-            struct A { the_field: u32 }
-            fn foo() {
-               A { the<|> }
-            }
-            ",
-        );
-        assert_debug_snapshot!(completions, @r###"
-        [
-            CompletionItem {
-                label: "the_field",
-                source_range: [83; 86),
-                delete: [83; 86),
-                insert: "the_field",
-                kind: Field,
-                detail: "u32",
-            },
-        ]
-        "###);
-    }
-
-    #[test]
-    fn test_record_literal_enum_variant() {
-        let completions = complete(
-            r"
-            enum E {
-                A { a: u32 }
-            }
-            fn foo() {
-                let _ = E::A { <|> }
-            }
-            ",
-        );
-        assert_debug_snapshot!(completions, @r###"
-        [
-            CompletionItem {
-                label: "a",
-                source_range: [119; 119),
-                delete: [119; 119),
-                insert: "a",
-                kind: Field,
-                detail: "u32",
-            },
-        ]
-        "###);
-    }
-
-    #[test]
-    fn test_record_literal_two_structs() {
-        let completions = complete(
-            r"
-            struct A { a: u32 }
-            struct B { b: u32 }
-
-            fn foo() {
-               let _: A = B { <|> }
-            }
-            ",
-        );
-        assert_debug_snapshot!(completions, @r###"
-        [
-            CompletionItem {
-                label: "b",
-                source_range: [119; 119),
-                delete: [119; 119),
-                insert: "b",
-                kind: Field,
-                detail: "u32",
-            },
-        ]
-        "###);
-    }
-
-    #[test]
-    fn test_record_literal_generic_struct() {
-        let completions = complete(
-            r"
-            struct A<T> { a: T }
-
-            fn foo() {
-               let _: A<u32> = A { <|> }
-            }
-            ",
-        );
-        assert_debug_snapshot!(completions, @r###"
-        [
-            CompletionItem {
-                label: "a",
-                source_range: [93; 93),
-                delete: [93; 93),
-                insert: "a",
-                kind: Field,
-                detail: "u32",
-            },
-        ]
-        "###);
-    }
-
-    #[test]
-    fn test_record_literal_field_in_simple_macro() {
-        let completions = complete(
-            r"
-            macro_rules! m { ($e:expr) => { $e } }
-            struct A { the_field: u32 }
-            fn foo() {
-               m!(A { the<|> })
-            }
-            ",
-        );
-        assert_debug_snapshot!(completions, @r###"
-        [
-            CompletionItem {
-                label: "the_field",
-                source_range: [137; 140),
-                delete: [137; 140),
-                insert: "the_field",
-                kind: Field,
-                detail: "u32",
-            },
-        ]
-        "###);
-    }
-
-    #[test]
-    fn only_missing_fields_are_completed() {
-        let completions = complete(
-            r"
-            struct S {
-                foo1: u32,
-                foo2: u32,
-                bar: u32,
-                baz: u32,
-            }
-
-            fn main() {
-                let foo1 = 1;
-                let s = S {
-                    foo1,
-                    foo2: 5,
-                    <|>
-                }
-            }
-            ",
-        );
-        assert_debug_snapshot!(completions, @r###"
-        [
-            CompletionItem {
-                label: "bar",
-                source_range: [302; 302),
-                delete: [302; 302),
-                insert: "bar",
-                kind: Field,
-                detail: "u32",
-            },
-            CompletionItem {
-                label: "baz",
-                source_range: [302; 302),
-                delete: [302; 302),
-                insert: "baz",
-                kind: Field,
-                detail: "u32",
-            },
-        ]
-        "###);
-    }
-}
diff --git a/crates/ra_ide/src/completion/complete_record_pattern.rs b/crates/ra_ide/src/completion/complete_record_pattern.rs
deleted file mode 100644 (file)
index f94dced..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-//! FIXME: write short doc here
-
-use super::get_missing_fields;
-use crate::completion::{CompletionContext, Completions};
-use either::Either;
-
-pub(super) fn complete_record_pattern(
-    acc: &mut Completions,
-    ctx: &CompletionContext,
-) -> Option<()> {
-    let record_pat = ctx.record_lit_pat.as_ref()?;
-    for (field, field_ty) in get_missing_fields(ctx, Either::Right(record_pat))? {
-        acc.add_field(ctx, field, &field_ty);
-    }
-    Some(())
-}
-
-#[cfg(test)]
-mod tests {
-    use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind};
-    use insta::assert_debug_snapshot;
-
-    fn complete(code: &str) -> Vec<CompletionItem> {
-        do_completion(code, CompletionKind::Reference)
-    }
-
-    #[test]
-    fn test_record_pattern_field() {
-        let completions = complete(
-            r"
-            struct S { foo: u32 }
-
-            fn process(f: S) {
-                match f {
-                    S { f<|>: 92 } => (),
-                }
-            }
-            ",
-        );
-        assert_debug_snapshot!(completions, @r###"
-        [
-            CompletionItem {
-                label: "foo",
-                source_range: [117; 118),
-                delete: [117; 118),
-                insert: "foo",
-                kind: Field,
-                detail: "u32",
-            },
-        ]
-        "###);
-    }
-
-    #[test]
-    fn test_record_pattern_enum_variant() {
-        let completions = complete(
-            r"
-            enum E {
-                S { foo: u32, bar: () }
-            }
-
-            fn process(e: E) {
-                match e {
-                    E::S { <|> } => (),
-                }
-            }
-            ",
-        );
-        assert_debug_snapshot!(completions, @r###"
-        [
-            CompletionItem {
-                label: "bar",
-                source_range: [161; 161),
-                delete: [161; 161),
-                insert: "bar",
-                kind: Field,
-                detail: "()",
-            },
-            CompletionItem {
-                label: "foo",
-                source_range: [161; 161),
-                delete: [161; 161),
-                insert: "foo",
-                kind: Field,
-                detail: "u32",
-            },
-        ]
-        "###);
-    }
-
-    #[test]
-    fn test_record_pattern_field_in_simple_macro() {
-        let completions = complete(
-            r"
-            macro_rules! m { ($e:expr) => { $e } }
-            struct S { foo: u32 }
-
-            fn process(f: S) {
-                m!(match f {
-                    S { f<|>: 92 } => (),
-                })
-            }
-            ",
-        );
-        assert_debug_snapshot!(completions, @r###"
-        [
-            CompletionItem {
-                label: "foo",
-                source_range: [171; 172),
-                delete: [171; 172),
-                insert: "foo",
-                kind: Field,
-                detail: "u32",
-            },
-        ]
-        "###);
-    }
-
-    #[test]
-    fn only_missing_fields_are_completed_in_destruct_pats() {
-        let completions = complete(
-            r"
-            struct S {
-                foo1: u32,
-                foo2: u32,
-                bar: u32,
-                baz: u32,
-            }
-
-            fn main() {
-                let s = S {
-                    foo1: 1,
-                    foo2: 2,
-                    bar: 3,
-                    baz: 4,
-                };
-                if let S { foo1, foo2: a, <|> } = s {}
-            }
-            ",
-        );
-        assert_debug_snapshot!(completions, @r###"
-        [
-            CompletionItem {
-                label: "bar",
-                source_range: [372; 372),
-                delete: [372; 372),
-                insert: "bar",
-                kind: Field,
-                detail: "u32",
-            },
-            CompletionItem {
-                label: "baz",
-                source_range: [372; 372),
-                delete: [372; 372),
-                insert: "baz",
-                kind: Field,
-                detail: "u32",
-            },
-        ]
-        "###);
-    }
-}