Repository: rust-analyzer/rust-analyzer
Pull request #3935 (2020-04-10 20:57:04)

Change missing impl assist to use todo!() instead of unimplemented()
todo!() "Indicates unfinished code" (https://doc.rust-lang.org/std/macro.todo.html)

Rust documentation provides further clarification:

> The difference between unimplemented! and todo! is that while todo!
> conveys an intent of implementing the functionality later and the
> message is "not yet implemented", unimplemented! makes no such claims.

todo!() seems more appropriate for assists that insert missing impls.


Patch:
diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs
index 722f207e24..2d6d44980e 100644
--- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs
@@ -40,7 +40,7 @@ enum AddMissingImplMembersMode {
 // }
 //
 // impl Trait<u32> for () {
-//     fn foo(&self) -> u32 { unimplemented!() }
+//     fn foo(&self) -> u32 { todo!() }
 //
 // }
 // ```
@@ -165,7 +165,7 @@ fn add_missing_impl_members_inner(
 
 fn add_body(fn_def: ast::FnDef) -> ast::FnDef {
     if fn_def.body().is_none() {
-        fn_def.with_body(make::block_from_expr(make::expr_unimplemented()))
+        fn_def.with_body(make::block_from_expr(make::expr_todo()))
     } else {
         fn_def
     }
@@ -215,8 +215,8 @@ impl Foo for S {
     fn bar(&self) {}
     <|>type Output;
     const CONST: usize = 42;
-    fn foo(&self) { unimplemented!() }
-    fn baz(&self) { unimplemented!() }
+    fn foo(&self) { todo!() }
+    fn baz(&self) { todo!() }
 
 }",
         );
@@ -250,7 +250,7 @@ struct S;
 
 impl Foo for S {
     fn bar(&self) {}
-    <|>fn foo(&self) { unimplemented!() }
+    <|>fn foo(&self) { todo!() }
 
 }",
         );
@@ -268,7 +268,7 @@ impl Foo for S { <|> }",
 trait Foo { fn foo(&self); }
 struct S;
 impl Foo for S {
-    <|>fn foo(&self) { unimplemented!() }
+    <|>fn foo(&self) { todo!() }
 }",
         );
     }
@@ -285,7 +285,7 @@ impl Foo<u32> for S { <|> }",
 trait Foo<T> { fn foo(&self, t: T) -> &T; }
 struct S;
 impl Foo<u32> for S {
-    <|>fn foo(&self, t: u32) -> &u32 { unimplemented!() }
+    <|>fn foo(&self, t: u32) -> &u32 { todo!() }
 }",
         );
     }
@@ -302,7 +302,7 @@ impl<U> Foo<U> for S { <|> }",
 trait Foo<T> { fn foo(&self, t: T) -> &T; }
 struct S;
 impl<U> Foo<U> for S {
-    <|>fn foo(&self, t: U) -> &U { unimplemented!() }
+    <|>fn foo(&self, t: U) -> &U { todo!() }
 }",
         );
     }
@@ -319,7 +319,7 @@ impl Foo for S {}<|>",
 trait Foo { fn foo(&self); }
 struct S;
 impl Foo for S {
-    <|>fn foo(&self) { unimplemented!() }
+    <|>fn foo(&self) { todo!() }
 }",
         )
     }
@@ -342,7 +342,7 @@ mod foo {
 }
 struct S;
 impl foo::Foo for S {
-    <|>fn foo(&self, bar: foo::Bar) { unimplemented!() }
+    <|>fn foo(&self, bar: foo::Bar) { todo!() }
 }",
         );
     }
@@ -365,7 +365,7 @@ mod foo {
 }
 struct S;
 impl foo::Foo for S {
-    <|>fn foo(&self, bar: foo::Bar<u32>) { unimplemented!() }
+    <|>fn foo(&self, bar: foo::Bar<u32>) { todo!() }
 }",
         );
     }
@@ -388,7 +388,7 @@ mod foo {
 }
 struct S;
 impl foo::Foo<u32> for S {
-    <|>fn foo(&self, bar: foo::Bar<u32>) { unimplemented!() }
+    <|>fn foo(&self, bar: foo::Bar<u32>) { todo!() }
 }",
         );
     }
@@ -414,7 +414,7 @@ mod foo {
 struct Param;
 struct S;
 impl foo::Foo<Param> for S {
-    <|>fn foo(&self, bar: Param) { unimplemented!() }
+    <|>fn foo(&self, bar: Param) { todo!() }
 }",
         );
     }
@@ -439,7 +439,7 @@ mod foo {
 }
 struct S;
 impl foo::Foo for S {
-    <|>fn foo(&self, bar: foo::Bar<u32>::Assoc) { unimplemented!() }
+    <|>fn foo(&self, bar: foo::Bar<u32>::Assoc) { todo!() }
 }",
         );
     }
@@ -464,7 +464,7 @@ mod foo {
 }
 struct S;
 impl foo::Foo for S {
-    <|>fn foo(&self, bar: foo::Bar<foo::Baz>) { unimplemented!() }
+    <|>fn foo(&self, bar: foo::Bar<foo::Baz>) { todo!() }
 }",
         );
     }
@@ -487,7 +487,7 @@ mod foo {
 }
 struct S;
 impl foo::Foo for S {
-    <|>fn foo(&self, bar: dyn Fn(u32) -> i32) { unimplemented!() }
+    <|>fn foo(&self, bar: dyn Fn(u32) -> i32) { todo!() }
 }",
         );
     }
@@ -544,7 +544,7 @@ trait Foo {
 struct S;
 impl Foo for S {
     <|>type Output;
-    fn foo(&self) { unimplemented!() }
+    fn foo(&self) { todo!() }
 }"#,
         )
     }
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs
index f39559e9ea..0f4a50be47 100644
--- a/crates/ra_syntax/src/ast/make.rs
+++ b/crates/ra_syntax/src/ast/make.rs
@@ -100,6 +100,9 @@ pub fn expr_empty_block() -> ast::Expr {
 pub fn expr_unimplemented() -> ast::Expr {
     expr_from_text("unimplemented!()")
 }
+pub fn expr_todo() -> ast::Expr {
+    expr_from_text("todo!()")
+}
 pub fn expr_path(path: ast::Path) -> ast::Expr {
     expr_from_text(&path.to_string())
 }
diff --git a/docs/user/assists.md b/docs/user/assists.md
index 754131f6fe..cc42169d8e 100644
--- a/docs/user/assists.md
+++ b/docs/user/assists.md
@@ -175,7 +175,7 @@ trait Trait<T> {
 }
 
 impl Trait<u32> for () {
-    fn foo(&self) -> u32 { unimplemented!() }
+    fn foo(&self) -> u32 { todo!() }
 
 }
 ```


Test patch:
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs
index 64444ee3aa..24392836c0 100644
--- a/crates/ra_assists/src/doc_tests/generated.rs
+++ b/crates/ra_assists/src/doc_tests/generated.rs
@@ -180,7 +180,7 @@ trait Trait<T> {
 }
 
 impl Trait<u32> for () {
-    fn foo(&self) -> u32 { unimplemented!() }
+    fn foo(&self) -> u32 { todo!() }
 
 }
 "#####,
diff --git a/xtask/tests/tidy-tests/main.rs b/xtask/tests/tidy-tests/main.rs
index 80911a68e8..4f525fcd04 100644
--- a/xtask/tests/tidy-tests/main.rs
+++ b/xtask/tests/tidy-tests/main.rs
@@ -20,7 +20,16 @@ fn rust_files_are_tidy() {
 }
 
 fn check_todo(path: &Path, text: &str) {
-    if path.ends_with("tests/cli.rs") {
+    let whitelist = &[
+        // This file itself is whitelisted since this test itself contains matches.
+        "tests/cli.rs",
+        // Some of our assists generate `todo!()` so those files are whitelisted.
+        "doc_tests/generated.rs",
+        "handlers/add_missing_impl_members.rs",
+        // To support generating `todo!()` in assists, we have `expr_todo()` in ast::make.
+        "ast/make.rs",
+    ];
+    if whitelist.iter().any(|p| path.ends_with(p)) {
         return;
     }
     if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") {