aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-10-08 19:14:52 +0100
committerAleksey Kladov <[email protected]>2019-10-08 19:14:52 +0100
commite0b1c17dcb367a3edfd9df4b1d7cfbcd059cd207 (patch)
tree416648fde13020d33d62068a5d52221c66c210b5 /crates
parentf4fa98b1bffe2200580506b83af5383555e1a958 (diff)
add `<>` when completing generic types
Diffstat (limited to 'crates')
-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.rs114
-rw-r--r--crates/ra_ide_api/src/marks.rs1
4 files changed, 198 insertions, 78 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 2d670372e..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};
@@ -150,7 +150,8 @@ impl Completions {
150 }) 150 })
151 .set_documentation(func.docs(ctx.db)) 151 .set_documentation(func.docs(ctx.db))
152 .detail(detail); 152 .detail(detail);
153 // If not an import, add parenthesis automatically. 153
154 // Add `<>` for generic types
154 if ctx.use_item_syntax.is_none() 155 if ctx.use_item_syntax.is_none()
155 && !ctx.is_call 156 && !ctx.is_call
156 && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis") 157 && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis")
@@ -164,11 +165,13 @@ impl Completions {
164 }; 165 };
165 builder = builder.insert_snippet(snippet); 166 builder = builder.insert_snippet(snippet);
166 } 167 }
168
167 self.add(builder) 169 self.add(builder)
168 } 170 }
169 171
170 fn add_adt_with_name(&mut self, ctx: &CompletionContext, name: String, adt: hir::Adt) { 172 fn add_adt_with_name(&mut self, ctx: &CompletionContext, name: String, adt: hir::Adt) {
171 let builder = CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name); 173 let mut builder =
174 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone());
172 175
173 let kind = match adt { 176 let kind = match adt {
174 hir::Adt::Struct(_) => CompletionItemKind::Struct, 177 hir::Adt::Struct(_) => CompletionItemKind::Struct,
@@ -178,6 +181,17 @@ impl Completions {
178 }; 181 };
179 let docs = adt.docs(ctx.db); 182 let docs = adt.docs(ctx.db);
180 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
181 builder.kind(kind).set_documentation(docs).add_to(self) 195 builder.kind(kind).set_documentation(docs).add_to(self)
182 } 196 }
183 197
@@ -221,7 +235,6 @@ impl Completions {
221 .separator(", ") 235 .separator(", ")
222 .surround_with("(", ")") 236 .surround_with("(", ")")
223 .to_string(); 237 .to_string();
224
225 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) 238 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
226 .kind(CompletionItemKind::EnumVariant) 239 .kind(CompletionItemKind::EnumVariant)
227 .set_documentation(variant.docs(ctx.db)) 240 .set_documentation(variant.docs(ctx.db))
@@ -230,6 +243,11 @@ impl Completions {
230 } 243 }
231} 244}
232 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
233#[cfg(test)] 251#[cfg(test)]
234mod tests { 252mod tests {
235 use crate::completion::{do_completion, CompletionItem, CompletionKind}; 253 use crate::completion::{do_completion, CompletionItem, CompletionKind};
@@ -397,4 +415,90 @@ mod tests {
397]"# 415]"#
398 ); 416 );
399 } 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 }
400} 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