aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/assists/add_new.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/assists/add_new.rs')
-rw-r--r--crates/ra_assists/src/assists/add_new.rs86
1 files changed, 40 insertions, 46 deletions
diff --git a/crates/ra_assists/src/assists/add_new.rs b/crates/ra_assists/src/assists/add_new.rs
index 8f68bd5fb..b2f946fac 100644
--- a/crates/ra_assists/src/assists/add_new.rs
+++ b/crates/ra_assists/src/assists/add_new.rs
@@ -1,5 +1,5 @@
1use format_buf::format; 1use format_buf::format;
2use hir::{db::HirDatabase, FromSource}; 2use hir::{db::HirDatabase, FromSource, InFile};
3use join_to_string::join; 3use join_to_string::join;
4use ra_syntax::{ 4use ra_syntax::{
5 ast::{ 5 ast::{
@@ -56,42 +56,39 @@ pub(crate) fn add_new(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
56 let vis = vis.as_ref().map(String::as_str).unwrap_or(""); 56 let vis = vis.as_ref().map(String::as_str).unwrap_or("");
57 write!(&mut buf, " {}fn new(", vis).unwrap(); 57 write!(&mut buf, " {}fn new(", vis).unwrap();
58 58
59 join(field_list.fields().map(|f| { 59 join(field_list.fields().filter_map(|f| {
60 format!( 60 Some(format!("{}: {}", f.name()?.syntax().text(), f.ascribed_type()?.syntax().text()))
61 "{}: {}",
62 f.name().unwrap().syntax().text(),
63 f.ascribed_type().unwrap().syntax().text()
64 )
65 })) 61 }))
66 .separator(", ") 62 .separator(", ")
67 .to_buf(&mut buf); 63 .to_buf(&mut buf);
68 64
69 buf.push_str(") -> Self { Self {"); 65 buf.push_str(") -> Self { Self {");
70 66
71 join(field_list.fields().map(|f| f.name().unwrap().syntax().text())) 67 join(field_list.fields().filter_map(|f| Some(f.name()?.syntax().text())))
72 .separator(", ") 68 .separator(", ")
73 .surround_with(" ", " ") 69 .surround_with(" ", " ")
74 .to_buf(&mut buf); 70 .to_buf(&mut buf);
75 71
76 buf.push_str("} }"); 72 buf.push_str("} }");
77 73
78 let (start_offset, end_offset) = if let Some(impl_block) = impl_block { 74 let (start_offset, end_offset) = impl_block
79 buf.push('\n'); 75 .and_then(|impl_block| {
80 let start = impl_block 76 buf.push('\n');
81 .syntax() 77 let start = impl_block
82 .descendants_with_tokens() 78 .syntax()
83 .find(|t| t.kind() == T!['{']) 79 .descendants_with_tokens()
84 .unwrap() 80 .find(|t| t.kind() == T!['{'])?
85 .text_range() 81 .text_range()
86 .end(); 82 .end();
87 83
88 (start, TextUnit::from_usize(1)) 84 Some((start, TextUnit::from_usize(1)))
89 } else { 85 })
90 buf = generate_impl_text(&strukt, &buf); 86 .unwrap_or_else(|| {
91 let start = strukt.syntax().text_range().end(); 87 buf = generate_impl_text(&strukt, &buf);
92 88 let start = strukt.syntax().text_range().end();
93 (start, TextUnit::from_usize(3)) 89
94 }; 90 (start, TextUnit::from_usize(3))
91 });
95 92
96 edit.set_cursor(start_offset + TextUnit::of_str(&buf) - end_offset); 93 edit.set_cursor(start_offset + TextUnit::of_str(&buf) - end_offset);
97 edit.insert(start_offset, buf); 94 edit.insert(start_offset, buf);
@@ -141,44 +138,41 @@ fn find_struct_impl(
141 })?; 138 })?;
142 139
143 let struct_ty = { 140 let struct_ty = {
144 let src = hir::Source { file_id: ctx.frange.file_id.into(), value: strukt.clone() }; 141 let src = InFile { file_id: ctx.frange.file_id.into(), value: strukt.clone() };
145 hir::Struct::from_source(db, src).unwrap().ty(db) 142 hir::Struct::from_source(db, src)?.ty(db)
146 }; 143 };
147 144
148 let mut found_new_fn = false; 145 let block = module.descendants().filter_map(ast::ImplBlock::cast).find_map(|impl_blk| {
149 146 let src = InFile { file_id: ctx.frange.file_id.into(), value: impl_blk.clone() };
150 let block = module.descendants().filter_map(ast::ImplBlock::cast).find(|impl_blk| { 147 let blk = hir::ImplBlock::from_source(db, src)?;
151 if found_new_fn {
152 return false;
153 }
154
155 let src = hir::Source { file_id: ctx.frange.file_id.into(), value: impl_blk.clone() };
156 let blk = hir::ImplBlock::from_source(db, src).unwrap();
157 148
158 let same_ty = blk.target_ty(db) == struct_ty; 149 let same_ty = blk.target_ty(db) == struct_ty;
159 let not_trait_impl = blk.target_trait(db).is_none(); 150 let not_trait_impl = blk.target_trait(db).is_none();
160 151
161 if !(same_ty && not_trait_impl) { 152 if !(same_ty && not_trait_impl) {
162 return false; 153 None
154 } else {
155 Some(impl_blk)
163 } 156 }
164
165 found_new_fn = has_new_fn(impl_blk);
166 true
167 }); 157 });
168 158
169 if found_new_fn { 159 if let Some(ref impl_blk) = block {
170 None 160 if has_new_fn(impl_blk) {
171 } else { 161 return None;
172 Some(block) 162 }
173 } 163 }
164
165 Some(block)
174} 166}
175 167
176fn has_new_fn(imp: &ast::ImplBlock) -> bool { 168fn has_new_fn(imp: &ast::ImplBlock) -> bool {
177 if let Some(il) = imp.item_list() { 169 if let Some(il) = imp.item_list() {
178 for item in il.impl_items() { 170 for item in il.impl_items() {
179 if let ast::ImplItem::FnDef(f) = item { 171 if let ast::ImplItem::FnDef(f) = item {
180 if f.name().unwrap().text().eq_ignore_ascii_case("new") { 172 if let Some(name) = f.name() {
181 return true; 173 if name.text().eq_ignore_ascii_case("new") {
174 return true;
175 }
182 } 176 }
183 } 177 }
184 } 178 }