aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ide_assists/src/handlers/generate_function.rs73
-rw-r--r--crates/ide_completion/src/completions/postfix.rs14
-rw-r--r--docs/dev/lsp-extensions.md20
3 files changed, 91 insertions, 16 deletions
diff --git a/crates/ide_assists/src/handlers/generate_function.rs b/crates/ide_assists/src/handlers/generate_function.rs
index 3870b7e75..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
90impl FunctionTemplate { 91impl 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,6 +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,
108 ret_type: ast::RetType,
109 should_render_snippet: bool,
107 file: FileId, 110 file: FileId,
108 needs_pub: bool, 111 needs_pub: bool,
109} 112}
@@ -132,7 +135,43 @@ impl FunctionBuilder {
132 let fn_name = fn_name(&path)?; 135 let fn_name = fn_name(&path)?;
133 let (type_params, params) = fn_args(ctx, target_module, &call)?; 136 let (type_params, params) = fn_args(ctx, target_module, &call)?;
134 137
135 Some(Self { target, fn_name, type_params, params, 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 })
136 } 175 }
137 176
138 fn render(self) -> FunctionTemplate { 177 fn render(self) -> FunctionTemplate {
@@ -145,7 +184,7 @@ impl FunctionBuilder {
145 self.type_params, 184 self.type_params,
146 self.params, 185 self.params,
147 fn_body, 186 fn_body,
148 Some(make::ret_type(make::ty_unit())), 187 Some(self.ret_type),
149 ); 188 );
150 let leading_ws; 189 let leading_ws;
151 let trailing_ws; 190 let trailing_ws;
@@ -171,6 +210,7 @@ impl FunctionBuilder {
171 insert_offset, 210 insert_offset,
172 leading_ws, 211 leading_ws,
173 ret_type: fn_def.ret_type().unwrap(), 212 ret_type: fn_def.ret_type().unwrap(),
213 should_render_snippet: self.should_render_snippet,
174 fn_def, 214 fn_def,
175 trailing_ws, 215 trailing_ws,
176 file: self.file, 216 file: self.file,
@@ -546,7 +586,7 @@ impl Baz {
546 } 586 }
547} 587}
548 588
549fn bar(baz: Baz) ${0:-> ()} { 589fn bar(baz: Baz) -> Baz {
550 todo!() 590 todo!()
551} 591}
552", 592",
@@ -1060,6 +1100,27 @@ pub(crate) fn bar() ${0:-> ()} {
1060 } 1100 }
1061 1101
1062 #[test] 1102 #[test]
1103 fn add_function_with_return_type() {
1104 check_assist(
1105 generate_function,
1106 r"
1107fn main() {
1108 let x: u32 = foo$0();
1109}
1110",
1111 r"
1112fn main() {
1113 let x: u32 = foo();
1114}
1115
1116fn foo() -> u32 {
1117 todo!()
1118}
1119",
1120 )
1121 }
1122
1123 #[test]
1063 fn add_function_not_applicable_if_function_already_exists() { 1124 fn add_function_not_applicable_if_function_already_exists() {
1064 check_assist_not_applicable( 1125 check_assist_not_applicable(
1065 generate_function, 1126 generate_function,
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs
index 9c34ed0b6..d45ad7944 100644
--- a/crates/ide_completion/src/completions/postfix.rs
+++ b/crates/ide_completion/src/completions/postfix.rs
@@ -187,6 +187,16 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
187 ctx, 187 ctx,
188 cap, 188 cap,
189 &dot_receiver, 189 &dot_receiver,
190 "err",
191 "Err(expr)",
192 &format!("Err({})", receiver_text),
193 )
194 .add_to(acc);
195
196 postfix_snippet(
197 ctx,
198 cap,
199 &dot_receiver,
190 "some", 200 "some",
191 "Some(expr)", 201 "Some(expr)",
192 &format!("Some({})", receiver_text), 202 &format!("Some({})", receiver_text),
@@ -325,6 +335,7 @@ fn main() {
325 sn match match expr {} 335 sn match match expr {}
326 sn box Box::new(expr) 336 sn box Box::new(expr)
327 sn ok Ok(expr) 337 sn ok Ok(expr)
338 sn err Err(expr)
328 sn some Some(expr) 339 sn some Some(expr)
329 sn dbg dbg!(expr) 340 sn dbg dbg!(expr)
330 sn dbgr dbg!(&expr) 341 sn dbgr dbg!(&expr)
@@ -357,6 +368,7 @@ fn main() {
357 sn match match expr {} 368 sn match match expr {}
358 sn box Box::new(expr) 369 sn box Box::new(expr)
359 sn ok Ok(expr) 370 sn ok Ok(expr)
371 sn err Err(expr)
360 sn some Some(expr) 372 sn some Some(expr)
361 sn dbg dbg!(expr) 373 sn dbg dbg!(expr)
362 sn dbgr dbg!(&expr) 374 sn dbgr dbg!(&expr)
@@ -380,6 +392,7 @@ fn main() {
380 sn match match expr {} 392 sn match match expr {}
381 sn box Box::new(expr) 393 sn box Box::new(expr)
382 sn ok Ok(expr) 394 sn ok Ok(expr)
395 sn err Err(expr)
383 sn some Some(expr) 396 sn some Some(expr)
384 sn dbg dbg!(expr) 397 sn dbg dbg!(expr)
385 sn dbgr dbg!(&expr) 398 sn dbgr dbg!(&expr)
@@ -408,6 +421,7 @@ fn main() {
408 sn match match expr {} 421 sn match match expr {}
409 sn box Box::new(expr) 422 sn box Box::new(expr)
410 sn ok Ok(expr) 423 sn ok Ok(expr)
424 sn err Err(expr)
411 sn some Some(expr) 425 sn some Some(expr)
412 sn dbg dbg!(expr) 426 sn dbg dbg!(expr)
413 sn dbgr dbg!(&expr) 427 sn dbgr dbg!(&expr)
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index 164c8482e..dd3ecc18d 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -39,7 +39,7 @@ If a language client does not know about `rust-analyzer`'s configuration options
39 39
40**Issue:** https://github.com/microsoft/language-server-protocol/issues/724 40**Issue:** https://github.com/microsoft/language-server-protocol/issues/724
41 41
42**Client Capability:** `{ "snippetTextEdit": boolean }` 42**Experimental Client Capability:** `{ "snippetTextEdit": boolean }`
43 43
44If this capability is set, `WorkspaceEdit`s returned from `codeAction` requests might contain `SnippetTextEdit`s instead of usual `TextEdit`s: 44If this capability is set, `WorkspaceEdit`s returned from `codeAction` requests might contain `SnippetTextEdit`s instead of usual `TextEdit`s:
45 45
@@ -72,7 +72,7 @@ At the moment, rust-analyzer guarantees that only a single edit will have `Inser
72 72
73**Issue:** https://github.com/microsoft/language-server-protocol/issues/994 73**Issue:** https://github.com/microsoft/language-server-protocol/issues/994
74 74
75**Client Capability:** `{ "codeActionGroup": boolean }` 75**Experimental Client Capability:** `{ "codeActionGroup": boolean }`
76 76
77If this capability is set, `CodeAction` returned from the server contain an additional field, `group`: 77If this capability is set, `CodeAction` returned from the server contain an additional field, `group`:
78 78
@@ -119,7 +119,7 @@ Invoking code action at this position will yield two code actions for importing
119 119
120**Issue:** https://github.com/microsoft/language-server-protocol/issues/1002 120**Issue:** https://github.com/microsoft/language-server-protocol/issues/1002
121 121
122**Server Capability:** `{ "parentModule": boolean }` 122**Experimental Server Capability:** `{ "parentModule": boolean }`
123 123
124This request is sent from client to server to handle "Goto Parent Module" editor action. 124This request is sent from client to server to handle "Goto Parent Module" editor action.
125 125
@@ -153,7 +153,7 @@ mod foo;
153 153
154**Issue:** https://github.com/microsoft/language-server-protocol/issues/992 154**Issue:** https://github.com/microsoft/language-server-protocol/issues/992
155 155
156**Server Capability:** `{ "joinLines": boolean }` 156**Experimental Server Capability:** `{ "joinLines": boolean }`
157 157
158This request is sent from client to server to handle "Join Lines" editor action. 158This request is sent from client to server to handle "Join Lines" editor action.
159 159
@@ -200,7 +200,7 @@ fn main() {
200 200
201**Issue:** https://github.com/microsoft/language-server-protocol/issues/1001 201**Issue:** https://github.com/microsoft/language-server-protocol/issues/1001
202 202
203**Server Capability:** `{ "onEnter": boolean }` 203**Experimental Server Capability:** `{ "onEnter": boolean }`
204 204
205This request is sent from client to server to handle <kbd>Enter</kbd> keypress. 205This request is sent from client to server to handle <kbd>Enter</kbd> keypress.
206 206
@@ -251,7 +251,7 @@ As proper cursor positioning is raison-d'etat for `onEnter`, it uses `SnippetTex
251 251
252## Structural Search Replace (SSR) 252## Structural Search Replace (SSR)
253 253
254**Server Capability:** `{ "ssr": boolean }` 254**Experimental Server Capability:** `{ "ssr": boolean }`
255 255
256This request is sent from client to server to handle structural search replace -- automated syntax tree based transformation of the source. 256This request is sent from client to server to handle structural search replace -- automated syntax tree based transformation of the source.
257 257
@@ -293,7 +293,7 @@ SSR with query `foo($a, $b) ==>> ($a).foo($b)` will transform, eg `foo(y + 5, z)
293 293
294**Issue:** https://github.com/microsoft/language-server-protocol/issues/999 294**Issue:** https://github.com/microsoft/language-server-protocol/issues/999
295 295
296**Server Capability:** `{ "matchingBrace": boolean }` 296**Experimental Server Capability:** `{ "matchingBrace": boolean }`
297 297
298This request is sent from client to server to handle "Matching Brace" editor action. 298This request is sent from client to server to handle "Matching Brace" editor action.
299 299
@@ -338,7 +338,7 @@ Moreover, it would be cool if editors didn't need to implement even basic langua
338 338
339**Issue:** https://github.com/microsoft/language-server-protocol/issues/944 339**Issue:** https://github.com/microsoft/language-server-protocol/issues/944
340 340
341**Server Capability:** `{ "runnables": { "kinds": string[] } }` 341**Experimental Server Capability:** `{ "runnables": { "kinds": string[] } }`
342 342
343This request is sent from client to server to get the list of things that can be run (tests, binaries, `cargo check -p`). 343This request is sent from client to server to get the list of things that can be run (tests, binaries, `cargo check -p`).
344 344
@@ -421,7 +421,7 @@ Reloads project information (that is, re-executes `cargo metadata`).
421 421
422## Status Notification 422## Status Notification
423 423
424**Client Capability:** `{ "statusNotification": boolean }` 424**Experimental Client Capability:** `{ "statusNotification": boolean }`
425 425
426**Method:** `rust-analyzer/status` 426**Method:** `rust-analyzer/status`
427 427
@@ -519,7 +519,7 @@ interface InlayHint {
519 519
520## Hover Actions 520## Hover Actions
521 521
522**Client Capability:** `{ "hoverActions": boolean }` 522**Experimental Client Capability:** `{ "hoverActions": boolean }`
523 523
524If this capability is set, `Hover` request returned from the server might contain an additional field, `actions`: 524If this capability is set, `Hover` request returned from the server might contain an additional field, `actions`:
525 525