use either::Either;
use hir::{
db::{AstDatabase, HirDatabase},
- known, HirDisplay, InFile, SemanticsScope, Type,
+ known, AssocItem, HirDisplay, InFile, Type,
};
use ide_db::{assists::Assist, helpers::FamousDefs, source_change::SourceChange};
use rustc_hash::FxHashMap;
let generate_fill_expr = |ty: &Type| match ctx.config.expr_fill_default {
crate::ExprFillDefaultMode::Todo => Some(make::ext::expr_todo()),
crate::ExprFillDefaultMode::DefaultImpl => {
- let scope = ctx.sema.scope(&root);
- let default_constr = get_default_constructor(ctx, d, &scope, ty);
+ let default_constr = get_default_constructor(ctx, d, ty);
match default_constr {
Some(default_constr) => Some(default_constr),
_ => Some(make::ext::expr_todo()),
fn get_default_constructor(
ctx: &DiagnosticsContext<'_>,
d: &hir::MissingFields,
- scope: &SemanticsScope,
ty: &Type,
) -> Option<ast::Expr> {
if let Some(builtin_ty) = ty.as_builtin() {
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);
- let default_trait = FamousDefs(&ctx.sema, Some(krate)).core_default_Default()?;
- let traits_in_scope = scope.visible_traits();
- // Look for a ::new() method
- // FIXME: doesn't work for now
- let has_new_method = ty
- .iterate_method_candidates(
- ctx.sema.db,
- krate,
- &traits_in_scope,
- Some(&known::new),
- |_, func| {
- if func.assoc_fn_params(ctx.sema.db).is_empty()
+ // 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()
&& func.self_param(ctx.sema.db).is_none()
{
return Some(());
}
- None
- },
- )
+ }
+
+ None
+ })
.is_some();
- if has_new_method {
+ 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, default_trait, &[]) {
+ } 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
macro_rules! id { ($($tt:tt)*) => { $($tt)*}; }
fn main() {
- let _x = id![Foo {a:42, b: todo!() }];
+ let _x = id![Foo {a:42, b: 0 }];
}
pub struct Foo { pub a: i32, pub b: i32 }
struct TestStruct { one: i32, two: i64 }
fn test_fn() {
- let s = TestStruct { one: todo!(), two: todo!() };
+ let s = TestStruct { one: 0, two: 0 };
}
"#,
);
struct TestStruct { one: i32 }
impl TestStruct {
- fn test_fn() { let s = Self { one: todo!() }; }
+ fn test_fn() { let s = Self { one: 0 }; }
}
"#,
);
struct TestStruct { one: i32, two: i64 }
fn test_fn() {
- let s = TestStruct{ two: 2, one: todo!() };
+ 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() };
}
",
);
struct TestStruct { r#type: u8 }
fn test_fn() {
- TestStruct { r#type: todo!() };
+ TestStruct { r#type: 0 };
}
",
);
let b = 1usize;
S {
a,
- b: todo!(),
+ b: 0,
};
}
"#,
use stdx::trim_indent;
use test_utils::{assert_eq_text, extract_annotations};
-use crate::{DiagnosticsConfig, Severity};
+use crate::{DiagnosticsConfig, ExprFillDefaultMode, Severity};
/// Takes a multi-file input fixture with annotated cursor positions,
/// and checks that:
let after = trim_indent(ra_fixture_after);
let (db, file_position) = RootDatabase::with_position(ra_fixture_before);
- let diagnostic = super::diagnostics(
- &db,
- &DiagnosticsConfig::default(),
- &AssistResolveStrategy::All,
- file_position.file_id,
- )
- .pop()
- .expect("no diagnostics");
+ let mut conf = DiagnosticsConfig::default();
+ conf.expr_fill_default = ExprFillDefaultMode::DefaultImpl;
+ let diagnostic =
+ super::diagnostics(&db, &conf, &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();