db::{AstDatabase, HirDatabase},
known, AssocItem, HirDisplay, InFile, Type,
};
-use ide_db::{assists::Assist, famous_defs::FamousDefs, source_change::SourceChange, FxHashMap};
+use ide_db::{
+ assists::Assist, famous_defs::FamousDefs, imports::import_assets::item_for_path_search,
+ source_change::SourceChange, FxHashMap,
+};
use stdx::format_to;
use syntax::{
algo,
use crate::{fix, Diagnostic, DiagnosticsContext};
+// TODO: how to depupicate with `ide-assists/generate_new`
+pub fn use_trivial_constructor(
+ db: &ide_db::RootDatabase,
+ path: ast::Path,
+ ty: &hir::Type,
+) -> Option<ast::Expr> {
+ match ty.as_adt() {
+ Some(hir::Adt::Enum(x)) => {
+ let variants = x.variants(db);
+
+ if variants.len() == 1 {
+ let variant = variants[0];
+
+ if variant.fields(db).is_empty() {
+ let path = ast::make::path_qualified(
+ path,
+ syntax::ast::make::path_segment(ast::make::name_ref(
+ &variant.name(db).to_smol_str(),
+ )),
+ );
+
+ let is_record = variant.kind(db) == hir::StructKind::Record;
+
+ return Some(if is_record {
+ ast::Expr::RecordExpr(syntax::ast::make::record_expr(
+ path,
+ ast::make::record_expr_field_list(std::iter::empty()),
+ ))
+ } else {
+ syntax::ast::make::expr_path(path)
+ });
+ }
+ }
+ }
+ Some(hir::Adt::Struct(x)) => {
+ if x.fields(db).is_empty() {
+ return Some(syntax::ast::make::expr_path(path));
+ }
+ }
+ _ => {}
+ }
+
+ None
+}
+
// Diagnostic: missing-fields
//
// This diagnostic is triggered if record lacks some fields that exist in the corresponding structure.
let root = ctx.sema.db.parse_or_expand(d.file)?;
+ let current_module = match &d.field_list_parent {
+ Either::Left(ptr) => ctx.sema.scope(ptr.to_node(&root).syntax()).unwrap().module(),
+ Either::Right(ptr) => ctx.sema.scope(ptr.to_node(&root).syntax()).unwrap().module(),
+ };
+
let build_text_edit = |parent_syntax, new_syntax: &SyntaxNode, old_syntax| {
let edit = {
let mut builder = TextEdit::builder();
Some(generate_fill_expr(ty))
}
} else {
- Some(generate_fill_expr(ty))
+ let expr = (|| -> Option<ast::Expr> {
+ let item_in_ns = hir::ItemInNs::from(hir::ModuleDef::from(ty.as_adt()?));
+
+ let type_path = current_module.find_use_path(
+ ctx.sema.db,
+ item_for_path_search(ctx.sema.db, item_in_ns)?,
+ )?;
+
+ use_trivial_constructor(
+ &ctx.sema.db,
+ ide_db::helpers::mod_path_to_ast(&type_path),
+ &ty,
+ )
+ })();
+
+ if expr.is_some() {
+ expr
+ } else {
+ Some(generate_fill_expr(ty))
+ }
};
let field = make::record_expr_field(
make::name_ref(&f.name(ctx.sema.db).to_smol_str()),
if builtin_ty.is_str() {
return Some(make::ext::empty_str());
}
+ if builtin_ty.is_bool() {
+ return Some(make::ext::default_bool());
+ }
}
let krate = ctx.sema.to_module_def(d.file.original_file(ctx.sema.db))?.krate();
})
.is_some();
+ let famous_defs = FamousDefs(&ctx.sema, krate);
if has_new_func {
Some(make::ext::expr_ty_new(&make_ty(ty, ctx.sema.db, module)))
+ } else if ty.as_adt() == famous_defs.core_option_Option()?.ty(ctx.sema.db).as_adt() {
+ Some(make::ext::option_none())
} else if !ty.is_array()
- && ty.impls_trait(ctx.sema.db, FamousDefs(&ctx.sema, krate).core_default_Default()?, &[])
+ && ty.impls_trait(ctx.sema.db, famous_defs.core_default_Default()?, &[])
{
Some(make::ext::expr_ty_default(&make_ty(ty, ctx.sema.db, module)))
} else {
fn test_fill_struct_fields_empty() {
check_fix(
r#"
-struct TestStruct { one: i32, two: i64 }
+//- minicore: option
+struct TestStruct { one: i32, two: i64, three: Option<i32>, four: bool }
fn test_fn() {
let s = TestStruct {$0};
}
"#,
r#"
-struct TestStruct { one: i32, two: i64 }
+struct TestStruct { one: i32, two: i64, three: Option<i32>, four: bool }
fn test_fn() {
- let s = TestStruct { one: 0, two: 0 };
+ let s = TestStruct { one: 0, two: 0, three: None, four: false };
}
"#,
);
fn test_fill_struct_fields_default() {
check_fix(
r#"
-//- minicore: default
+//- minicore: default, option
struct TestWithDefault(usize);
impl Default for TestWithDefault {
pub fn default() -> Self {