Repository: rust-analyzer/rust-analyzer
Pull request #11230 (2022-01-07 17:51:29)

fix: Fix attribute stripping ignoring doc comments
Follow up to https://github.com/rust-analyzer/rust-analyzer/pull/11225#pullrequestreview-846779237



Patch:
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 3b28b14668..ec8349cfde 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -68,7 +68,7 @@ use once_cell::unsync::Lazy;
 use rustc_hash::FxHashSet;
 use stdx::{format_to, impl_from};
 use syntax::{
-    ast::{self, HasAttrs as _, HasName},
+    ast::{self, HasAttrs as _, HasDocComments, HasName},
     AstNode, AstPtr, SmolStr, SyntaxKind, SyntaxNodePtr,
 };
 use tt::{Ident, Leaf, Literal, TokenTree};
@@ -612,10 +612,13 @@ impl Module {
                         }
                         MacroCallKind::Attr { ast_id, invoc_attr_index, attr_name, .. } => {
                             let node = ast_id.to_node(db.upcast());
-                            let attr =
-                                node.attrs().nth((*invoc_attr_index) as usize).unwrap_or_else(
-                                    || panic!("cannot find attribute #{}", invoc_attr_index),
-                                );
+                            let attr = node
+                                .doc_comments_and_attrs()
+                                .nth((*invoc_attr_index) as usize)
+                                .and_then(Either::right)
+                                .unwrap_or_else(|| {
+                                    panic!("cannot find attribute #{}", invoc_attr_index)
+                                });
                             (
                                 ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))),
                                 Some(attr_name.clone()),
@@ -1689,26 +1692,6 @@ impl BuiltinType {
     pub fn name(self) -> Name {
         self.inner.as_name()
     }
-
-    pub fn is_int(&self) -> bool {
-        matches!(self.inner, hir_def::builtin_type::BuiltinType::Int(_))
-    }
-
-    pub fn is_uint(&self) -> bool {
-        matches!(self.inner, hir_def::builtin_type::BuiltinType::Uint(_))
-    }
-
-    pub fn is_float(&self) -> bool {
-        matches!(self.inner, hir_def::builtin_type::BuiltinType::Float(_))
-    }
-
-    pub fn is_char(&self) -> bool {
-        matches!(self.inner, hir_def::builtin_type::BuiltinType::Char)
-    }
-
-    pub fn is_str(&self) -> bool {
-        matches!(self.inner, hir_def::builtin_type::BuiltinType::Str)
-    }
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -2635,10 +2618,6 @@ impl Type {
         matches!(&self.ty.kind(Interner), TyKind::FnDef(..) | TyKind::Function { .. })
     }
 
-    pub fn is_array(&self) -> bool {
-        matches!(&self.ty.kind(Interner), TyKind::Array(..))
-    }
-
     pub fn is_packed(&self, db: &dyn HirDatabase) -> bool {
         let adt_id = match *self.ty.kind(Interner) {
             TyKind::Adt(hir_ty::AdtId(adt_id), ..) => adt_id,
@@ -2737,7 +2716,7 @@ impl Type {
     // This would be nicer if it just returned an iterator, but that runs into
     // lifetime problems, because we need to borrow temp `CrateImplDefs`.
     pub fn iterate_assoc_items<T>(
-        &self,
+        self,
         db: &dyn HirDatabase,
         krate: Crate,
         mut callback: impl FnMut(AssocItem) -> Option<T>,
@@ -2751,7 +2730,7 @@ impl Type {
     }
 
     fn iterate_assoc_items_dyn(
-        &self,
+        self,
         db: &dyn HirDatabase,
         krate: Crate,
         callback: &mut dyn FnMut(AssocItemId) -> bool,
@@ -2793,7 +2772,6 @@ impl Type {
     ) -> Option<T> {
         let _p = profile::span("iterate_method_candidates");
         let mut slot = None;
-
         self.iterate_method_candidates_dyn(
             db,
             krate,
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index c88b5639f0..c39825b591 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -3,12 +3,13 @@
 use std::sync::Arc;
 
 use base_db::{salsa, SourceDatabase};
+use either::Either;
 use limit::Limit;
 use mbe::{syntax_node_to_token_tree, ExpandError, ExpandResult};
 use rustc_hash::FxHashSet;
 use syntax::{
     algo::diff,
-    ast::{self, HasAttrs},
+    ast::{self, HasAttrs, HasDocComments},
     AstNode, GreenNode, Parse, SyntaxNode, SyntaxToken, T,
 };
 
@@ -153,7 +154,10 @@ pub fn expand_speculative(
             // Attributes may have an input token tree, build the subtree and map for this as well
             // then try finding a token id for our token if it is inside this input subtree.
             let item = ast::Item::cast(speculative_args.clone())?;
-            let attr = item.attrs().nth(invoc_attr_index as usize)?;
+            let attr = item
+                .doc_comments_and_attrs()
+                .nth(invoc_attr_index as usize)
+                .and_then(Either::right)?;
             match attr.token_tree() {
                 Some(token_tree) => {
                     let (mut tree, map) = syntax_node_to_token_tree(attr.token_tree()?.syntax());
@@ -328,8 +332,9 @@ fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet<Sy
             MacroCallKind::Attr { invoc_attr_index, .. } => {
                 cov_mark::hit!(attribute_macro_attr_censoring);
                 ast::Item::cast(node.clone())?
-                    .attrs()
+                    .doc_comments_and_attrs()
                     .nth(invoc_attr_index as usize)
+                    .and_then(Either::right)
                     .map(|attr| attr.syntax().clone())
                     .into_iter()
                     .collect()
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs
index e74c705217..d7dc0443b2 100644
--- a/crates/hir_expand/src/hygiene.rs
+++ b/crates/hir_expand/src/hygiene.rs
@@ -9,7 +9,7 @@ use db::TokenExpander;
 use either::Either;
 use mbe::Origin;
 use syntax::{
-    ast::{self, HasAttrs},
+    ast::{self, HasDocComments},
     AstNode, SyntaxKind, SyntaxNode, TextRange, TextSize,
 };
 
@@ -187,7 +187,12 @@ fn make_hygiene_info(
     });
     let attr_input_or_mac_def = def.or_else(|| match loc.kind {
         MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
-            let tt = ast_id.to_node(db).attrs().nth(invoc_attr_index as usize)?.token_tree()?;
+            let tt = ast_id
+                .to_node(db)
+                .doc_comments_and_attrs()
+                .nth(invoc_attr_index as usize)
+                .and_then(Either::right)?
+                .token_tree()?;
             Some(InFile::new(ast_id.file_id, tt))
         }
         _ => None,
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index 3e2e1ba630..5f190b8727 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -25,7 +25,7 @@ use std::{hash::Hash, iter, sync::Arc};
 use base_db::{impl_intern_key, salsa, CrateId, FileId, FileRange};
 use syntax::{
     algo::{self, skip_trivia_token},
-    ast::{self, AstNode, HasAttrs},
+    ast::{self, AstNode, HasDocComments},
     Direction, SyntaxNode, SyntaxToken,
 };
 
@@ -201,8 +201,9 @@ impl HirFileId {
                     MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
                         let tt = ast_id
                             .to_node(db)
-                            .attrs()
-                            .nth(invoc_attr_index as usize)?
+                            .doc_comments_and_attrs()
+                            .nth(invoc_attr_index as usize)
+                            .and_then(Either::right)?
                             .token_tree()?;
                         Some(InFile::new(ast_id.file_id, tt))
                     }
@@ -429,8 +430,11 @@ impl ExpansionInfo {
 
             let token_range = token.value.text_range();
             match &loc.kind {
-                MacroCallKind::Attr { attr_args, invoc_attr_index, .. } => {
-                    let attr = item.attrs().nth(*invoc_attr_index as usize)?;
+                MacroCallKind::Attr { attr_args: (_, map), invoc_attr_index, .. } => {
+                    let attr = item
+                        .doc_comments_and_attrs()
+                        .nth(*invoc_attr_index as usize)
+                        .and_then(Either::right)?;
                     match attr.token_tree() {
                         Some(token_tree)
                             if token_tree.syntax().text_range().contains_range(token_range) =>
@@ -440,9 +444,8 @@ impl ExpansionInfo {
                             let relative_range =
                                 token.value.text_range().checked_sub(attr_input_start)?;
                             // shift by the item's tree's max id
-                            let token_id = self
-                                .macro_arg_shift
-                                .shift(attr_args.1.token_by_range(relative_range)?);
+                            let token_id =
+                                self.macro_arg_shift.shift(map.token_by_range(relative_range)?);
                             Some(token_id)
                         }
                         _ => None,
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index 3636ab6213..23f81d3c7f 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -226,7 +226,6 @@ pub mod known {
         iter_mut,
         len,
         is_empty,
-        new,
         // Builtin macros
         asm,
         assert,
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 1a451ae79f..cb6b6ec39f 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -542,7 +542,6 @@ pub fn iterate_method_candidates_dyn(
 
             let deref_chain = autoderef_method_receiver(db, krate, ty);
             let mut deref_chains = stdx::slice_tails(&deref_chain);
-
             deref_chains.try_for_each(|deref_chain| {
                 iterate_method_candidates_with_autoref(
                     deref_chain,
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index b8482d0222..16a2b4a113 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -118,7 +118,7 @@ pub use ide_db::{
     symbol_index::Query,
     RootDatabase, SymbolKind,
 };
-pub use ide_diagnostics::{Diagnostic, DiagnosticsConfig, ExprFillDefaultMode, Severity};
+pub use ide_diagnostics::{Diagnostic, DiagnosticsConfig, Severity};
 pub use ide_ssr::SsrError;
 pub use syntax::{TextRange, TextSize};
 pub use text_edit::{Indel, TextEdit};
diff --git a/crates/ide_assists/src/handlers/add_turbo_fish.rs b/crates/ide_assists/src/handlers/add_turbo_fish.rs
index c3d27f7ea6..2872edc9e1 100644
--- a/crates/ide_assists/src/handlers/add_turbo_fish.rs
+++ b/crates/ide_assists/src/handlers/add_turbo_fish.rs
@@ -1,5 +1,4 @@
 use ide_db::defs::{Definition, NameRefClass};
-use itertools::Itertools;
 use syntax::{ast, AstNode, SyntaxKind, T};
 
 use crate::{
@@ -78,12 +77,8 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<(
         }
     }
 
-    let number_of_arguments = generics
-        .iter()
-        .filter(|param| {
-            matches!(param, hir::GenericParam::TypeParam(_) | hir::GenericParam::ConstParam(_))
-        })
-        .count();
+    let number_of_arguments = generics.len();
+    let fish_head = std::iter::repeat("_").take(number_of_arguments).collect::<Vec<_>>().join(",");
 
     acc.add(
         AssistId("add_turbo_fish", AssistKind::RefactorRewrite),
@@ -91,11 +86,10 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<(
         ident.text_range(),
         |builder| match ctx.config.snippet_cap {
             Some(cap) => {
-                let snip = format!("::<{}>", get_snippet_fish_head(number_of_arguments));
+                let snip = format!("::<${{0:{}}}>", fish_head);
                 builder.insert_snippet(cap, ident.text_range().end(), snip)
             }
             None => {
-                let fish_head = std::iter::repeat("_").take(number_of_arguments).format(", ");
                 let snip = format!("::<{}>", fish_head);
                 builder.insert(ident.text_range().end(), snip);
             }
@@ -103,17 +97,6 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<(
     )
 }
 
-/// This will create a snippet string with tabstops marked
-fn get_snippet_fish_head(number_of_arguments: usize) -> String {
-    let mut fish_head = (1..number_of_arguments)
-        .format_with("", |i, f| f(&format_args!("${{{}:_}}, ", i)))
-        .to_string();
-
-    // tabstop 0 is a special case and always the last one
-    fish_head.push_str("${0:_}");
-    fish_head
-}
-
 #[cfg(test)]
 mod tests {
     use crate::tests::{check_assist, check_assist_by_label, check_assist_not_applicable};
@@ -152,7 +135,7 @@ fn main() {
             r#"
 fn make<T, A>() -> T {}
 fn main() {
-    make::<${1:_}, ${0:_}>();
+    make::<${0:_,_}>();
 }
 "#,
         );
@@ -171,7 +154,7 @@ fn main() {
             r#"
 fn make<T, A, B, C, D, E, F>() -> T {}
 fn main() {
-    make::<${1:_}, ${2:_}, ${3:_}, ${4:_}, ${5:_}, ${6:_}, ${0:_}>();
+    make::<${0:_,_,_,_,_,_,_}>();
 }
 "#,
         );
@@ -356,42 +339,4 @@ fn main() {
             "Add `: _` before assignment operator",
         );
     }
-
-    #[test]
-    fn add_turbo_fish_function_lifetime_parameter() {
-        check_assist(
-            add_turbo_fish,
-            r#"
-fn make<'a, T, A>(t: T, a: A) {}
-fn main() {
-    make$0(5, 2);
-}
-"#,
-            r#"
-fn make<'a, T, A>(t: T, a: A) {}
-fn main() {
-    make::<${1:_}, ${0:_}>(5, 2);
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn add_turbo_fish_function_const_parameter() {
-        check_assist(
-            add_turbo_fish,
-            r#"
-fn make<T, const N: usize>(t: T) {}
-fn main() {
-    make$0(3);
-}
-"#,
-            r#"
-fn make<T, const N: usize>(t: T) {}
-fn main() {
-    make::<${1:_}, ${0:_}>(3);
-}
-"#,
-        );
-    }
 }
diff --git a/crates/ide_assists/src/handlers/generate_documentation_template.rs b/crates/ide_assists/src/handlers/generate_documentation_template.rs
index bb7c8b1010..1481eadb51 100644
--- a/crates/ide_assists/src/handlers/generate_documentation_template.rs
+++ b/crates/ide_assists/src/handlers/generate_documentation_template.rs
@@ -88,9 +88,7 @@ fn introduction_builder(ast_func: &ast::Fn, ctx: &AssistContext) -> String {
 
             let is_new = ast_func.name()?.to_string() == "new";
             match is_new && ret_ty == self_ty {
-                true => {
-                    Some(format!("Creates a new [`{}`].", self_type_without_lifetimes(ast_func)?))
-                }
+                true => Some(format!("Creates a new [`{}`].", self_type(ast_func)?)),
                 false => None,
             }
         } else {
@@ -223,34 +221,18 @@ fn self_name(ast_func: &ast::Fn) -> Option<String> {
 }
 
 /// Heper function to get the name of the type of `self`
-fn self_type(ast_func: &ast::Fn) -> Option<ast::Type> {
-    ast_func.syntax().ancestors().find_map(ast::Impl::cast).and_then(|i| i.self_ty())
-}
-
-/// Output the real name of `Self` like `MyType<T>`, without the lifetimes.
-fn self_type_without_lifetimes(ast_func: &ast::Fn) -> Option<String> {
-    let path_segment = match self_type(ast_func)? {
-        ast::Type::PathType(path_type) => path_type.path()?.segment()?,
-        _ => return None,
-    };
-    let mut name = path_segment.name_ref()?.to_string();
-    let generics = path_segment
-        .generic_arg_list()?
-        .generic_args()
-        .filter(|generic| matches!(generic, ast::GenericArg::TypeArg(_)))
-        .map(|generic| generic.to_string());
-    let generics: String = generics.format(", ").to_string();
-    if !generics.is_empty() {
-        name.push('<');
-        name.push_str(&generics);
-        name.push('>');
-    }
-    Some(name)
+fn self_type(ast_func: &ast::Fn) -> Option<String> {
+    ast_func
+        .syntax()
+        .ancestors()
+        .find_map(ast::Impl::cast)
+        .and_then(|i| i.self_ty())
+        .map(|t| (t.to_string()))
 }
 
 /// Heper function to get the name of the type of `self` without generic arguments
 fn self_partial_type(ast_func: &ast::Fn) -> Option<String> {
-    let mut self_type = self_type(ast_func)?.to_string();
+    let mut self_type = self_type(ast_func)?;
     if let Some(idx) = self_type.find(|c| ['<', ' '].contains(&c)) {
         self_type.truncate(idx);
     }
@@ -327,7 +309,7 @@ fn arguments_from_params(param_list: &ast::ParamList) -> String {
         },
         _ => "_".to_string(),
     });
-    args_iter.format(", ").to_string()
+    Itertools::intersperse(args_iter, ", ".to_string()).collect()
 }
 
 /// Helper function to build a function call. `None` if expected `self_name` was not provided
@@ -1009,124 +991,6 @@ impl<T> MyGenericStruct<T> {
         );
     }
 
-    #[test]
-    fn removes_one_lifetime_from_description() {
-        check_assist(
-            generate_documentation_template,
-            r#"
-#[derive(Debug, PartialEq)]
-pub struct MyGenericStruct<'a, T> {
-    pub x: &'a T,
-}
-impl<'a, T> MyGenericStruct<'a, T> {
-    pub fn new$0(x: &'a T) -> Self {
-        MyGenericStruct { x }
-    }
-}
-"#,
-            r#"
-#[derive(Debug, PartialEq)]
-pub struct MyGenericStruct<'a, T> {
-    pub x: &'a T,
-}
-impl<'a, T> MyGenericStruct<'a, T> {
-    /// Creates a new [`MyGenericStruct<T>`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use test::MyGenericStruct;
-    ///
-    /// assert_eq!(MyGenericStruct::new(x), );
-    /// ```
-    pub fn new(x: &'a T) -> Self {
-        MyGenericStruct { x }
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn removes_all_lifetimes_from_description() {
-        check_assist(
-            generate_documentation_template,
-            r#"
-#[derive(Debug, PartialEq)]
-pub struct MyGenericStruct<'a, 'b, T> {
-    pub x: &'a T,
-    pub y: &'b T,
-}
-impl<'a, 'b, T> MyGenericStruct<'a, 'b, T> {
-    pub fn new$0(x: &'a T, y: &'b T) -> Self {
-        MyGenericStruct { x, y }
-    }
-}
-"#,
-            r#"
-#[derive(Debug, PartialEq)]
-pub struct MyGenericStruct<'a, 'b, T> {
-    pub x: &'a T,
-    pub y: &'b T,
-}
-impl<'a, 'b, T> MyGenericStruct<'a, 'b, T> {
-    /// Creates a new [`MyGenericStruct<T>`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use test::MyGenericStruct;
-    ///
-    /// assert_eq!(MyGenericStruct::new(x, y), );
-    /// ```
-    pub fn new(x: &'a T, y: &'b T) -> Self {
-        MyGenericStruct { x, y }
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn removes_all_lifetimes_and_brackets_from_description() {
-        check_assist(
-            generate_documentation_template,
-            r#"
-#[derive(Debug, PartialEq)]
-pub struct MyGenericStruct<'a, 'b> {
-    pub x: &'a usize,
-    pub y: &'b usize,
-}
-impl<'a, 'b> MyGenericStruct<'a, 'b> {
-    pub fn new$0(x: &'a usize, y: &'b usize) -> Self {
-        MyGenericStruct { x, y }
-    }
-}
-"#,
-            r#"
-#[derive(Debug, PartialEq)]
-pub struct MyGenericStruct<'a, 'b> {
-    pub x: &'a usize,
-    pub y: &'b usize,
-}
-impl<'a, 'b> MyGenericStruct<'a, 'b> {
-    /// Creates a new [`MyGenericStruct`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use test::MyGenericStruct;
-    ///
-    /// assert_eq!(MyGenericStruct::new(x, y), );
-    /// ```
-    pub fn new(x: &'a usize, y: &'b usize) -> Self {
-        MyGenericStruct { x, y }
-    }
-}
-"#,
-        );
-    }
-
     #[test]
     fn detects_new_with_self() {
         check_assist(
diff --git a/crates/ide_diagnostics/src/handlers/missing_fields.rs b/crates/ide_diagnostics/src/handlers/missing_fields.rs
index 186bfc3d58..8d17a7e714 100644
--- a/crates/ide_diagnostics/src/handlers/missing_fields.rs
+++ b/crates/ide_diagnostics/src/handlers/missing_fields.rs
@@ -1,16 +1,9 @@
 use either::Either;
-use hir::{
-    db::{AstDatabase, HirDatabase},
-    known, AssocItem, HirDisplay, InFile, Type,
-};
-use ide_db::{assists::Assist, helpers::FamousDefs, source_change::SourceChange};
+use hir::{db::AstDatabase, InFile};
+use ide_db::{assists::Assist, source_change::SourceChange};
 use rustc_hash::FxHashMap;
 use stdx::format_to;
-use syntax::{
-    algo,
-    ast::{self, make},
-    AstNode, SyntaxNodePtr,
-};
+use syntax::{algo, ast::make, AstNode, SyntaxNodePtr};
 use text_edit::TextEdit;
 
 use crate::{fix, Diagnostic, DiagnosticsContext};
@@ -70,18 +63,6 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
         }
     });
     let missing_fields = ctx.sema.record_literal_missing_fields(&field_list_parent);
-
-    let generate_fill_expr = |ty: &Type| match ctx.config.expr_fill_default {
-        crate::ExprFillDefaultMode::Todo => Some(make::ext::expr_todo()),
-        crate::ExprFillDefaultMode::Default => {
-            let default_constr = get_default_constructor(ctx, d, ty);
-            match default_constr {
-                Some(default_constr) => Some(default_constr),
-                _ => Some(make::ext::expr_todo()),
-            }
-        }
-    };
-
     for (f, ty) in missing_fields.iter() {
         let field_expr = if let Some(local_candidate) = locals.get(&f.name(ctx.sema.db)) {
             cov_mark::hit!(field_shorthand);
@@ -89,10 +70,10 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
             if ty.could_unify_with(ctx.sema.db, &candidate_ty) {
                 None
             } else {
-                generate_fill_expr(ty)
+                Some(make::ext::expr_todo())
             }
         } else {
-            generate_fill_expr(ty)
+            Some(make::ext::expr_todo())
         };
         let field =
             make::record_expr_field(make::name_ref(&f.name(ctx.sema.db).to_smol_str()), field_expr)
@@ -121,68 +102,6 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
     )])
 }
 
-fn make_ty(ty: &hir::Type, db: &dyn HirDatabase, module: hir::Module) -> ast::Type {
-    let ty_str = match ty.as_adt() {
-        Some(adt) => adt.name(db).to_string(),
-        None => ty.display_source_code(db, module.into()).ok().unwrap_or_else(|| "_".to_string()),
-    };
-
-    make::ty(&ty_str)
-}
-
-fn get_default_constructor(
-    ctx: &DiagnosticsContext<'_>,
-    d: &hir::MissingFields,
-    ty: &Type,
-) -> Option<ast::Expr> {
-    if let Some(builtin_ty) = ty.as_builtin() {
-        if builtin_ty.is_int() || builtin_ty.is_uint() {
-            return Some(make::ext::zero_number());
-        }
-        if builtin_ty.is_float() {
-            return Some(make::ext::zero_float());
-        }
-        if builtin_ty.is_char() {
-            return Some(make::ext::empty_char());
-        }
-        if builtin_ty.is_str() {
-            return Some(make::ext::empty_str());
-        }
-    }
-
-    let krate = ctx.sema.to_module_def(d.file.original_file(ctx.sema.db))?.krate();
-    let module = krate.root_module(ctx.sema.db);
-
-    // Look for a ::new() associated function
-    let has_new_func = ty
-        .iterate_assoc_items(ctx.sema.db, krate, |assoc_item| {
-            if let AssocItem::Function(func) = assoc_item {
-                if func.name(ctx.sema.db) == known::new
-                    && func.assoc_fn_params(ctx.sema.db).is_empty()
-                {
-                    return Some(());
-                }
-            }
-
-            None
-        })
-        .is_some();
-
-    if has_new_func {
-        Some(make::ext::expr_ty_new(&make_ty(ty, ctx.sema.db, module)))
-    } else if !ty.is_array()
-        && ty.impls_trait(
-            ctx.sema.db,
-            FamousDefs(&ctx.sema, Some(krate)).core_default_Default()?,
-            &[],
-        )
-    {
-        Some(make::ext::expr_ty_default(&make_ty(ty, ctx.sema.db, module)))
-    } else {
-        None
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use crate::tests::{check_diagnostics, check_fix};
@@ -263,7 +182,7 @@ fn here() {}
 macro_rules! id { ($($tt:tt)*) => { $($tt)*}; }
 
 fn main() {
-    let _x = id![Foo {a:42, b: 0 }];
+    let _x = id![Foo {a:42, b: todo!() }];
 }
 
 pub struct Foo { pub a: i32, pub b: i32 }
@@ -285,7 +204,7 @@ fn test_fn() {
 struct TestStruct { one: i32, two: i64 }
 
 fn test_fn() {
-    let s = TestStruct { one: 0, two: 0 };
+    let s = TestStruct { one: todo!(), two: todo!() };
 }
 "#,
         );
@@ -305,7 +224,7 @@ impl TestStruct {
 struct TestStruct { one: i32 }
 
 impl TestStruct {
-    fn test_fn() { let s = Self { one: 0 }; }
+    fn test_fn() { let s = Self { one: todo!() }; }
 }
 "#,
         );
@@ -353,72 +272,7 @@ fn test_fn() {
 struct TestStruct { one: i32, two: i64 }
 
 fn test_fn() {
-    let s = TestStruct{ two: 2, one: 0 };
-}
-",
-        );
-    }
-
-    #[test]
-    fn test_fill_struct_fields_new() {
-        check_fix(
-            r#"
-struct TestWithNew(usize);
-impl TestWithNew {
-    pub fn new() -> Self {
-        Self(0)
-    }
-}
-struct TestStruct { one: i32, two: TestWithNew }
-
-fn test_fn() {
-    let s = TestStruct{ $0 };
-}
-"#,
-            r"
-struct TestWithNew(usize);
-impl TestWithNew {
-    pub fn new() -> Self {
-        Self(0)
-    }
-}
-struct TestStruct { one: i32, two: TestWithNew }
-
-fn test_fn() {
-    let s = TestStruct{ one: 0, two: TestWithNew::new()  };
-}
-",
-        );
-    }
-
-    #[test]
-    fn test_fill_struct_fields_default() {
-        check_fix(
-            r#"
-//- minicore: default
-struct TestWithDefault(usize);
-impl Default for TestWithDefault {
-    pub fn default() -> Self {
-        Self(0)
-    }
-}
-struct TestStruct { one: i32, two: TestWithDefault }
-
-fn test_fn() {
-    let s = TestStruct{ $0 };
-}
-"#,
-            r"
-struct TestWithDefault(usize);
-impl Default for TestWithDefault {
-    pub fn default() -> Self {
-        Self(0)
-    }
-}
-struct TestStruct { one: i32, two: TestWithDefault }
-
-fn test_fn() {
-    let s = TestStruct{ one: 0, two: TestWithDefault::default()  };
+    let s = TestStruct{ two: 2, one: todo!() };
 }
 ",
         );
@@ -438,7 +292,7 @@ fn test_fn() {
 struct TestStruct { r#type: u8 }
 
 fn test_fn() {
-    TestStruct { r#type: 0  };
+    TestStruct { r#type: todo!()  };
 }
 ",
         );
@@ -549,7 +403,7 @@ fn f() {
     let b = 1usize;
     S {
         a,
-        b: 0,
+        b: todo!(),
     };
 }
 "#,
diff --git a/crates/ide_diagnostics/src/lib.rs b/crates/ide_diagnostics/src/lib.rs
index 86d76751ad..c921d989bd 100644
--- a/crates/ide_diagnostics/src/lib.rs
+++ b/crates/ide_diagnostics/src/lib.rs
@@ -129,22 +129,10 @@ pub enum Severity {
     WeakWarning,
 }
 
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum ExprFillDefaultMode {
-    Todo,
-    Default,
-}
-impl Default for ExprFillDefaultMode {
-    fn default() -> Self {
-        Self::Todo
-    }
-}
-
 #[derive(Default, Debug, Clone)]
 pub struct DiagnosticsConfig {
     pub disable_experimental: bool,
     pub disabled: FxHashSet<String>,
-    pub expr_fill_default: ExprFillDefaultMode,
 }
 
 struct DiagnosticsContext<'a> {
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 88d86ef503..de0aba0caa 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -11,8 +11,8 @@ use std::{ffi::OsString, iter, path::PathBuf};
 
 use flycheck::FlycheckConfig;
 use ide::{
-    AssistConfig, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode, HighlightRelatedConfig,
-    HoverConfig, HoverDocFormat, InlayHintsConfig, JoinLinesConfig, Snippet, SnippetScope,
+    AssistConfig, CompletionConfig, DiagnosticsConfig, HighlightRelatedConfig, HoverConfig,
+    HoverDocFormat, InlayHintsConfig, JoinLinesConfig, Snippet, SnippetScope,
 };
 use ide_db::helpers::{
     insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
@@ -45,8 +45,6 @@ use crate::{
 // parsing the old name.
 config_data! {
     struct ConfigData {
-        /// Placeholder for missing expressions in assists.
-        assist_exprFillDefault: ExprFillDefaultDef              = "\"todo\"",
         /// How imports should be grouped into use statements.
         assist_importGranularity |
         assist_importMergeBehavior |
@@ -710,10 +708,6 @@ impl Config {
         DiagnosticsConfig {
             disable_experimental: !self.data.diagnostics_enableExperimental,
             disabled: self.data.diagnostics_disabled.clone(),
-            expr_fill_default: match self.data.assist_exprFillDefault {
-                ExprFillDefaultDef::Todo => ExprFillDefaultMode::Todo,
-                ExprFillDefaultDef::Default => ExprFillDefaultMode::Default,
-            },
         }
     }
     pub fn diagnostics_map(&self) -> DiagnosticsMapConfig {
@@ -1085,15 +1079,6 @@ enum ManifestOrProjectJson {
     ProjectJson(ProjectJsonData),
 }
 
-#[derive(Deserialize, Debug, Clone)]
-#[serde(rename_all = "snake_case")]
-pub enum ExprFillDefaultDef {
-    #[serde(alias = "todo")]
-    Todo,
-    #[serde(alias = "default")]
-    Default,
-}
-
 #[derive(Deserialize, Debug, Clone)]
 #[serde(rename_all = "snake_case")]
 enum ImportGranularityDef {
@@ -1300,14 +1285,6 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
                 "Merge imports from the same module into a single `use` statement."
             ],
         },
-        "ExprFillDefaultDef" => set! {
-            "type": "string",
-            "enum": ["todo", "default"],
-            "enumDescriptions": [
-                "Fill missing expressions with the `todo` macro",
-                "Fill missing expressions with reasonable defaults, `new` or `default` constructors."
-            ],
-        },
         "ImportGranularityDef" => set! {
             "type": "string",
             "enum": ["preserve", "crate", "module", "item"],
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index 3575020975..e1938307cf 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -59,28 +59,6 @@ pub mod ext {
     pub fn expr_todo() -> ast::Expr {
         expr_from_text("todo!()")
     }
-    pub fn expr_ty_default(ty: &ast::Type) -> ast::Expr {
-        expr_from_text(&format!("{}::default()", ty))
-    }
-    pub fn expr_ty_new(ty: &ast::Type) -> ast::Expr {
-        expr_from_text(&format!("{}::new()", ty))
-    }
-
-    pub fn zero_number() -> ast::Expr {
-        expr_from_text("0")
-    }
-    pub fn zero_float() -> ast::Expr {
-        expr_from_text("0.0")
-    }
-    pub fn empty_str() -> ast::Expr {
-        expr_from_text(r#""""#)
-    }
-    pub fn empty_char() -> ast::Expr {
-        expr_from_text("'\x00'")
-    }
-    pub fn default_bool() -> ast::Expr {
-        expr_from_text("false")
-    }
     pub fn empty_block_expr() -> ast::BlockExpr {
         block_expr(None, None)
     }
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 705aa5edac..470e9a04b3 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -772,6 +772,7 @@ impl ast::HasLoopBody for ast::ForExpr {
 }
 
 impl ast::HasAttrs for ast::AnyHasDocComments {}
+impl ast::HasDocComments for ast::Item {}
 
 impl From<ast::Adt> for ast::Item {
     fn from(it: ast::Adt) -> Self {
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index 88dcacfe83..f46dda2351 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -1,8 +1,3 @@
-[[rust-analyzer.assist.exprFillDefault]]rust-analyzer.assist.exprFillDefault (default: `"todo"`)::
-+
---
-Placeholder for missing expressions in assists.
---
 [[rust-analyzer.assist.importGranularity]]rust-analyzer.assist.importGranularity (default: `"crate"`)::
 +
 --
diff --git a/editors/code/package.json b/editors/code/package.json
index 2c7d6c3773..d418868474 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -378,19 +378,6 @@
                     "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`"
                 },
                 "$generated-start": {},
-                "rust-analyzer.assist.exprFillDefault": {
-                    "markdownDescription": "Placeholder for missing expressions in assists.",
-                    "default": "todo",
-                    "type": "string",
-                    "enum": [
-                        "todo",
-                        "default"
-                    ],
-                    "enumDescriptions": [
-                        "Fill missing expressions with the `todo` macro",
-                        "Fill missing expressions with reasonable defaults, `new` or `default` constructors."
-                    ]
-                },
                 "rust-analyzer.assist.importGranularity": {
                     "markdownDescription": "How imports should be grouped into use statements.",
                     "default": "crate",


Test patch:
diff --git a/crates/ide_diagnostics/src/tests.rs b/crates/ide_diagnostics/src/tests.rs
index 7d06e9d36f..a2b92c4ff9 100644
--- a/crates/ide_diagnostics/src/tests.rs
+++ b/crates/ide_diagnostics/src/tests.rs
@@ -9,7 +9,7 @@ use ide_db::{
 use stdx::trim_indent;
 use test_utils::{assert_eq_text, extract_annotations};
 
-use crate::{DiagnosticsConfig, ExprFillDefaultMode, Severity};
+use crate::{DiagnosticsConfig, Severity};
 
 /// Takes a multi-file input fixture with annotated cursor positions,
 /// and checks that:
@@ -36,12 +36,14 @@ fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) {
     let after = trim_indent(ra_fixture_after);
 
     let (db, file_position) = RootDatabase::with_position(ra_fixture_before);
-    let mut conf = DiagnosticsConfig::default();
-    conf.expr_fill_default = ExprFillDefaultMode::Default;
-    let diagnostic =
-        super::diagnostics(&db, &conf, &AssistResolveStrategy::All, file_position.file_id)
-            .pop()
-            .expect("no diagnostics");
+    let diagnostic = super::diagnostics(
+        &db,
+        &DiagnosticsConfig::default(),
+        &AssistResolveStrategy::All,
+        file_position.file_id,
+    )
+    .pop()
+    .expect("no diagnostics");
     let fix = &diagnostic.fixes.expect("diagnostic misses fixes")[nth];
     let actual = {
         let source_change = fix.source_change.as_ref().unwrap();