1 //! This module provides primitives for showing type and function parameter information when editing
2 //! a call or use-site.
4 use std
::collections
::BTreeSet
;
8 AssocItem
, DescendPreference
, GenericParam
, HirDisplay
, ModuleDef
, PathResolution
, Semantics
,
12 active_parameter
::{callable_for_node, generic_def_for_node}
,
13 base_db
::FilePosition
,
14 documentation
::{Documentation, HasDocs}
,
20 ast
::{self, AstChildren, HasArgList}
,
21 match_ast
, AstNode
, Direction
, NodeOrToken
, SyntaxElementChildren
, SyntaxNode
, SyntaxToken
,
22 TextRange
, TextSize
, T
,
25 use crate::RootDatabase
;
27 /// Contains information about an item signature as seen from a use site.
29 /// This includes the "active parameter", which is the parameter whose value is currently being
32 pub struct SignatureHelp
{
33 pub doc
: Option
<Documentation
>,
34 pub signature
: String
,
35 pub active_parameter
: Option
<usize>,
36 parameters
: Vec
<TextRange
>,
40 pub fn parameter_labels(&self) -> impl Iterator
<Item
= &str> + '_
{
41 self.parameters
.iter().map(move |&it
| &self.signature
[it
])
44 pub fn parameter_ranges(&self) -> &[TextRange
] {
48 fn push_call_param(&mut self, param
: &str) {
49 self.push_param("(", param
);
52 fn push_generic_param(&mut self, param
: &str) {
53 self.push_param("<", param
);
56 fn push_record_field(&mut self, param
: &str) {
57 self.push_param("{ ", param
);
60 fn push_param(&mut self, opening_delim
: &str, param
: &str) {
61 if !self.signature
.ends_with(opening_delim
) {
62 self.signature
.push_str(", ");
64 let start
= TextSize
::of(&self.signature
);
65 self.signature
.push_str(param
);
66 let end
= TextSize
::of(&self.signature
);
67 self.parameters
.push(TextRange
::new(start
, end
))
71 /// Computes parameter information for the given position.
72 pub(crate) fn signature_help(
74 FilePosition { file_id, offset }
: FilePosition
,
75 ) -> Option
<SignatureHelp
> {
76 let sema
= Semantics
::new(db
);
77 let file
= sema
.parse(file_id
);
78 let file
= file
.syntax();
80 .token_at_offset(offset
)
82 // if the cursor is sandwiched between two space tokens and the call is unclosed
83 // this prevents us from leaving the CallExpression
84 .and_then(|tok
| algo
::skip_trivia_token(tok
, Direction
::Prev
))?
;
85 let token
= sema
.descend_into_macros_single(DescendPreference
::None
, token
);
87 for node
in token
.parent_ancestors() {
90 ast
::ArgList(arg_list
) => {
91 let cursor_outside
= arg_list
.r_paren_token().as_ref() == Some(&token
);
95 return signature_help_for_call(&sema
, arg_list
, token
);
97 ast
::GenericArgList(garg_list
) => {
98 let cursor_outside
= garg_list
.r_angle_token().as_ref() == Some(&token
);
102 return signature_help_for_generics(&sema
, garg_list
, token
);
104 ast
::RecordExpr(record
) => {
105 let cursor_outside
= record
.record_expr_field_list().and_then(|list
| list
.r_curly_token()).as_ref() == Some(&token
);
109 return signature_help_for_record_lit(&sema
, record
, token
);
111 ast
::RecordPat(record
) => {
112 let cursor_outside
= record
.record_pat_field_list().and_then(|list
| list
.r_curly_token()).as_ref() == Some(&token
);
116 return signature_help_for_record_pat(&sema
, record
, token
);
118 ast
::TupleStructPat(tuple_pat
) => {
119 let cursor_outside
= tuple_pat
.r_paren_token().as_ref() == Some(&token
);
123 return signature_help_for_tuple_struct_pat(&sema
, tuple_pat
, token
);
125 ast
::TuplePat(tuple_pat
) => {
126 let cursor_outside
= tuple_pat
.r_paren_token().as_ref() == Some(&token
);
130 return signature_help_for_tuple_pat(&sema
, tuple_pat
, token
);
132 ast
::TupleExpr(tuple_expr
) => {
133 let cursor_outside
= tuple_expr
.r_paren_token().as_ref() == Some(&token
);
137 return signature_help_for_tuple_expr(&sema
, tuple_expr
, token
);
143 // Stop at multi-line expressions, since the signature of the outer call is not very
144 // helpful inside them.
145 if let Some(expr
) = ast
::Expr
::cast(node
.clone()) {
146 if !matches
!(expr
, ast
::Expr
::RecordExpr(..))
147 && expr
.syntax().text().contains_char('
\n'
)
157 fn signature_help_for_call(
158 sema
: &Semantics
<'_
, RootDatabase
>,
159 arg_list
: ast
::ArgList
,
161 ) -> Option
<SignatureHelp
> {
162 // Find the calling expression and its NameRef
163 let mut nodes
= arg_list
.syntax().ancestors().skip(1);
164 let calling_node
= loop {
165 if let Some(callable
) = ast
::CallableExpr
::cast(nodes
.next()?
) {
166 let inside_callable
= callable
168 .map_or(false, |it
| it
.syntax().text_range().contains(token
.text_range().start()));
175 let (callable
, active_parameter
) = callable_for_node(sema
, &calling_node
, &token
)?
;
178 SignatureHelp { doc: None, signature: String::new(), parameters: vec![], active_parameter }
;
181 let mut fn_params
= None
;
182 match callable
.kind() {
183 hir
::CallableKind
::Function(func
) => {
184 res
.doc
= func
.docs(db
);
185 format_to
!(res
.signature
, "fn {}", func
.name(db
).display(db
));
186 fn_params
= Some(match callable
.receiver_param(db
) {
187 Some(_self
) => func
.params_without_self(db
),
188 None
=> func
.assoc_fn_params(db
),
191 hir
::CallableKind
::TupleStruct(strukt
) => {
192 res
.doc
= strukt
.docs(db
);
193 format_to
!(res
.signature
, "struct {}", strukt
.name(db
).display(db
));
195 hir
::CallableKind
::TupleEnumVariant(variant
) => {
196 res
.doc
= variant
.docs(db
);
200 variant
.parent_enum(db
).name(db
).display(db
),
201 variant
.name(db
).display(db
)
204 hir
::CallableKind
::Closure(closure
) => {
205 let fn_trait
= closure
.fn_trait(db
);
206 format_to
!(res
.signature
, "impl {fn_trait}")
208 hir
::CallableKind
::FnPtr
=> format_to
!(res
.signature
, "fn"),
209 hir
::CallableKind
::FnImpl(fn_trait
) => match callable
.ty().as_adt() {
210 // FIXME: Render docs of the concrete trait impl function
211 Some(adt
) => format_to
!(
213 "<{} as {fn_trait}>::{}",
214 adt
.name(db
).display(db
),
215 fn_trait
.function_name()
217 None
=> format_to
!(res
.signature
, "impl {fn_trait}"),
221 res
.signature
.push('
('
);
223 if let Some((self_param
, _
)) = callable
.receiver_param(db
) {
224 format_to
!(res
.signature
, "{}", self_param
.display(db
))
226 let mut buf
= String
::new();
227 for (idx
, p
) in callable
.params().into_iter().enumerate() {
229 if let Some(param
) = p
.source(sema
.db
) {
231 Either
::Right(param
) => match param
.pat() {
232 Some(pat
) => format_to
!(buf
, "{}: ", pat
),
233 None
=> format_to
!(buf
, "?: "),
235 Either
::Left(_
) => format_to
!(buf
, "self: "),
238 // APITs (argument position `impl Trait`s) are inferred as {unknown} as the user is
239 // in the middle of entering call arguments.
240 // In that case, fall back to render definitions of the respective parameters.
241 // This is overly conservative: we do not substitute known type vars
242 // (see FIXME in tests::impl_trait) and falling back on any unknowns.
243 match (p
.ty().contains_unknown(), fn_params
.as_deref()) {
244 (true, Some(fn_params
)) => format_to
!(buf
, "{}", fn_params
[idx
].ty().display(db
)),
245 _
=> format_to
!(buf
, "{}", p
.ty().display(db
)),
247 res
.push_call_param(&buf
);
250 res
.signature
.push('
)'
);
252 let mut render
= |ret_type
: hir
::Type
| {
253 if !ret_type
.is_unit() {
254 format_to
!(res
.signature
, " -> {}", ret_type
.display(db
));
257 match callable
.kind() {
258 hir
::CallableKind
::Function(func
) if callable
.return_type().contains_unknown() => {
259 render(func
.ret_type(db
))
261 hir
::CallableKind
::Function(_
)
262 | hir
::CallableKind
::Closure(_
)
263 | hir
::CallableKind
::FnPtr
264 | hir
::CallableKind
::FnImpl(_
) => render(callable
.return_type()),
265 hir
::CallableKind
::TupleStruct(_
) | hir
::CallableKind
::TupleEnumVariant(_
) => {}
270 fn signature_help_for_generics(
271 sema
: &Semantics
<'_
, RootDatabase
>,
272 arg_list
: ast
::GenericArgList
,
274 ) -> Option
<SignatureHelp
> {
275 let (mut generics_def
, mut active_parameter
, first_arg_is_non_lifetime
) =
276 generic_def_for_node(sema
, &arg_list
, &token
)?
;
277 let mut res
= SignatureHelp
{
279 signature
: String
::new(),
281 active_parameter
: None
,
286 hir
::GenericDef
::Function(it
) => {
287 res
.doc
= it
.docs(db
);
288 format_to
!(res
.signature
, "fn {}", it
.name(db
).display(db
));
290 hir
::GenericDef
::Adt(hir
::Adt
::Enum(it
)) => {
291 res
.doc
= it
.docs(db
);
292 format_to
!(res
.signature
, "enum {}", it
.name(db
).display(db
));
294 hir
::GenericDef
::Adt(hir
::Adt
::Struct(it
)) => {
295 res
.doc
= it
.docs(db
);
296 format_to
!(res
.signature
, "struct {}", it
.name(db
).display(db
));
298 hir
::GenericDef
::Adt(hir
::Adt
::Union(it
)) => {
299 res
.doc
= it
.docs(db
);
300 format_to
!(res
.signature
, "union {}", it
.name(db
).display(db
));
302 hir
::GenericDef
::Trait(it
) => {
303 res
.doc
= it
.docs(db
);
304 format_to
!(res
.signature
, "trait {}", it
.name(db
).display(db
));
306 hir
::GenericDef
::TraitAlias(it
) => {
307 res
.doc
= it
.docs(db
);
308 format_to
!(res
.signature
, "trait {}", it
.name(db
).display(db
));
310 hir
::GenericDef
::TypeAlias(it
) => {
311 res
.doc
= it
.docs(db
);
312 format_to
!(res
.signature
, "type {}", it
.name(db
).display(db
));
314 hir
::GenericDef
::Variant(it
) => {
315 // In paths, generics of an enum can be specified *after* one of its variants.
317 // We'll use the signature of the enum, but include the docs of the variant.
318 res
.doc
= it
.docs(db
);
319 let enum_
= it
.parent_enum(db
);
320 format_to
!(res
.signature
, "enum {}", enum_
.name(db
).display(db
));
321 generics_def
= enum_
.into();
323 // These don't have generic args that can be specified
324 hir
::GenericDef
::Impl(_
) | hir
::GenericDef
::Const(_
) => return None
,
327 let params
= generics_def
.params(sema
.db
);
328 let num_lifetime_params
=
329 params
.iter().take_while(|param
| matches
!(param
, GenericParam
::LifetimeParam(_
))).count();
330 if first_arg_is_non_lifetime
{
331 // Lifetime parameters were omitted.
332 active_parameter
+= num_lifetime_params
;
334 res
.active_parameter
= Some(active_parameter
);
336 res
.signature
.push('
<'
);
337 let mut buf
= String
::new();
338 for param
in params
{
339 if let hir
::GenericParam
::TypeParam(ty
) = param
{
340 if ty
.is_implicit(db
) {
346 format_to
!(buf
, "{}", param
.display(db
));
347 res
.push_generic_param(&buf
);
349 if let hir
::GenericDef
::Trait(tr
) = generics_def
{
350 add_assoc_type_bindings(db
, &mut res
, tr
, arg_list
);
352 res
.signature
.push('
>'
);
357 fn add_assoc_type_bindings(
359 res
: &mut SignatureHelp
,
361 args
: ast
::GenericArgList
,
363 if args
.syntax().ancestors().find_map(ast
::TypeBound
::cast
).is_none() {
364 // Assoc type bindings are only valid in type bound position.
368 let present_bindings
= args
370 .filter_map(|arg
| match arg
{
371 ast
::GenericArg
::AssocTypeArg(arg
) => arg
.name_ref().map(|n
| n
.to_string()),
374 .collect
::<BTreeSet
<_
>>();
376 let mut buf
= String
::new();
377 for binding
in &present_bindings
{
379 format_to
!(buf
, "{} = …", binding
);
380 res
.push_generic_param(&buf
);
383 for item
in tr
.items_with_supertraits(db
) {
384 if let AssocItem
::TypeAlias(ty
) = item
{
385 let name
= ty
.name(db
).to_smol_str();
386 if !present_bindings
.contains(&*name
) {
388 format_to
!(buf
, "{} = …", name
);
389 res
.push_generic_param(&buf
);
395 fn signature_help_for_record_lit(
396 sema
: &Semantics
<'_
, RootDatabase
>,
397 record
: ast
::RecordExpr
,
399 ) -> Option
<SignatureHelp
> {
400 signature_help_for_record_(
402 record
.record_expr_field_list()?
.syntax().children_with_tokens(),
405 .record_expr_field_list()?
407 .filter_map(|field
| sema
.resolve_record_field(&field
))
408 .map(|(field
, _
, ty
)| (field
, ty
)),
413 fn signature_help_for_record_pat(
414 sema
: &Semantics
<'_
, RootDatabase
>,
415 record
: ast
::RecordPat
,
417 ) -> Option
<SignatureHelp
> {
418 signature_help_for_record_(
420 record
.record_pat_field_list()?
.syntax().children_with_tokens(),
423 .record_pat_field_list()?
425 .filter_map(|field
| sema
.resolve_record_pat_field(&field
)),
430 fn signature_help_for_tuple_struct_pat(
431 sema
: &Semantics
<'_
, RootDatabase
>,
432 pat
: ast
::TupleStructPat
,
434 ) -> Option
<SignatureHelp
> {
435 let path
= pat
.path()?
;
436 let path_res
= sema
.resolve_path(&path
)?
;
437 let mut res
= SignatureHelp
{
439 signature
: String
::new(),
441 active_parameter
: None
,
445 let fields
: Vec
<_
> = if let PathResolution
::Def(ModuleDef
::Variant(variant
)) = path_res
{
446 let en
= variant
.parent_enum(db
);
448 res
.doc
= en
.docs(db
);
452 en
.name(db
).display(db
),
453 variant
.name(db
).display(db
)
457 let adt
= match path_res
{
458 PathResolution
::SelfType(imp
) => imp
.self_ty(db
).as_adt()?
,
459 PathResolution
::Def(ModuleDef
::Adt(adt
)) => adt
,
464 hir
::Adt
::Struct(it
) => {
465 res
.doc
= it
.docs(db
);
466 format_to
!(res
.signature
, "struct {} (", it
.name(db
).display(db
));
472 Some(signature_help_for_tuple_pat_ish(
478 fields
.into_iter().map(|it
| it
.ty(db
)),
482 fn signature_help_for_tuple_pat(
483 sema
: &Semantics
<'_
, RootDatabase
>,
486 ) -> Option
<SignatureHelp
> {
488 let field_pats
= pat
.fields();
489 let pat
= pat
.into();
490 let ty
= sema
.type_of_pat(&pat
)?
;
491 let fields
= ty
.original
.tuple_fields(db
);
493 Some(signature_help_for_tuple_pat_ish(
497 signature
: String
::from('
('
),
499 active_parameter
: None
,
508 fn signature_help_for_tuple_expr(
509 sema
: &Semantics
<'_
, RootDatabase
>,
510 expr
: ast
::TupleExpr
,
512 ) -> Option
<SignatureHelp
> {
513 let active_parameter
= Some(
515 .children_with_tokens()
516 .filter_map(NodeOrToken
::into_token
)
517 .filter(|t
| t
.kind() == T
![,])
518 .take_while(|t
| t
.text_range().start() <= token
.text_range().start())
523 let mut res
= SignatureHelp
{
525 signature
: String
::from('
('
),
529 let expr
= sema
.type_of_expr(&expr
.into())?
;
530 let fields
= expr
.original
.tuple_fields(db
);
531 let mut buf
= String
::new();
533 format_to
!(buf
, "{}", ty
.display_truncated(db
, Some(20)));
534 res
.push_call_param(&buf
);
537 res
.signature
.push('
)'
);
541 fn signature_help_for_record_(
542 sema
: &Semantics
<'_
, RootDatabase
>,
543 field_list_children
: SyntaxElementChildren
,
545 fields2
: impl Iterator
<Item
= (hir
::Field
, hir
::Type
)>,
547 ) -> Option
<SignatureHelp
> {
548 let active_parameter
= field_list_children
549 .filter_map(NodeOrToken
::into_token
)
550 .filter(|t
| t
.kind() == T
![,])
551 .take_while(|t
| t
.text_range().start() <= token
.text_range().start())
554 let mut res
= SignatureHelp
{
556 signature
: String
::new(),
558 active_parameter
: Some(active_parameter
),
564 let path_res
= sema
.resolve_path(path
)?
;
565 if let PathResolution
::Def(ModuleDef
::Variant(variant
)) = path_res
{
566 fields
= variant
.fields(db
);
567 let en
= variant
.parent_enum(db
);
569 res
.doc
= en
.docs(db
);
573 en
.name(db
).display(db
),
574 variant
.name(db
).display(db
)
577 let adt
= match path_res
{
578 PathResolution
::SelfType(imp
) => imp
.self_ty(db
).as_adt()?
,
579 PathResolution
::Def(ModuleDef
::Adt(adt
)) => adt
,
584 hir
::Adt
::Struct(it
) => {
585 fields
= it
.fields(db
);
586 res
.doc
= it
.docs(db
);
587 format_to
!(res
.signature
, "struct {} {{ ", it
.name(db
).display(db
));
589 hir
::Adt
::Union(it
) => {
590 fields
= it
.fields(db
);
591 res
.doc
= it
.docs(db
);
592 format_to
!(res
.signature
, "union {} {{ ", it
.name(db
).display(db
));
599 fields
.into_iter().map(|field
| (field
.name(db
), Some(field
))).collect
::<FxIndexMap
<_
, _
>>();
600 let mut buf
= String
::new();
601 for (field
, ty
) in fields2
{
602 let name
= field
.name(db
);
603 format_to
!(buf
, "{}: {}", name
.display(db
), ty
.display_truncated(db
, Some(20)));
604 res
.push_record_field(&buf
);
607 if let Some(field
) = fields
.get_mut(&name
) {
611 for (name
, field
) in fields
{
612 let Some(field
) = field
else { continue }
;
613 format_to
!(buf
, "{}: {}", name
.display(db
), field
.ty(db
).display_truncated(db
, Some(20)));
614 res
.push_record_field(&buf
);
617 res
.signature
.push_str(" }");
621 fn signature_help_for_tuple_pat_ish(
623 mut res
: SignatureHelp
,
626 mut field_pats
: AstChildren
<ast
::Pat
>,
627 fields
: impl ExactSizeIterator
<Item
= hir
::Type
>,
629 let rest_pat
= field_pats
.find(|it
| matches
!(it
, ast
::Pat
::RestPat(_
)));
630 let is_left_of_rest_pat
=
631 rest_pat
.map_or(true, |it
| token
.text_range().start() < it
.syntax().text_range().end());
634 .children_with_tokens()
635 .filter_map(NodeOrToken
::into_token
)
636 .filter(|t
| t
.kind() == T
![,]);
638 res
.active_parameter
= {
639 Some(if is_left_of_rest_pat
{
640 commas
.take_while(|t
| t
.text_range().start() <= token
.text_range().start()).count()
642 let n_commas
= commas
646 .take_while(|t
| t
.text_range().start() > token
.text_range().start())
648 fields
.len().saturating_sub(1).saturating_sub(n_commas
)
652 let mut buf
= String
::new();
654 format_to
!(buf
, "{}", ty
.display_truncated(db
, Some(20)));
655 res
.push_call_param(&buf
);
658 res
.signature
.push('
)'
);
665 use expect_test
::{expect, Expect}
;
666 use ide_db
::base_db
::FilePosition
;
668 use test_fixture
::ChangeFixture
;
670 use crate::RootDatabase
;
672 /// Creates analysis from a multi-file fixture, returns positions marked with $0.
673 pub(crate) fn position(ra_fixture
: &str) -> (RootDatabase
, FilePosition
) {
674 let change_fixture
= ChangeFixture
::parse(ra_fixture
);
675 let mut database
= RootDatabase
::default();
676 database
.apply_change(change_fixture
.change
);
677 let (file_id
, range_or_offset
) =
678 change_fixture
.file_position
.expect("expected a marker ($0)");
679 let offset
= range_or_offset
.expect_offset();
680 (database
, FilePosition { file_id, offset }
)
684 fn check(ra_fixture
: &str, expect
: Expect
) {
685 let fixture
= format
!(
687 //- minicore: sized, fn
691 let (db
, position
) = position(&fixture
);
692 let sig_help
= crate::signature_help
::signature_help(&db
, position
);
693 let actual
= match sig_help
{
695 let mut rendered
= String
::new();
696 if let Some(docs
) = &sig_help
.doc
{
697 format_to
!(rendered
, "{}\n------\n", docs
.as_str());
699 format_to
!(rendered
, "{}\n", sig_help
.signature
);
701 for (i
, range
) in sig_help
.parameter_ranges().iter().enumerate() {
702 let is_active
= sig_help
.active_parameter
== Some(i
);
704 let start
= u32::from(range
.start());
705 let gap
= start
.checked_sub(offset
).unwrap_or_else(|| {
706 panic
!("parameter ranges out of order: {:?}", sig_help
.parameter_ranges())
708 rendered
.extend(iter
::repeat(' '
).take(gap
as usize));
709 let param_text
= &sig_help
.signature
[*range
];
710 let width
= param_text
.chars().count(); // …
711 let marker
= if is_active { '^' }
else { '-' }
;
712 rendered
.extend(iter
::repeat(marker
).take(width
));
713 offset
+= gap
+ u32::from(range
.len());
715 if !sig_help
.parameter_ranges().is_empty() {
716 format_to
!(rendered
, "\n");
720 None
=> String
::new(),
722 expect
.assert_eq(&actual
);
726 fn test_fn_signature_two_args() {
729 fn foo(x: u32, y: u32) -> u32 {x + y}
730 fn bar() { foo($03, ); }
733 fn foo(x: u32, y: u32) -> u32
739 fn foo(x: u32, y: u32) -> u32 {x + y}
740 fn bar() { foo(3$0, ); }
743 fn foo(x: u32, y: u32) -> u32
749 fn foo(x: u32, y: u32) -> u32 {x + y}
750 fn bar() { foo(3,$0 ); }
753 fn foo(x: u32, y: u32) -> u32
759 fn foo(x: u32, y: u32) -> u32 {x + y}
760 fn bar() { foo(3, $0); }
763 fn foo(x: u32, y: u32) -> u32
770 fn test_fn_signature_two_args_empty() {
773 fn foo(x: u32, y: u32) -> u32 {x + y}
774 fn bar() { foo($0); }
777 fn foo(x: u32, y: u32) -> u32
784 fn test_fn_signature_two_args_first_generics() {
787 fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
788 where T: Copy + Display, U: Debug
791 fn bar() { foo($03, ); }
794 fn foo(x: i32, y: U) -> u32
801 fn test_fn_signature_no_params() {
804 fn foo<T>() -> T where T: Copy + Display {}
805 fn bar() { foo($0); }
814 fn test_fn_signature_for_impl() {
818 impl F { pub fn new() { } }
820 let _ : F = F::new($0);
830 fn test_fn_signature_for_method_self() {
834 impl S { pub fn do_it(&self) {} }
848 fn test_fn_signature_for_method_with_arg() {
853 fn foo(&self, x: i32) {}
856 fn main() { S.foo($0); }
859 fn foo(&self, x: i32)
866 fn test_fn_signature_for_generic_method() {
871 fn foo(&self, x: T) {}
874 fn main() { S(1u32).foo($0); }
877 fn foo(&self, x: u32)
884 fn test_fn_signature_for_method_with_arg_as_assoc_fn() {
889 fn foo(&self, x: i32) {}
892 fn main() { S::foo($0); }
895 fn foo(self: &S, x: i32)
902 fn test_fn_signature_with_docs_simple() {
907 fn foo(j: u32) -> u32 {
918 fn foo(j: u32) -> u32
925 fn test_fn_signature_with_docs() {
928 /// Adds one to the number given.
935 /// assert_eq!(6, my_crate::add_one(5));
937 pub fn add_one(x: i32) -> i32 {
945 Adds one to the number given.
952 assert_eq!(6, my_crate::add_one(5));
955 fn add_one(x: i32) -> i32
962 fn test_fn_signature_with_docs_impl() {
967 /// Adds one to the number given.
974 /// assert_eq!(6, my_crate::add_one(5));
976 pub fn add_one(x: i32) -> i32 {
987 Adds one to the number given.
994 assert_eq!(6, my_crate::add_one(5));
997 fn add_one(x: i32) -> i32
1004 fn test_fn_signature_with_docs_from_actix() {
1008 /// Actor execution context type
1011 trait WriteHandler<E>
1015 /// Method is called when writer finishes.
1017 /// By default this method stops actor's `Context`.
1018 fn finished(&mut self, ctx: &mut Self::Context) {}
1021 fn foo(mut r: impl WriteHandler<()>) {
1026 Method is called when writer finishes.
1028 By default this method stops actor's `Context`.
1030 fn finished(&mut self, ctx: &mut <impl WriteHandler<()> as Actor>::Context)
1031 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1037 fn call_info_bad_offset() {
1040 fn foo(x: u32, y: u32) -> u32 {x + y}
1041 fn bar() { foo $0 (3, ); }
1048 fn outside_of_arg_list() {
1069 fn foo(a: u8) -> u8 {a}
1070 fn bar(a: u8) -> u8 {a}
1085 let _: Vec2<Vec<u8>$0>
1096 fn test_nested_method_in_lambda() {
1100 impl Foo { fn bar(&self, _: u32) { } }
1106 std::thread::spawn(move || foo.bar($0));
1110 fn bar(&self, _: u32)
1117 fn works_for_tuple_structs() {
1120 /// A cool tuple struct
1136 fn tuple_struct_pat() {
1139 /// A cool tuple struct
1155 fn tuple_struct_pat_rest() {
1158 /// A cool tuple struct
1159 struct S(u32, i32, f32, u16);
1167 struct S (u32, i32, f32, u16)
1173 /// A cool tuple struct
1174 struct S(u32, i32, f32, u16, u8);
1176 let S(0, .., $0, 0);
1182 struct S (u32, i32, f32, u16, u8)
1188 /// A cool tuple struct
1189 struct S(u32, i32, f32, u16);
1197 struct S (u32, i32, f32, u16)
1203 /// A cool tuple struct
1204 struct S(u32, i32, f32, u16, u8);
1206 let S(1, .., 1, $0, 2);
1212 struct S (u32, i32, f32, u16, u8)
1218 /// A cool tuple struct
1219 struct S(u32, i32, f32, u16);
1227 struct S (u32, i32, f32, u16)
1233 /// A cool tuple struct
1234 struct S(u32, i32, f32, u16);
1242 struct S (u32, i32, f32, u16)
1249 fn generic_struct() {
1265 fn works_for_enum_variants() {
1274 C { a: i32, b: i32 }
1291 fn cant_call_struct_record() {
1294 struct S { x: u32, y: i32 }
1304 fn cant_call_enum_record() {
1313 C { a: i32, b: i32 }
1325 fn fn_signature_for_call_in_macro() {
1328 macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
1331 fn bar() { foo($0); }
1341 fn fn_signature_for_method_call_defined_in_macro() {
1344 macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
1348 fn foo<'a>(&'a mut self) {}
1351 fn test() { S.foo($0); }
1354 fn foo(&'a mut self)
1360 fn call_info_for_lambdas() {
1364 fn foo(s: S) -> i32 { 92 }
1367 (|s| {{_move}; foo(s)})($0)
1371 impl FnOnce(s: S) -> i32
1378 fn foo(s: S) -> i32 { 92 }
1384 impl Fn(s: S) -> i32
1391 fn foo(s: S) -> i32 { 92 }
1394 (|s| { mutate = 1; foo(s) })($0)
1398 impl FnMut(s: S) -> i32
1405 fn call_info_for_fn_def_over_reference() {
1409 fn foo(s: S) -> i32 { 92 }
1423 fn call_info_for_fn_ptr() {
1426 fn main(f: fn(i32, f64) -> char) {
1431 fn(i32, f64) -> char
1438 fn call_info_for_fn_impl() {
1442 impl core::ops::FnOnce<(i32, f64)> for S {
1445 impl core::ops::FnMut<(i32, f64)> for S {}
1446 impl core::ops::Fn<(i32, f64)> for S {}
1452 <S as Fn>::call(i32, f64) -> char
1459 impl core::ops::FnOnce<(i32, f64)> for S {
1462 impl core::ops::FnMut<(i32, f64)> for S {}
1463 impl core::ops::Fn<(i32, f64)> for S {}
1469 <S as Fn>::call(i32, f64) -> char
1476 impl core::ops::FnOnce<(i32, f64)> for S {
1479 impl core::ops::FnOnce<(char, char)> for S {
1491 impl core::ops::FnOnce<(i32, f64)> for S {
1494 impl core::ops::FnOnce<(char, char)> for S {
1498 // FIXME: The ide layer loses the calling info here so we get an ambiguous trait solve result
1507 fn call_info_for_unclosed_call() {
1510 fn foo(foo: u32, bar: u32) {}
1515 fn foo(foo: u32, bar: u32)
1519 // check with surrounding space
1522 fn foo(foo: u32, bar: u32) {}
1527 fn foo(foo: u32, bar: u32)
1534 fn test_multiline_argument() {
1537 fn callee(a: u8, b: u8) {}
1547 fn callee(a: u8, b: u8) {}
1554 fn callee(a: u8, b: u8)
1560 fn callee(a: u8, b: u8) {}
1567 fn callee(a: u8, b: u8)
1574 fn test_generics_simple() {
1597 fn test_generics_on_variant() {
1624 fn test_lots_of_generics() {
1632 fn f<G, H>(g: G, h: impl Tr<G>) where G: Tr<()> {}
1647 fn test_generics_in_trait_ufcs() {
1670 fn test_generics_in_method_call() {
1691 fn test_generic_param_in_method_call() {
1696 fn test<V>(&mut self, val: V) {}
1703 fn test(&mut self, val: V)
1710 fn test_generic_kinds() {
1713 fn callee<'a, const A: u8, T, const C: u8>() {}
1716 callee::<'static, $0
1720 fn callee<'a, const A: u8, T, const C: u8>
1721 -- ^^^^^^^^^^^ - -----------
1726 fn callee<'a, const A: u8, T, const C: u8>() {}
1729 callee::<NON_LIFETIME$0
1733 fn callee<'a, const A: u8, T, const C: u8>
1734 -- ^^^^^^^^^^^ - -----------
1740 fn test_trait_assoc_types() {
1743 trait Trait<'a, T> {
1746 fn f() -> impl Trait<(), $0
1749 trait Trait<'a, T, Assoc = …>
1758 fn f() -> impl Iterator<$0
1761 trait Iterator<Item = …>
1770 fn f() -> impl Iterator<Item = $0
1773 trait Iterator<Item = …>
1783 fn f() -> impl Tr<$0
1786 trait Tr<A = …, B = …>
1796 fn f() -> impl Tr<B$0
1799 trait Tr<A = …, B = …>
1809 fn f() -> impl Tr<B = $0
1812 trait Tr<B = …, A = …>
1822 fn f() -> impl Tr<B = (), $0
1825 trait Tr<B = …, A = …>
1832 fn test_supertrait_assoc() {
1838 trait Sub: Super + Super {
1841 fn f() -> impl Sub<$0
1844 trait Sub<SubTy = …, SuperTy = …>
1845 ^^^^^^^^^ -----------
1851 fn no_assoc_types_outside_type_bounds() {
1869 // FIXME: Substitute type vars in impl trait (`U` -> `i8`)
1874 fn foo<U>(x: Wrap<impl Trait<U>>) {}
1880 fn foo(x: Wrap<impl Trait<U>>)
1881 ^^^^^^^^^^^^^^^^^^^^^^
1887 fn fully_qualified_syntax() {
1891 trait A { fn foo(&self, other: Self); }
1892 A::foo(&self$0, other);
1896 fn foo(self: &Self, other: Self)
1897 ^^^^^^^^^^^ -----------
1903 fn help_for_generic_call() {
1906 fn f<F: FnOnce(u8, u16) -> i32>(f: F) {
1911 impl FnOnce(u8, u16) -> i32
1917 fn f<T, F: FnMut(&T, u16) -> &T>(f: F) {
1922 impl FnMut(&T, u16) -> &T
1929 fn regression_13579() {
1938 ) -> impl Fn() -> C {
1949 fn record_literal() {
1952 struct Strukt<T, U = ()> {
1965 struct Strukt { u: i32, t: T, unit: () }
1966 ------ ^^^^ --------
1972 fn record_literal_nonexistent_field() {
1986 struct Strukt { a: u8 }
1993 fn tuple_variant_record_literal() {
2004 enum Opt::Some { 0: u8 }
2018 enum Opt::Some { 0: u8 }
2025 fn record_literal_self() {
2046 struct Strukt<T, U = ()> {
2059 struct Strukt { u: i32, t: T, unit: () }
2060 ------ ^^^^ --------
2066 fn test_enum_in_nested_method_in_lambda() {
2078 std::thread::spawn(move || { bar(A:$0) } );
2089 fn test_tuple_expr_free() {
2137 fn test_tuple_expr_expected() {
2141 let _: (&str, u32, u32)= ($0, 1, 3);
2149 // FIXME: Should typeck report a 4-ary tuple for the expression here?
2153 let _: (&str, u32, u32, u32) = ($0, 1, 3);
2164 let _: (&str, u32, u32)= ($0, 1, 3, 5);
2168 (&str, u32, u32, i32)
2175 fn test_tuple_pat_free() {
2183 ({unknown}, i32, i32)
2248 // FIXME: This is wrong, this should not mark the last as active
2257 fn test_tuple_pat_expected() {
2261 let (0$0, 1, 3): (i32, i32, i32);
2272 let ($0, 1, 3): (i32, i32, i32);
2283 let (1, 3 $0): (i32,);
2294 let (1, 3 $0, ..): (i32, i32, i32, i32);
2298 (i32, i32, i32, i32)
2305 let (1, 3, .., $0): (i32, i32, i32);
2315 fn test_tuple_pat_expected_inferred() {
2319 let (0$0, 1, 3) = (1, 2 ,3);
2330 let ($0 1, 3) = (1, 2, 3);
2333 // FIXME: Should typeck report a 3-ary tuple for the pattern here?
2342 let (1, 3 $0) = (1,);
2353 let (1, 3 $0, ..) = (1, 2, 3, 4);
2357 (i32, i32, i32, i32)
2364 let (1, 3, .., $0) = (1, 2, 3);