diff options
Diffstat (limited to 'crates/ra_ide_api')
-rw-r--r-- | crates/ra_ide_api/src/completion/complete_scope.rs | 154 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/completion_context.rs | 7 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/presentation.rs | 114 | ||||
-rw-r--r-- | crates/ra_ide_api/src/marks.rs | 1 |
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 | ||
45 | impl<'a> CompletionContext<'a> { | 47 | impl<'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 | ||
3 | use hir::{Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; | 3 | use hir::{db::HirDatabase, Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; |
4 | use join_to_string::join; | 4 | use join_to_string::join; |
5 | use ra_syntax::ast::NameOwner; | 5 | use ra_syntax::ast::NameOwner; |
6 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
7 | 7 | ||
8 | use crate::completion::{ | 8 | use crate::completion::{ |
9 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, | 9 | db, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::display::{const_label, function_label, macro_label, type_label}; | 12 | use 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 | ||
246 | fn 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)] |
234 | mod tests { | 252 | mod 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 | ||
3 | test_utils::marks!( | 3 | test_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 |