aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-10-09 09:16:18 +0100
committerGitHub <[email protected]>2019-10-09 09:16:18 +0100
commitd5a6cac3357f22dea2e630e17d0f091988cdd558 (patch)
tree416648fde13020d33d62068a5d52221c66c210b5 /crates/ra_ide_api
parent06a8deae4a29949f438d66c54eed4e016ac35432 (diff)
parente0b1c17dcb367a3edfd9df4b1d7cfbcd059cd207 (diff)
Merge #1970
1970: Add <> when completing generics r=matklad a=matklad @flodiebold wdyt? Is it correct that we always need to add `<>` in generic types? Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_ide_api')
-rw-r--r--crates/ra_ide_api/src/completion/complete_scope.rs154
-rw-r--r--crates/ra_ide_api/src/completion/completion_context.rs7
-rw-r--r--crates/ra_ide_api/src/completion/presentation.rs136
-rw-r--r--crates/ra_ide_api/src/marks.rs1
4 files changed, 213 insertions, 85 deletions
diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs
index 38a6c3d37..84826cdcc 100644
--- a/crates/ra_ide_api/src/completion/complete_scope.rs
+++ b/crates/ra_ide_api/src/completion/complete_scope.rs
@@ -290,22 +290,24 @@ mod tests {
290 } 290 }
291 " 291 "
292 ), 292 ),
293 @r###"[ 293 @r###"
294 CompletionItem { 294 [
295 label: "T", 295 CompletionItem {
296 source_range: [54; 54), 296 label: "T",
297 delete: [54; 54), 297 source_range: [54; 54),
298 insert: "T", 298 delete: [54; 54),
299 kind: TypeParam, 299 insert: "T",
300 }, 300 kind: TypeParam,
301 CompletionItem { 301 },
302 label: "X", 302 CompletionItem {
303 source_range: [54; 54), 303 label: "X",
304 delete: [54; 54), 304 source_range: [54; 54),
305 insert: "X", 305 delete: [54; 54),
306 kind: Struct, 306 insert: "X<$0>",
307 }, 307 kind: Struct,
308]"### 308 },
309 ]
310 "###
309 ); 311 );
310 } 312 }
311 313
@@ -319,22 +321,24 @@ mod tests {
319 } 321 }
320 " 322 "
321 ), 323 ),
322 @r###"[ 324 @r###"
323 CompletionItem { 325 [
324 label: "Self", 326 CompletionItem {
325 source_range: [48; 48), 327 label: "Self",
326 delete: [48; 48), 328 source_range: [48; 48),
327 insert: "Self", 329 delete: [48; 48),
328 kind: TypeParam, 330 insert: "Self",
329 }, 331 kind: TypeParam,
330 CompletionItem { 332 },
331 label: "X", 333 CompletionItem {
332 source_range: [48; 48), 334 label: "X",
333 delete: [48; 48), 335 source_range: [48; 48),
334 insert: "X", 336 delete: [48; 48),
335 kind: Enum, 337 insert: "X",
336 }, 338 kind: Enum,
337]"### 339 },
340 ]
341 "###
338 ); 342 );
339 } 343 }
340 344
@@ -442,23 +446,25 @@ mod tests {
442 fn x() -> <|> 446 fn x() -> <|>
443 " 447 "
444 ), 448 ),
445 @r###"[ 449 @r###"
446 CompletionItem { 450 [
447 label: "Foo", 451 CompletionItem {
448 source_range: [55; 55), 452 label: "Foo",
449 delete: [55; 55), 453 source_range: [55; 55),
450 insert: "Foo", 454 delete: [55; 55),
451 kind: Struct, 455 insert: "Foo",
452 }, 456 kind: Struct,
453 CompletionItem { 457 },
454 label: "x", 458 CompletionItem {
455 source_range: [55; 55), 459 label: "x",
456 delete: [55; 55), 460 source_range: [55; 55),
457 insert: "x()$0", 461 delete: [55; 55),
458 kind: Function, 462 insert: "x()$0",
459 detail: "fn x()", 463 kind: Function,
460 }, 464 detail: "fn x()",
461]"### 465 },
466 ]
467 "###
462 ); 468 );
463 } 469 }
464 470
@@ -538,30 +544,32 @@ mod tests {
538 } 544 }
539 " 545 "
540 ), 546 ),
541 @r#"[ 547 @r###"
542 CompletionItem { 548 [
543 label: "Option", 549 CompletionItem {
544 source_range: [18; 18), 550 label: "Option",
545 delete: [18; 18), 551 source_range: [18; 18),
546 insert: "Option", 552 delete: [18; 18),
547 kind: Struct, 553 insert: "Option",
548 }, 554 kind: Struct,
549 CompletionItem { 555 },
550 label: "foo", 556 CompletionItem {
551 source_range: [18; 18), 557 label: "foo",
552 delete: [18; 18), 558 source_range: [18; 18),
553 insert: "foo()$0", 559 delete: [18; 18),
554 kind: Function, 560 insert: "foo()$0",
555 detail: "fn foo()", 561 kind: Function,
556 }, 562 detail: "fn foo()",
557 CompletionItem { 563 },
558 label: "std", 564 CompletionItem {
559 source_range: [18; 18), 565 label: "std",
560 delete: [18; 18), 566 source_range: [18; 18),
561 insert: "std", 567 delete: [18; 18),
562 kind: Module, 568 insert: "std",
563 }, 569 kind: Module,
564]"# 570 },
571 ]
572 "###
565 ); 573 );
566 } 574 }
567 575
diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs
index e9ad06965..73f3f3960 100644
--- a/crates/ra_ide_api/src/completion/completion_context.rs
+++ b/crates/ra_ide_api/src/completion/completion_context.rs
@@ -40,6 +40,8 @@ pub(crate) struct CompletionContext<'a> {
40 pub(super) dot_receiver: Option<ast::Expr>, 40 pub(super) dot_receiver: Option<ast::Expr>,
41 /// If this is a call (method or function) in particular, i.e. the () are already there. 41 /// If this is a call (method or function) in particular, i.e. the () are already there.
42 pub(super) is_call: bool, 42 pub(super) is_call: bool,
43 pub(super) is_path_type: bool,
44 pub(super) has_type_args: bool,
43} 45}
44 46
45impl<'a> CompletionContext<'a> { 47impl<'a> CompletionContext<'a> {
@@ -76,6 +78,8 @@ impl<'a> CompletionContext<'a> {
76 is_new_item: false, 78 is_new_item: false,
77 dot_receiver: None, 79 dot_receiver: None,
78 is_call: false, 80 is_call: false,
81 is_path_type: false,
82 has_type_args: false,
79 }; 83 };
80 ctx.fill(&original_parse, position.offset); 84 ctx.fill(&original_parse, position.offset);
81 Some(ctx) 85 Some(ctx)
@@ -176,6 +180,9 @@ impl<'a> CompletionContext<'a> {
176 .and_then(|it| it.syntax().parent().and_then(ast::CallExpr::cast)) 180 .and_then(|it| it.syntax().parent().and_then(ast::CallExpr::cast))
177 .is_some(); 181 .is_some();
178 182
183 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some();
184 self.has_type_args = segment.type_arg_list().is_some();
185
179 if let Some(mut path) = hir::Path::from_ast(path.clone()) { 186 if let Some(mut path) = hir::Path::from_ast(path.clone()) {
180 if !path.is_ident() { 187 if !path.is_ident() {
181 path.segments.pop().unwrap(); 188 path.segments.pop().unwrap();
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs
index eb480a775..400a266a2 100644
--- a/crates/ra_ide_api/src/completion/presentation.rs
+++ b/crates/ra_ide_api/src/completion/presentation.rs
@@ -1,12 +1,12 @@
1//! This modules takes care of rendering various definitions as completion items. 1//! This modules takes care of rendering various definitions as completion items.
2 2
3use hir::{Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; 3use hir::{db::HirDatabase, Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk};
4use join_to_string::join; 4use join_to_string::join;
5use ra_syntax::ast::NameOwner; 5use ra_syntax::ast::NameOwner;
6use test_utils::tested_by; 6use test_utils::tested_by;
7 7
8use crate::completion::{ 8use crate::completion::{
9 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, 9 db, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
10}; 10};
11 11
12use crate::display::{const_label, function_label, macro_label, type_label}; 12use crate::display::{const_label, function_label, macro_label, type_label};
@@ -50,14 +50,8 @@ impl Completions {
50 ScopeDef::ModuleDef(Function(func)) => { 50 ScopeDef::ModuleDef(Function(func)) => {
51 return self.add_function_with_name(ctx, Some(local_name), *func); 51 return self.add_function_with_name(ctx, Some(local_name), *func);
52 } 52 }
53 ScopeDef::ModuleDef(Adt(hir::Adt::Struct(it))) => { 53 ScopeDef::ModuleDef(Adt(adt)) => {
54 (CompletionItemKind::Struct, it.docs(ctx.db)) 54 return self.add_adt_with_name(ctx, local_name, *adt);
55 }
56 ScopeDef::ModuleDef(Adt(hir::Adt::Union(it))) => {
57 (CompletionItemKind::Struct, it.docs(ctx.db))
58 }
59 ScopeDef::ModuleDef(Adt(hir::Adt::Enum(it))) => {
60 (CompletionItemKind::Enum, it.docs(ctx.db))
61 } 55 }
62 ScopeDef::ModuleDef(EnumVariant(it)) => { 56 ScopeDef::ModuleDef(EnumVariant(it)) => {
63 (CompletionItemKind::EnumVariant, it.docs(ctx.db)) 57 (CompletionItemKind::EnumVariant, it.docs(ctx.db))
@@ -156,7 +150,8 @@ impl Completions {
156 }) 150 })
157 .set_documentation(func.docs(ctx.db)) 151 .set_documentation(func.docs(ctx.db))
158 .detail(detail); 152 .detail(detail);
159 // If not an import, add parenthesis automatically. 153
154 // Add `<>` for generic types
160 if ctx.use_item_syntax.is_none() 155 if ctx.use_item_syntax.is_none()
161 && !ctx.is_call 156 && !ctx.is_call
162 && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis") 157 && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis")
@@ -170,9 +165,36 @@ impl Completions {
170 }; 165 };
171 builder = builder.insert_snippet(snippet); 166 builder = builder.insert_snippet(snippet);
172 } 167 }
168
173 self.add(builder) 169 self.add(builder)
174 } 170 }
175 171
172 fn add_adt_with_name(&mut self, ctx: &CompletionContext, name: String, adt: hir::Adt) {
173 let mut builder =
174 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone());
175
176 let kind = match adt {
177 hir::Adt::Struct(_) => CompletionItemKind::Struct,
178 // FIXME: add CompletionItemKind::Union
179 hir::Adt::Union(_) => CompletionItemKind::Struct,
180 hir::Adt::Enum(_) => CompletionItemKind::Enum,
181 };
182 let docs = adt.docs(ctx.db);
183
184 // If not an import, add parenthesis automatically.
185 if ctx.is_path_type
186 && !ctx.has_type_args
187 && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis")
188 {
189 if has_non_default_type_params(adt, ctx.db) {
190 tested_by!(inserts_angle_brackets_for_generics);
191 builder = builder.insert_snippet(format!("{}<$0>", name));
192 }
193 }
194
195 builder.kind(kind).set_documentation(docs).add_to(self)
196 }
197
176 pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { 198 pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) {
177 let ast_node = constant.source(ctx.db).ast; 199 let ast_node = constant.source(ctx.db).ast;
178 let name = match ast_node.name() { 200 let name = match ast_node.name() {
@@ -213,7 +235,6 @@ impl Completions {
213 .separator(", ") 235 .separator(", ")
214 .surround_with("(", ")") 236 .surround_with("(", ")")
215 .to_string(); 237 .to_string();
216
217 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) 238 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
218 .kind(CompletionItemKind::EnumVariant) 239 .kind(CompletionItemKind::EnumVariant)
219 .set_documentation(variant.docs(ctx.db)) 240 .set_documentation(variant.docs(ctx.db))
@@ -222,6 +243,11 @@ impl Completions {
222 } 243 }
223} 244}
224 245
246fn has_non_default_type_params(adt: hir::Adt, db: &db::RootDatabase) -> bool {
247 let subst = db.generic_defaults(adt.into());
248 subst.iter().any(|ty| ty == &Ty::Unknown)
249}
250
225#[cfg(test)] 251#[cfg(test)]
226mod tests { 252mod tests {
227 use crate::completion::{do_completion, CompletionItem, CompletionKind}; 253 use crate::completion::{do_completion, CompletionItem, CompletionKind};
@@ -389,4 +415,90 @@ mod tests {
389]"# 415]"#
390 ); 416 );
391 } 417 }
418
419 #[test]
420 fn inserts_angle_brackets_for_generics() {
421 covers!(inserts_angle_brackets_for_generics);
422 assert_debug_snapshot!(
423 do_reference_completion(
424 r"
425 struct Vec<T> {}
426 fn foo(xs: Ve<|>)
427 "
428 ),
429 @r###"
430 [
431 CompletionItem {
432 label: "Vec",
433 source_range: [61; 63),
434 delete: [61; 63),
435 insert: "Vec<$0>",
436 kind: Struct,
437 },
438 CompletionItem {
439 label: "foo",
440 source_range: [61; 63),
441 delete: [61; 63),
442 insert: "foo($0)",
443 kind: Function,
444 detail: "fn foo(xs: Ve)",
445 },
446 ]
447 "###
448 );
449 assert_debug_snapshot!(
450 do_reference_completion(
451 r"
452 struct Vec<T = i128> {}
453 fn foo(xs: Ve<|>)
454 "
455 ),
456 @r###"
457 [
458 CompletionItem {
459 label: "Vec",
460 source_range: [68; 70),
461 delete: [68; 70),
462 insert: "Vec",
463 kind: Struct,
464 },
465 CompletionItem {
466 label: "foo",
467 source_range: [68; 70),
468 delete: [68; 70),
469 insert: "foo($0)",
470 kind: Function,
471 detail: "fn foo(xs: Ve)",
472 },
473 ]
474 "###
475 );
476 assert_debug_snapshot!(
477 do_reference_completion(
478 r"
479 struct Vec<T> {}
480 fn foo(xs: Ve<|><i128>)
481 "
482 ),
483 @r###"
484 [
485 CompletionItem {
486 label: "Vec",
487 source_range: [61; 63),
488 delete: [61; 63),
489 insert: "Vec",
490 kind: Struct,
491 },
492 CompletionItem {
493 label: "foo",
494 source_range: [61; 63),
495 delete: [61; 63),
496 insert: "foo($0)",
497 kind: Function,
498 detail: "fn foo(xs: Ve<i128>)",
499 },
500 ]
501 "###
502 );
503 }
392} 504}
diff --git a/crates/ra_ide_api/src/marks.rs b/crates/ra_ide_api/src/marks.rs
index 3f4ba248b..848ae4dc7 100644
--- a/crates/ra_ide_api/src/marks.rs
+++ b/crates/ra_ide_api/src/marks.rs
@@ -1,6 +1,7 @@
1//! See test_utils/src/marks.rs 1//! See test_utils/src/marks.rs
2 2
3test_utils::marks!( 3test_utils::marks!(
4 inserts_angle_brackets_for_generics
4 inserts_parens_for_function_calls 5 inserts_parens_for_function_calls
5 goto_definition_works_for_macros 6 goto_definition_works_for_macros
6 goto_definition_works_for_methods 7 goto_definition_works_for_methods