diff options
-rw-r--r-- | crates/ide_assists/src/handlers/generate_function.rs | 73 |
1 files changed, 47 insertions, 26 deletions
diff --git a/crates/ide_assists/src/handlers/generate_function.rs b/crates/ide_assists/src/handlers/generate_function.rs index fd4f2fbed..6f95b1a07 100644 --- a/crates/ide_assists/src/handlers/generate_function.rs +++ b/crates/ide_assists/src/handlers/generate_function.rs | |||
@@ -83,17 +83,18 @@ struct FunctionTemplate { | |||
83 | leading_ws: String, | 83 | leading_ws: String, |
84 | fn_def: ast::Fn, | 84 | fn_def: ast::Fn, |
85 | ret_type: ast::RetType, | 85 | ret_type: ast::RetType, |
86 | should_render_snippet: bool, | ||
86 | trailing_ws: String, | 87 | trailing_ws: String, |
87 | file: FileId, | 88 | file: FileId, |
88 | } | 89 | } |
89 | 90 | ||
90 | impl FunctionTemplate { | 91 | impl FunctionTemplate { |
91 | fn to_string(&self, cap: Option<SnippetCap>) -> String { | 92 | fn to_string(&self, cap: Option<SnippetCap>) -> String { |
92 | let f = match cap { | 93 | let f = match (cap, self.should_render_snippet) { |
93 | Some(cap) => { | 94 | (Some(cap), true) => { |
94 | render_snippet(cap, self.fn_def.syntax(), Cursor::Replace(self.ret_type.syntax())) | 95 | render_snippet(cap, self.fn_def.syntax(), Cursor::Replace(self.ret_type.syntax())) |
95 | } | 96 | } |
96 | None => self.fn_def.to_string(), | 97 | _ => self.fn_def.to_string(), |
97 | }; | 98 | }; |
98 | format!("{}{}{}", self.leading_ws, f, self.trailing_ws) | 99 | format!("{}{}{}", self.leading_ws, f, self.trailing_ws) |
99 | } | 100 | } |
@@ -104,7 +105,8 @@ struct FunctionBuilder { | |||
104 | fn_name: ast::Name, | 105 | fn_name: ast::Name, |
105 | type_params: Option<ast::GenericParamList>, | 106 | type_params: Option<ast::GenericParamList>, |
106 | params: ast::ParamList, | 107 | params: ast::ParamList, |
107 | ret_type: Option<ast::RetType>, | 108 | ret_type: ast::RetType, |
109 | should_render_snippet: bool, | ||
108 | file: FileId, | 110 | file: FileId, |
109 | needs_pub: bool, | 111 | needs_pub: bool, |
110 | } | 112 | } |
@@ -132,9 +134,44 @@ impl FunctionBuilder { | |||
132 | let target_module = target_module.or_else(|| ctx.sema.scope(target.syntax()).module())?; | 134 | let target_module = target_module.or_else(|| ctx.sema.scope(target.syntax()).module())?; |
133 | let fn_name = fn_name(&path)?; | 135 | let fn_name = fn_name(&path)?; |
134 | let (type_params, params) = fn_args(ctx, target_module, &call)?; | 136 | let (type_params, params) = fn_args(ctx, target_module, &call)?; |
135 | let ret_type = fn_ret_type(ctx, target_module, &call); | ||
136 | 137 | ||
137 | Some(Self { target, fn_name, type_params, params, ret_type, file, needs_pub }) | 138 | // should_render_snippet intends to express a rough level of confidence about |
139 | // the correctness of the return type. | ||
140 | // | ||
141 | // If we are able to infer some return type, and that return type is not unit, we | ||
142 | // don't want to render the snippet. The assumption here is in this situation the | ||
143 | // return type is just as likely to be correct as any other part of the generated | ||
144 | // function. | ||
145 | // | ||
146 | // In the case where the return type is inferred as unit it is likely that the | ||
147 | // user does in fact intend for this generated function to return some non unit | ||
148 | // type, but that the current state of their code doesn't allow that return type | ||
149 | // to be accurately inferred. | ||
150 | let (ret_ty, should_render_snippet) = { | ||
151 | match ctx.sema.type_of_expr(&ast::Expr::CallExpr(call.clone())) { | ||
152 | Some(ty) if ty.is_unknown() || ty.is_unit() => (make::ty_unit(), true), | ||
153 | Some(ty) => { | ||
154 | let rendered = ty.display_source_code(ctx.db(), target_module.into()); | ||
155 | match rendered { | ||
156 | Ok(rendered) => (make::ty(&rendered), false), | ||
157 | Err(_) => (make::ty_unit(), true), | ||
158 | } | ||
159 | } | ||
160 | None => (make::ty_unit(), true), | ||
161 | } | ||
162 | }; | ||
163 | let ret_type = make::ret_type(ret_ty); | ||
164 | |||
165 | Some(Self { | ||
166 | target, | ||
167 | fn_name, | ||
168 | type_params, | ||
169 | params, | ||
170 | ret_type, | ||
171 | should_render_snippet, | ||
172 | file, | ||
173 | needs_pub, | ||
174 | }) | ||
138 | } | 175 | } |
139 | 176 | ||
140 | fn render(self) -> FunctionTemplate { | 177 | fn render(self) -> FunctionTemplate { |
@@ -147,7 +184,7 @@ impl FunctionBuilder { | |||
147 | self.type_params, | 184 | self.type_params, |
148 | self.params, | 185 | self.params, |
149 | fn_body, | 186 | fn_body, |
150 | Some(self.ret_type.unwrap_or_else(|| make::ret_type(make::ty_unit()))), | 187 | Some(self.ret_type), |
151 | ); | 188 | ); |
152 | let leading_ws; | 189 | let leading_ws; |
153 | let trailing_ws; | 190 | let trailing_ws; |
@@ -173,6 +210,7 @@ impl FunctionBuilder { | |||
173 | insert_offset, | 210 | insert_offset, |
174 | leading_ws, | 211 | leading_ws, |
175 | ret_type: fn_def.ret_type().unwrap(), | 212 | ret_type: fn_def.ret_type().unwrap(), |
213 | should_render_snippet: self.should_render_snippet, | ||
176 | fn_def, | 214 | fn_def, |
177 | trailing_ws, | 215 | trailing_ws, |
178 | file: self.file, | 216 | file: self.file, |
@@ -225,23 +263,6 @@ fn fn_args( | |||
225 | Some((None, make::param_list(None, params))) | 263 | Some((None, make::param_list(None, params))) |
226 | } | 264 | } |
227 | 265 | ||
228 | fn fn_ret_type( | ||
229 | ctx: &AssistContext, | ||
230 | target_module: hir::Module, | ||
231 | call: &ast::CallExpr, | ||
232 | ) -> Option<ast::RetType> { | ||
233 | let ty = ctx.sema.type_of_expr(&ast::Expr::CallExpr(call.clone()))?; | ||
234 | if ty.is_unknown() { | ||
235 | return None; | ||
236 | } | ||
237 | |||
238 | if let Ok(rendered) = ty.display_source_code(ctx.db(), target_module.into()) { | ||
239 | Some(make::ret_type(make::ty(&rendered))) | ||
240 | } else { | ||
241 | None | ||
242 | } | ||
243 | } | ||
244 | |||
245 | /// Makes duplicate argument names unique by appending incrementing numbers. | 266 | /// Makes duplicate argument names unique by appending incrementing numbers. |
246 | /// | 267 | /// |
247 | /// ``` | 268 | /// ``` |
@@ -565,7 +586,7 @@ impl Baz { | |||
565 | } | 586 | } |
566 | } | 587 | } |
567 | 588 | ||
568 | fn bar(baz: Baz) ${0:-> Baz} { | 589 | fn bar(baz: Baz) -> Baz { |
569 | todo!() | 590 | todo!() |
570 | } | 591 | } |
571 | ", | 592 | ", |
@@ -1092,7 +1113,7 @@ fn main() { | |||
1092 | let x: u32 = foo(); | 1113 | let x: u32 = foo(); |
1093 | } | 1114 | } |
1094 | 1115 | ||
1095 | fn foo() ${0:-> u32} { | 1116 | fn foo() -> u32 { |
1096 | todo!() | 1117 | todo!() |
1097 | } | 1118 | } |
1098 | ", | 1119 | ", |