]> git.lizzy.rs Git - rust.git/commitdiff
impl gen hash for structs
authorYoshua Wuyts <yoshuawuyts@gmail.com>
Tue, 10 Aug 2021 10:13:30 +0000 (12:13 +0200)
committerYoshua Wuyts <yoshuawuyts@gmail.com>
Tue, 10 Aug 2021 10:37:10 +0000 (12:37 +0200)
crates/ide/src/hover.rs
crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
crates/ide_assists/src/utils/gen_trait_fn_body.rs

index a9e2b52639448137c4689d65a091c3fe65a19a88..3a17035ae853e852a93a7e919080650f32ade0d7 100644 (file)
@@ -2732,8 +2732,8 @@ fn foo() {
                                     file_id: FileId(
                                         1,
                                     ),
-                                    full_range: 252..434,
-                                    focus_range: 291..297,
+                                    full_range: 253..435,
+                                    focus_range: 292..298,
                                     name: "Future",
                                     kind: Trait,
                                     description: "pub trait Future",
index 1cd9ab222c5fe31fef120be89f7ded0aa7510c34..bd0b2028a1a00d1dcf78b96f6025cb801f9ed67e 100644 (file)
@@ -370,6 +370,56 @@ impl Default for Foo {
         )
     }
 
+    #[test]
+    fn add_custom_impl_hash_record_struct() {
+        check_assist(
+            replace_derive_with_manual_impl,
+            r#"
+//- minicore: hash
+#[derive(Has$0h)]
+struct Foo {
+    bin: usize,
+    bar: usize,
+}
+"#,
+            r#"
+struct Foo {
+    bin: usize,
+    bar: usize,
+}
+
+impl core::hash::Hash for Foo {
+    $0fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
+        self.bin.hash(state);
+        self.bar.hash(state);
+    }
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn add_custom_impl_hash_tuple_struct() {
+        check_assist(
+            replace_derive_with_manual_impl,
+            r#"
+//- minicore: hash
+#[derive(Has$0h)]
+struct Foo(usize, usize);
+"#,
+            r#"
+struct Foo(usize, usize);
+
+impl core::hash::Hash for Foo {
+    $0fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
+        self.0.hash(state);
+        self.1.hash(state);
+    }
+}
+"#,
+        )
+    }
+
     #[test]
     fn add_custom_impl_hash_enum() {
         check_assist(
index 2908f62dd30dfb4dbdaed29ba3ec6d79e95e26bf..9ed8cbdbc735d318c763092f87499e9dd92f2ea5 100644 (file)
@@ -155,6 +155,14 @@ fn gen_default_call() -> ast::Expr {
 
 /// Generate a `Hash` impl based on the fields and members of the target type.
 fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
+    fn gen_hash_call(target: ast::Expr) -> ast::Stmt {
+        let method = make::name_ref("hash");
+        let arg = make::expr_path(make::ext::ident_path("state"));
+        let expr = make::expr_method_call(target, method, make::arg_list(Some(arg)));
+        let stmt = make::expr_stmt(expr);
+        stmt.into()
+    }
+
     let body = match adt {
         // `Hash` cannot be derived for unions, so no default impl can be provided.
         ast::Adt::Union(_) => return None,
@@ -169,29 +177,35 @@ fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
 
             let arg = make::expr_path(make::ext::ident_path("self"));
             let fn_call = make::expr_call(fn_name, make::arg_list(Some(arg)));
+            let stmt = gen_hash_call(fn_call);
 
-            let method = make::name_ref("hash");
-            let arg = make::expr_path(make::ext::ident_path("state"));
-            let expr = make::expr_method_call(fn_call, method, make::arg_list(Some(arg)));
-            let stmt = make::expr_stmt(expr);
-
-            make::block_expr(Some(stmt.into()), None).indent(ast::edit::IndentLevel(1))
+            make::block_expr(Some(stmt), None).indent(ast::edit::IndentLevel(1))
         }
         ast::Adt::Struct(strukt) => match strukt.field_list() {
             // => self.<field>.hash(state);*
             Some(ast::FieldList::RecordFieldList(field_list)) => {
-                // let mut stmts = vec![];
-                for field in field_list.fields() {}
-                todo!();
+                let mut stmts = vec![];
+                for field in field_list.fields() {
+                    let base = make::expr_path(make::ext::ident_path("self"));
+                    let target = make::expr_field(base, &field.name()?.to_string());
+                    stmts.push(gen_hash_call(target));
+                }
+                make::block_expr(stmts, None).indent(ast::edit::IndentLevel(1))
             }
 
             // => self.<field_index>.hash(state);*
             Some(ast::FieldList::TupleFieldList(field_list)) => {
-                todo!();
+                let mut stmts = vec![];
+                for (i, _) in field_list.fields().enumerate() {
+                    let base = make::expr_path(make::ext::ident_path("self"));
+                    let target = make::expr_field(base, &format!("{}", i));
+                    stmts.push(gen_hash_call(target));
+                }
+                make::block_expr(stmts, None).indent(ast::edit::IndentLevel(1))
             }
 
             // No fields in the body means there's nothing to hash.
-            None => make::ext::empty_block_expr(),
+            None => return None,
         },
     };