Skip to content

Commit 8e3bbaa

Browse files
committed
instanciate_empty_structs
1 parent 65874df commit 8e3bbaa

File tree

2 files changed

+179
-4
lines changed

2 files changed

+179
-4
lines changed

crates/ide-assists/src/handlers/generate_new.rs

Lines changed: 98 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use ide_db::imports::import_assets::item_for_path_search;
12
use itertools::Itertools;
23
use stdx::format_to;
34
use syntax::ast::{self, AstNode, HasName, HasVisibility, StructKind};
@@ -7,6 +8,58 @@ use crate::{
78
AssistContext, AssistId, AssistKind, Assists,
89
};
910

11+
// TODO: how to depupicate with `ide-diagnostics/mssing_fields`
12+
pub fn use_trivial_constructor(
13+
db: &ide_db::RootDatabase,
14+
path: ast::Path,
15+
ty: &hir::Type,
16+
) -> Option<ast::Expr> {
17+
match ty.as_adt() {
18+
Some(hir::Adt::Enum(x)) => {
19+
let variants = x.variants(db);
20+
21+
if variants.len() == 1 {
22+
let variant = variants[0];
23+
24+
if variant.fields(db).is_empty() {
25+
let path = ast::make::path_qualified(
26+
path,
27+
syntax::ast::make::path_segment(ast::make::name_ref(
28+
&variant.name(db).to_smol_str(),
29+
)),
30+
);
31+
32+
use hir::StructKind::*;
33+
let is_record = match variant.kind(db) {
34+
Record => true,
35+
Tuple => false,
36+
Unit => false,
37+
};
38+
39+
return Some(if is_record {
40+
ast::Expr::RecordExpr(syntax::ast::make::record_expr(
41+
path,
42+
ast::make::record_expr_field_list(std::iter::empty()),
43+
))
44+
} else {
45+
syntax::ast::make::expr_path(path)
46+
});
47+
}
48+
}
49+
}
50+
Some(hir::Adt::Struct(x)) => {
51+
let fields = x.fields(db);
52+
53+
if fields.is_empty() {
54+
return Some(syntax::ast::make::expr_path(path));
55+
}
56+
}
57+
_ => {}
58+
}
59+
60+
None
61+
}
62+
1063
// Assist: generate_new
1164
//
1265
// Adds a new inherent impl for a type.
@@ -48,11 +101,54 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
48101

49102
let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v));
50103

104+
let current_module = ctx.sema.scope(strukt.syntax()).unwrap().module();
105+
106+
let trivial_constructors = field_list
107+
.fields()
108+
.map(|f| {
109+
let ty = ctx.sema.resolve_type(&f.ty()?)?;
110+
111+
let item_in_ns = hir::ItemInNs::from(hir::ModuleDef::from(ty.as_adt()?));
112+
113+
let type_path = current_module
114+
.find_use_path(ctx.sema.db, item_for_path_search(ctx.sema.db, item_in_ns)?)?;
115+
116+
let expr = use_trivial_constructor(
117+
&ctx.sema.db,
118+
ide_db::helpers::mod_path_to_ast(&type_path),
119+
&ty,
120+
)?;
121+
122+
Some(format!("{}: {}", f.name()?.syntax(), expr))
123+
})
124+
.collect::<Vec<_>>();
125+
126+
dbg!(&trivial_constructors);
127+
51128
let params = field_list
52129
.fields()
53-
.filter_map(|f| Some(format!("{}: {}", f.name()?.syntax(), f.ty()?.syntax())))
130+
.enumerate()
131+
.filter_map(|(i, f)| {
132+
if trivial_constructors[i].is_none() {
133+
Some(format!("{}: {}", f.name()?.syntax(), f.ty()?.syntax()))
134+
} else {
135+
None
136+
}
137+
})
138+
.format(", ");
139+
140+
let fields = field_list
141+
.fields()
142+
.enumerate()
143+
.filter_map(|(i, f)| {
144+
let contructor = trivial_constructors[i].clone();
145+
if contructor.is_some() {
146+
contructor
147+
} else {
148+
Some(f.name()?.to_string())
149+
}
150+
})
54151
.format(", ");
55-
let fields = field_list.fields().filter_map(|f| f.name()).format(", ");
56152

57153
format_to!(buf, " {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields);
58154

crates/ide-diagnostics/src/handlers/missing_fields.rs

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ use hir::{
33
db::{AstDatabase, HirDatabase},
44
known, AssocItem, HirDisplay, InFile, Type,
55
};
6-
use ide_db::{assists::Assist, famous_defs::FamousDefs, source_change::SourceChange, FxHashMap};
6+
use ide_db::{
7+
assists::Assist, famous_defs::FamousDefs, imports::import_assets::item_for_path_search,
8+
source_change::SourceChange, FxHashMap,
9+
};
710
use stdx::format_to;
811
use syntax::{
912
algo,
@@ -14,6 +17,58 @@ use text_edit::TextEdit;
1417

1518
use crate::{fix, Diagnostic, DiagnosticsContext};
1619

20+
// TODO: how to depupicate with `ide-assists/generate_new`
21+
pub fn use_trivial_constructor(
22+
db: &ide_db::RootDatabase,
23+
path: ast::Path,
24+
ty: &hir::Type,
25+
) -> Option<ast::Expr> {
26+
match ty.as_adt() {
27+
Some(hir::Adt::Enum(x)) => {
28+
let variants = x.variants(db);
29+
30+
if variants.len() == 1 {
31+
let variant = variants[0];
32+
33+
if variant.fields(db).is_empty() {
34+
let path = ast::make::path_qualified(
35+
path,
36+
syntax::ast::make::path_segment(ast::make::name_ref(
37+
&variant.name(db).to_smol_str(),
38+
)),
39+
);
40+
41+
use hir::StructKind::*;
42+
let is_record = match variant.kind(db) {
43+
Record => true,
44+
Tuple => false,
45+
Unit => false,
46+
};
47+
48+
return Some(if is_record {
49+
ast::Expr::RecordExpr(syntax::ast::make::record_expr(
50+
path,
51+
ast::make::record_expr_field_list(std::iter::empty()),
52+
))
53+
} else {
54+
syntax::ast::make::expr_path(path)
55+
});
56+
}
57+
}
58+
}
59+
Some(hir::Adt::Struct(x)) => {
60+
let fields = x.fields(db);
61+
62+
if fields.is_empty() {
63+
return Some(syntax::ast::make::expr_path(path));
64+
}
65+
}
66+
_ => {}
67+
}
68+
69+
None
70+
}
71+
1772
// Diagnostic: missing-fields
1873
//
1974
// This diagnostic is triggered if record lacks some fields that exist in the corresponding structure.
@@ -55,6 +110,11 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
55110

56111
let root = ctx.sema.db.parse_or_expand(d.file)?;
57112

113+
let current_module = match &d.field_list_parent {
114+
Either::Left(ptr) => ctx.sema.scope(ptr.to_node(&root).syntax()).unwrap().module(),
115+
Either::Right(ptr) => ctx.sema.scope(ptr.to_node(&root).syntax()).unwrap().module(),
116+
};
117+
58118
let build_text_edit = |parent_syntax, new_syntax: &SyntaxNode, old_syntax| {
59119
let edit = {
60120
let mut builder = TextEdit::builder();
@@ -110,7 +170,26 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
110170
Some(generate_fill_expr(ty))
111171
}
112172
} else {
113-
Some(generate_fill_expr(ty))
173+
let expr = (|| -> Option<ast::Expr> {
174+
let item_in_ns = hir::ItemInNs::from(hir::ModuleDef::from(ty.as_adt()?));
175+
176+
let type_path = current_module.find_use_path(
177+
ctx.sema.db,
178+
item_for_path_search(ctx.sema.db, item_in_ns)?,
179+
)?;
180+
181+
use_trivial_constructor(
182+
&ctx.sema.db,
183+
ide_db::helpers::mod_path_to_ast(&type_path),
184+
&ty,
185+
)
186+
})();
187+
188+
if expr.is_some() {
189+
expr
190+
} else {
191+
Some(generate_fill_expr(ty))
192+
}
114193
};
115194
let field = make::record_expr_field(
116195
make::name_ref(&f.name(ctx.sema.db).to_smol_str()),

0 commit comments

Comments
 (0)