2020-10-20 10:04:38 -05:00
use either ::Either ;
2020-10-01 13:05:39 -05:00
use hir ::{ known , Callable , HirDisplay , Semantics } ;
2020-11-28 08:30:39 -06:00
use ide_db ::helpers ::FamousDefs ;
2020-08-13 09:39:16 -05:00
use ide_db ::RootDatabase ;
2020-08-12 11:26:51 -05:00
use stdx ::to_lower_snake_case ;
use syntax ::{
2020-10-20 10:04:38 -05:00
ast ::{ self , ArgListOwner , AstNode , NameOwner } ,
2020-06-30 11:04:25 -05:00
match_ast , Direction , NodeOrToken , SmolStr , SyntaxKind , TextRange , T ,
2019-07-19 16:20:09 -05:00
} ;
2019-12-21 11:45:46 -06:00
2020-07-16 14:51:44 -05:00
use crate ::FileId ;
2020-07-16 11:07:53 -05:00
2020-03-10 13:21:56 -05:00
#[ derive(Clone, Debug, PartialEq, Eq) ]
2020-03-31 09:02:55 -05:00
pub struct InlayHintsConfig {
2020-03-11 22:14:39 -05:00
pub type_hints : bool ,
pub parameter_hints : bool ,
2020-03-23 14:32:05 -05:00
pub chaining_hints : bool ,
2020-03-10 13:21:56 -05:00
pub max_length : Option < usize > ,
}
2020-03-31 09:02:55 -05:00
impl Default for InlayHintsConfig {
2020-03-10 13:21:56 -05:00
fn default ( ) -> Self {
2020-03-24 14:31:02 -05:00
Self { type_hints : true , parameter_hints : true , chaining_hints : true , max_length : None }
2020-03-10 13:21:56 -05:00
}
}
#[ derive(Clone, Debug, PartialEq, Eq) ]
2019-07-19 16:20:09 -05:00
pub enum InlayKind {
2019-08-04 16:28:36 -05:00
TypeHint ,
2020-01-14 11:02:01 -06:00
ParameterHint ,
2020-03-23 14:32:05 -05:00
ChainingHint ,
2019-07-19 16:20:09 -05:00
}
#[ derive(Debug) ]
pub struct InlayHint {
pub range : TextRange ,
2019-07-22 13:52:47 -05:00
pub kind : InlayKind ,
pub label : SmolStr ,
2019-07-19 16:20:09 -05:00
}
2020-05-31 04:29:19 -05:00
// Feature: Inlay Hints
//
// rust-analyzer shows additional information inline with the source code.
// Editors usually render this using read-only virtual text snippets interspersed with code.
//
2020-08-15 15:37:44 -05:00
// rust-analyzer shows hints for
2020-05-31 04:29:19 -05:00
//
// * types of local variables
// * names of function arguments
// * types of chained expressions
//
// **Note:** VS Code does not have native support for inlay hints https://github.com/microsoft/vscode/issues/16221[yet] and the hints are implemented using decorations.
// This approach has limitations, the caret movement and bracket highlighting near the edges of the hint may be weird:
// https://github.com/rust-analyzer/rust-analyzer/issues/1623[1], https://github.com/rust-analyzer/rust-analyzer/issues/3453[2].
//
// |===
// | Editor | Action Name
//
// | VS Code | **Rust Analyzer: Toggle inlay hints*
// |===
2019-11-18 11:02:28 -06:00
pub ( crate ) fn inlay_hints (
db : & RootDatabase ,
file_id : FileId ,
2020-03-31 09:02:55 -05:00
config : & InlayHintsConfig ,
2019-11-18 11:02:28 -06:00
) -> Vec < InlayHint > {
2020-08-12 09:32:36 -05:00
let _p = profile ::span ( " inlay_hints " ) ;
2020-02-18 11:35:10 -06:00
let sema = Semantics ::new ( db ) ;
let file = sema . parse ( file_id ) ;
2020-02-29 16:24:50 -06:00
2020-01-16 07:31:34 -06:00
let mut res = Vec ::new ( ) ;
for node in file . syntax ( ) . descendants ( ) {
2020-03-23 14:32:05 -05:00
if let Some ( expr ) = ast ::Expr ::cast ( node . clone ( ) ) {
2020-03-31 09:02:55 -05:00
get_chaining_hints ( & mut res , & sema , config , expr ) ;
2020-03-23 14:32:05 -05:00
}
2020-02-29 16:24:50 -06:00
match_ast! {
match node {
2020-03-31 09:02:55 -05:00
ast ::CallExpr ( it ) = > { get_param_name_hints ( & mut res , & sema , config , ast ::Expr ::from ( it ) ) ; } ,
ast ::MethodCallExpr ( it ) = > { get_param_name_hints ( & mut res , & sema , config , ast ::Expr ::from ( it ) ) ; } ,
2020-07-31 13:09:09 -05:00
ast ::IdentPat ( it ) = > { get_bind_pat_hints ( & mut res , & sema , config , it ) ; } ,
2020-02-29 16:24:50 -06:00
_ = > ( ) ,
}
}
2020-01-16 07:31:34 -06:00
}
res
2019-07-19 16:20:09 -05:00
}
2020-03-24 13:33:00 -05:00
fn get_chaining_hints (
acc : & mut Vec < InlayHint > ,
sema : & Semantics < RootDatabase > ,
2020-03-31 09:02:55 -05:00
config : & InlayHintsConfig ,
2020-03-24 13:33:00 -05:00
expr : ast ::Expr ,
) -> Option < ( ) > {
2020-03-31 09:02:55 -05:00
if ! config . chaining_hints {
2020-03-24 13:33:00 -05:00
return None ;
}
2020-07-30 09:21:30 -05:00
if matches! ( expr , ast ::Expr ::RecordExpr ( _ ) ) {
2020-03-24 13:33:00 -05:00
return None ;
}
2020-10-20 10:38:21 -05:00
let krate = sema . scope ( expr . syntax ( ) ) . module ( ) . map ( | it | it . krate ( ) ) ;
let famous_defs = FamousDefs ( & sema , krate ) ;
2020-03-24 14:31:02 -05:00
let mut tokens = expr
. syntax ( )
2020-03-24 13:33:00 -05:00
. siblings_with_tokens ( Direction ::Next )
. filter_map ( NodeOrToken ::into_token )
. filter ( | t | match t . kind ( ) {
SyntaxKind ::WHITESPACE if ! t . text ( ) . contains ( '\n' ) = > false ,
SyntaxKind ::COMMENT = > false ,
_ = > true ,
} ) ;
// Chaining can be defined as an expression whose next sibling tokens are newline and dot
// Ignoring extra whitespace and comments
let next = tokens . next ( ) ? . kind ( ) ;
let next_next = tokens . next ( ) ? . kind ( ) ;
2020-06-30 11:04:25 -05:00
if next = = SyntaxKind ::WHITESPACE & & next_next = = T! [ . ] {
2020-03-31 13:25:03 -05:00
let ty = sema . type_of_expr ( & expr ) ? ;
if ty . is_unknown ( ) {
return None ;
}
if matches! ( expr , ast ::Expr ::PathExpr ( _ ) ) {
2020-10-07 06:14:12 -05:00
if let Some ( hir ::Adt ::Struct ( st ) ) = ty . as_adt ( ) {
2020-03-31 13:25:03 -05:00
if st . fields ( sema . db ) . is_empty ( ) {
return None ;
}
}
}
2020-03-24 13:33:00 -05:00
acc . push ( InlayHint {
range : expr . syntax ( ) . text_range ( ) ,
kind : InlayKind ::ChainingHint ,
2020-10-20 10:38:21 -05:00
label : hint_iterator ( sema , & famous_defs , config , & ty ) . unwrap_or_else ( | | {
2020-10-07 04:30:42 -05:00
ty . display_truncated ( sema . db , config . max_length ) . to_string ( ) . into ( )
} ) ,
2020-03-24 13:33:00 -05:00
} ) ;
}
Some ( ( ) )
}
2020-02-29 16:24:50 -06:00
fn get_param_name_hints (
2020-01-16 07:31:34 -06:00
acc : & mut Vec < InlayHint > ,
2020-02-18 11:35:10 -06:00
sema : & Semantics < RootDatabase > ,
2020-03-31 09:02:55 -05:00
config : & InlayHintsConfig ,
2020-02-29 16:24:50 -06:00
expr : ast ::Expr ,
2020-01-16 07:31:34 -06:00
) -> Option < ( ) > {
2020-03-31 09:02:55 -05:00
if ! config . parameter_hints {
2020-03-10 13:21:56 -05:00
return None ;
2020-03-10 02:55:46 -05:00
}
2020-02-29 16:24:50 -06:00
let args = match & expr {
ast ::Expr ::CallExpr ( expr ) = > expr . arg_list ( ) ? . args ( ) ,
ast ::Expr ::MethodCallExpr ( expr ) = > expr . arg_list ( ) ? . args ( ) ,
_ = > return None ,
2020-01-16 07:31:34 -06:00
} ;
2020-02-29 16:24:50 -06:00
2020-07-16 14:51:44 -05:00
let callable = get_callable ( sema , & expr ) ? ;
let hints = callable
. params ( sema . db )
. into_iter ( )
2020-02-29 16:24:50 -06:00
. zip ( args )
2020-08-12 16:43:01 -05:00
. filter_map ( | ( ( param , _ty ) , arg ) | {
let param_name = match param ? {
2020-10-29 07:02:34 -05:00
Either ::Left ( _ ) = > " self " . to_string ( ) ,
2020-08-12 16:43:01 -05:00
Either ::Right ( pat ) = > match pat {
2020-07-31 13:09:09 -05:00
ast ::Pat ::IdentPat ( it ) = > it . name ( ) ? . to_string ( ) ,
2020-08-12 16:43:01 -05:00
_ = > return None ,
} ,
} ;
Some ( ( param_name , arg ) )
2020-07-16 14:51:44 -05:00
} )
2020-10-01 13:05:39 -05:00
. filter ( | ( param_name , arg ) | should_show_param_name_hint ( sema , & callable , param_name , & arg ) )
2020-02-29 16:24:50 -06:00
. map ( | ( param_name , arg ) | InlayHint {
range : arg . syntax ( ) . text_range ( ) ,
kind : InlayKind ::ParameterHint ,
2020-07-19 13:26:24 -05:00
label : param_name . into ( ) ,
2020-02-29 16:24:50 -06:00
} ) ;
acc . extend ( hints ) ;
Some ( ( ) )
}
fn get_bind_pat_hints (
acc : & mut Vec < InlayHint > ,
sema : & Semantics < RootDatabase > ,
2020-03-31 09:02:55 -05:00
config : & InlayHintsConfig ,
2020-07-31 13:09:09 -05:00
pat : ast ::IdentPat ,
2020-02-29 16:24:50 -06:00
) -> Option < ( ) > {
2020-03-31 09:02:55 -05:00
if ! config . type_hints {
2020-03-10 13:21:56 -05:00
return None ;
2020-03-10 02:55:46 -05:00
}
2020-10-20 10:38:21 -05:00
let krate = sema . scope ( pat . syntax ( ) ) . module ( ) . map ( | it | it . krate ( ) ) ;
let famous_defs = FamousDefs ( & sema , krate ) ;
2020-02-29 16:24:50 -06:00
let ty = sema . type_of_pat ( & pat . clone ( ) . into ( ) ) ? ;
2020-09-13 12:24:04 -05:00
if should_not_display_type_hint ( sema , & pat , & ty ) {
2020-02-29 16:24:50 -06:00
return None ;
}
2020-10-07 04:30:42 -05:00
acc . push ( InlayHint {
range : pat . syntax ( ) . text_range ( ) ,
kind : InlayKind ::TypeHint ,
2020-10-20 10:38:21 -05:00
label : hint_iterator ( sema , & famous_defs , config , & ty )
2020-10-07 04:30:42 -05:00
. unwrap_or_else ( | | ty . display_truncated ( sema . db , config . max_length ) . to_string ( ) . into ( ) ) ,
} ) ;
2020-10-06 12:07:34 -05:00
2020-01-16 07:31:34 -06:00
Some ( ( ) )
2019-07-21 15:28:05 -05:00
}
2020-01-16 07:31:34 -06:00
2020-10-06 12:07:34 -05:00
/// Checks if the type is an Iterator from std::iter and replaces its hint with an `impl Iterator<Item = Ty>`.
fn hint_iterator (
2020-10-06 14:05:57 -05:00
sema : & Semantics < RootDatabase > ,
2020-10-20 10:38:21 -05:00
famous_defs : & FamousDefs ,
2020-10-06 12:07:34 -05:00
config : & InlayHintsConfig ,
2020-10-07 06:14:12 -05:00
ty : & hir ::Type ,
2020-10-07 04:30:42 -05:00
) -> Option < SmolStr > {
2020-10-06 14:05:57 -05:00
let db = sema . db ;
2020-10-07 05:13:32 -05:00
let strukt = std ::iter ::successors ( Some ( ty . clone ( ) ) , | ty | ty . remove_ref ( ) )
. last ( )
. and_then ( | strukt | strukt . as_adt ( ) ) ? ;
2020-10-06 12:07:34 -05:00
let krate = strukt . krate ( db ) ? ;
2020-10-20 10:38:21 -05:00
if krate ! = famous_defs . core ( ) ? {
2020-10-06 12:07:34 -05:00
return None ;
}
2020-10-20 10:38:21 -05:00
let iter_trait = famous_defs . core_iter_Iterator ( ) ? ;
let iter_mod = famous_defs . core_iter ( ) ? ;
2020-10-12 10:16:57 -05:00
// assert this struct comes from `core::iter`
iter_mod . visibility_of ( db , & strukt . into ( ) ) . filter ( | & vis | vis = = hir ::Visibility ::Public ) ? ;
2020-10-06 12:07:34 -05:00
if ty . impls_trait ( db , iter_trait , & [ ] ) {
let assoc_type_item = iter_trait . items ( db ) . into_iter ( ) . find_map ( | item | match item {
2020-10-07 06:14:12 -05:00
hir ::AssocItem ::TypeAlias ( alias ) if alias . name ( db ) = = known ::Item = > Some ( alias ) ,
2020-10-06 12:07:34 -05:00
_ = > None ,
} ) ? ;
if let Some ( ty ) = ty . normalize_trait_assoc_type ( db , iter_trait , & [ ] , assoc_type_item ) {
2020-10-06 14:05:57 -05:00
const LABEL_START : & str = " impl Iterator<Item = " ;
const LABEL_END : & str = " > " ;
2020-10-20 10:38:21 -05:00
let ty_display = hint_iterator ( sema , famous_defs , config , & ty )
2020-10-10 13:37:20 -05:00
. map ( | assoc_type_impl | assoc_type_impl . to_string ( ) )
. unwrap_or_else ( | | {
ty . display_truncated (
db ,
config
. max_length
. map ( | len | len . saturating_sub ( LABEL_START . len ( ) + LABEL_END . len ( ) ) ) ,
)
. to_string ( )
} ) ;
2020-10-07 04:30:42 -05:00
return Some ( format! ( " {} {} {} " , LABEL_START , ty_display , LABEL_END ) . into ( ) ) ;
2020-10-06 12:07:34 -05:00
}
}
None
}
2020-10-07 06:14:12 -05:00
fn pat_is_enum_variant ( db : & RootDatabase , bind_pat : & ast ::IdentPat , pat_ty : & hir ::Type ) -> bool {
if let Some ( hir ::Adt ::Enum ( enum_data ) ) = pat_ty . as_adt ( ) {
2020-05-03 07:07:57 -05:00
let pat_text = bind_pat . to_string ( ) ;
2020-02-24 01:29:34 -06:00
enum_data
. variants ( db )
. into_iter ( )
. map ( | variant | variant . name ( db ) . to_string ( ) )
. any ( | enum_name | enum_name = = pat_text )
} else {
false
}
}
2020-07-31 13:09:09 -05:00
fn should_not_display_type_hint (
2020-09-13 12:24:04 -05:00
sema : & Semantics < RootDatabase > ,
2020-07-31 13:09:09 -05:00
bind_pat : & ast ::IdentPat ,
2020-10-07 06:14:12 -05:00
pat_ty : & hir ::Type ,
2020-07-31 13:09:09 -05:00
) -> bool {
2020-09-13 12:24:04 -05:00
let db = sema . db ;
2020-02-24 01:29:34 -06:00
if pat_ty . is_unknown ( ) {
return true ;
}
2020-10-07 06:14:12 -05:00
if let Some ( hir ::Adt ::Struct ( s ) ) = pat_ty . as_adt ( ) {
2020-05-03 07:07:57 -05:00
if s . fields ( db ) . is_empty ( ) & & s . name ( db ) . to_string ( ) = = bind_pat . to_string ( ) {
2020-03-08 16:21:08 -05:00
return true ;
}
}
2020-02-22 14:07:09 -06:00
for node in bind_pat . syntax ( ) . ancestors ( ) {
match_ast! {
match node {
ast ::LetStmt ( it ) = > {
2020-07-30 13:51:43 -05:00
return it . ty ( ) . is_some ( )
2020-02-22 14:07:09 -06:00
} ,
ast ::Param ( it ) = > {
2020-07-30 13:51:43 -05:00
return it . ty ( ) . is_some ( )
2020-02-22 14:07:09 -06:00
} ,
2020-02-24 01:29:34 -06:00
ast ::MatchArm ( _it ) = > {
return pat_is_enum_variant ( db , bind_pat , pat_ty ) ;
} ,
ast ::IfExpr ( it ) = > {
return it . condition ( ) . and_then ( | condition | condition . pat ( ) ) . is_some ( )
& & pat_is_enum_variant ( db , bind_pat , pat_ty ) ;
} ,
ast ::WhileExpr ( it ) = > {
return it . condition ( ) . and_then ( | condition | condition . pat ( ) ) . is_some ( )
& & pat_is_enum_variant ( db , bind_pat , pat_ty ) ;
} ,
2020-09-13 12:24:04 -05:00
ast ::ForExpr ( it ) = > {
// We *should* display hint only if user provided "in {expr}" and we know the type of expr (and it's not unit).
// Type of expr should be iterable.
2020-10-03 05:44:43 -05:00
return it . in_token ( ) . is_none ( ) | |
it . iterable ( )
. and_then ( | iterable_expr | sema . type_of_expr ( & iterable_expr ) )
. map ( | iterable_ty | iterable_ty . is_unknown ( ) | | iterable_ty . is_unit ( ) )
. unwrap_or ( true )
2020-09-13 12:24:04 -05:00
} ,
2020-02-22 14:07:09 -06:00
_ = > ( ) ,
}
}
}
false
}
2020-05-03 07:07:57 -05:00
fn should_show_param_name_hint (
2020-05-03 07:50:35 -05:00
sema : & Semantics < RootDatabase > ,
2020-10-07 06:14:12 -05:00
callable : & hir ::Callable ,
2020-02-23 03:49:53 -06:00
param_name : & str ,
2020-02-24 01:29:34 -06:00
argument : & ast ::Expr ,
2020-02-23 03:49:53 -06:00
) -> bool {
2020-05-03 07:50:35 -05:00
let param_name = param_name . trim_start_matches ( '_' ) ;
2020-07-16 14:51:44 -05:00
let fn_name = match callable . kind ( ) {
hir ::CallableKind ::Function ( it ) = > Some ( it . name ( sema . db ) . to_string ( ) ) ,
2020-07-17 03:57:49 -05:00
hir ::CallableKind ::TupleStruct ( _ )
| hir ::CallableKind ::TupleEnumVariant ( _ )
| hir ::CallableKind ::Closure = > None ,
2020-07-16 14:51:44 -05:00
} ;
2020-10-01 13:05:39 -05:00
2020-04-09 05:47:48 -05:00
if param_name . is_empty ( )
2020-07-16 14:51:44 -05:00
| | Some ( param_name ) = = fn_name . as_ref ( ) . map ( | s | s . trim_start_matches ( '_' ) )
2020-05-03 07:50:35 -05:00
| | is_argument_similar_to_param_name ( sema , argument , param_name )
2020-10-01 13:05:39 -05:00
| | is_param_name_similar_to_fn_name ( param_name , callable , fn_name . as_ref ( ) )
2020-06-28 06:11:41 -05:00
| | param_name . starts_with ( " ra_fixture " )
2020-04-09 05:47:48 -05:00
{
2020-02-23 03:49:53 -06:00
return false ;
}
// avoid displaying hints for common functions like map, filter, etc.
2020-04-08 16:48:16 -05:00
// or other obvious words used in std
2020-07-16 14:51:44 -05:00
! ( callable . n_params ( ) = = 1 & & is_obvious_param ( param_name ) )
2020-04-09 09:35:07 -05:00
}
2020-05-03 07:50:35 -05:00
fn is_argument_similar_to_param_name (
sema : & Semantics < RootDatabase > ,
argument : & ast ::Expr ,
param_name : & str ,
) -> bool {
if is_enum_name_similar_to_param_name ( sema , argument , param_name ) {
return true ;
2020-05-04 02:58:21 -05:00
}
match get_string_representation ( argument ) {
None = > false ,
Some ( repr ) = > {
let argument_string = repr . trim_start_matches ( '_' ) ;
argument_string . starts_with ( param_name ) | | argument_string . ends_with ( param_name )
}
2020-05-03 07:50:35 -05:00
}
}
2020-10-01 13:05:39 -05:00
fn is_param_name_similar_to_fn_name (
param_name : & str ,
callable : & Callable ,
fn_name : Option < & String > ,
) -> bool {
// if it's the only parameter, don't show it if:
// - is the same as the function name, or
// - the function ends with '_' + param_name
match ( callable . n_params ( ) , fn_name ) {
( 1 , Some ( function ) ) = > {
function = = param_name
| | ( function . len ( ) > param_name . len ( )
& & function . ends_with ( param_name )
& & function [ .. function . len ( ) - param_name . len ( ) ] . ends_with ( '_' ) )
}
_ = > false ,
}
}
2020-05-03 07:50:35 -05:00
fn is_enum_name_similar_to_param_name (
sema : & Semantics < RootDatabase > ,
argument : & ast ::Expr ,
param_name : & str ,
) -> bool {
match sema . type_of_expr ( argument ) . and_then ( | t | t . as_adt ( ) ) {
2020-10-07 06:14:12 -05:00
Some ( hir ::Adt ::Enum ( e ) ) = > to_lower_snake_case ( & e . name ( sema . db ) . to_string ( ) ) = = param_name ,
2020-05-03 07:50:35 -05:00
_ = > false ,
}
}
2020-05-03 07:07:57 -05:00
fn get_string_representation ( expr : & ast ::Expr ) -> Option < String > {
match expr {
ast ::Expr ::MethodCallExpr ( method_call_expr ) = > {
2020-10-22 12:42:39 -05:00
let name_ref = method_call_expr . name_ref ( ) ? ;
match name_ref . text ( ) . as_str ( ) {
" clone " = > method_call_expr . receiver ( ) . map ( | rec | rec . to_string ( ) ) ,
name_ref = > Some ( name_ref . to_owned ( ) ) ,
}
2020-04-09 11:26:49 -05:00
}
2020-05-03 07:07:57 -05:00
ast ::Expr ::RefExpr ( ref_expr ) = > get_string_representation ( & ref_expr . expr ( ) ? ) ,
_ = > Some ( expr . to_string ( ) ) ,
2020-04-09 11:26:49 -05:00
}
}
2020-04-09 09:35:07 -05:00
fn is_obvious_param ( param_name : & str ) -> bool {
2020-06-27 20:02:03 -05:00
let is_obvious_param_name =
matches! ( param_name , " predicate " | " value " | " pat " | " rhs " | " other " ) ;
2020-04-09 09:35:07 -05:00
param_name . len ( ) = = 1 | | is_obvious_param_name
2020-02-23 03:49:53 -06:00
}
2020-10-07 06:14:12 -05:00
fn get_callable ( sema : & Semantics < RootDatabase > , expr : & ast ::Expr ) -> Option < hir ::Callable > {
2020-01-14 11:02:01 -06:00
match expr {
2020-07-16 14:51:44 -05:00
ast ::Expr ::CallExpr ( expr ) = > sema . type_of_expr ( & expr . expr ( ) ? ) ? . as_callable ( sema . db ) ,
ast ::Expr ::MethodCallExpr ( expr ) = > sema . resolve_method_call_as_callable ( expr ) ,
2020-01-14 11:02:01 -06:00
_ = > None ,
}
}
2019-07-21 15:28:05 -05:00
2019-07-19 16:20:09 -05:00
#[ cfg(test) ]
mod tests {
2020-08-21 06:19:31 -05:00
use expect_test ::{ expect , Expect } ;
2020-11-28 08:30:39 -06:00
use ide_db ::helpers ::FamousDefs ;
2020-06-30 11:04:25 -05:00
use test_utils ::extract_annotations ;
2019-07-19 16:20:09 -05:00
2020-10-02 10:34:31 -05:00
use crate ::{ fixture , inlay_hints ::InlayHintsConfig } ;
2020-06-30 11:04:25 -05:00
fn check ( ra_fixture : & str ) {
2020-07-09 09:12:53 -05:00
check_with_config ( InlayHintsConfig ::default ( ) , ra_fixture ) ;
2020-06-30 11:04:25 -05:00
}
2020-07-09 09:12:53 -05:00
fn check_with_config ( config : InlayHintsConfig , ra_fixture : & str ) {
2020-10-07 04:30:42 -05:00
let ra_fixture =
format! ( " //- /main.rs crate:main deps:core \n {} \n {} " , ra_fixture , FamousDefs ::FIXTURE ) ;
2020-10-07 03:14:42 -05:00
let ( analysis , file_id ) = fixture ::file ( & ra_fixture ) ;
2020-06-30 11:04:25 -05:00
let expected = extract_annotations ( & * analysis . file_text ( file_id ) . unwrap ( ) ) ;
let inlay_hints = analysis . inlay_hints ( file_id , & config ) . unwrap ( ) ;
let actual =
inlay_hints . into_iter ( ) . map ( | it | ( it . range , it . label . to_string ( ) ) ) . collect ::< Vec < _ > > ( ) ;
2020-07-16 14:51:44 -05:00
assert_eq! ( expected , actual , " \n Expected: \n {:#?} \n \n Actual: \n {:#?} " , expected , actual ) ;
2020-06-30 11:04:25 -05:00
}
2019-12-07 12:14:01 -06:00
2020-07-09 09:12:53 -05:00
fn check_expect ( config : InlayHintsConfig , ra_fixture : & str , expect : Expect ) {
2020-10-07 04:30:42 -05:00
let ra_fixture =
format! ( " //- /main.rs crate:main deps:core \n {} \n {} " , ra_fixture , FamousDefs ::FIXTURE ) ;
let ( analysis , file_id ) = fixture ::file ( & ra_fixture ) ;
2020-06-30 14:55:21 -05:00
let inlay_hints = analysis . inlay_hints ( file_id , & config ) . unwrap ( ) ;
expect . assert_debug_eq ( & inlay_hints )
}
2020-03-10 02:55:46 -05:00
#[ test ]
fn param_hints_only ( ) {
2020-06-30 11:04:25 -05:00
check_with_config (
2020-07-09 09:12:53 -05:00
InlayHintsConfig {
parameter_hints : true ,
type_hints : false ,
chaining_hints : false ,
max_length : None ,
} ,
2020-03-10 02:55:46 -05:00
r #"
2020-06-30 11:04:25 -05:00
fn foo ( a : i32 , b : i32 ) -> i32 { a + b }
fn main ( ) {
let _x = foo (
4 ,
//^ a
4 ,
//^ b
) ;
} " #,
) ;
2020-03-10 02:55:46 -05:00
}
2020-10-01 13:05:39 -05:00
#[ test ]
fn param_name_similar_to_fn_name_still_hints ( ) {
check_with_config (
InlayHintsConfig {
parameter_hints : true ,
type_hints : false ,
chaining_hints : false ,
max_length : None ,
} ,
r #"
fn max ( x : i32 , y : i32 ) -> i32 { x + y }
fn main ( ) {
let _x = max (
4 ,
//^ x
4 ,
//^ y
) ;
} " #,
) ;
}
#[ test ]
fn param_name_similar_to_fn_name ( ) {
check_with_config (
InlayHintsConfig {
parameter_hints : true ,
type_hints : false ,
chaining_hints : false ,
max_length : None ,
} ,
r #"
fn param_with_underscore ( with_underscore : i32 ) -> i32 { with_underscore }
fn main ( ) {
let _x = param_with_underscore (
4 ,
) ;
} " #,
) ;
}
#[ test ]
fn param_name_same_as_fn_name ( ) {
check_with_config (
InlayHintsConfig {
parameter_hints : true ,
type_hints : false ,
chaining_hints : false ,
max_length : None ,
} ,
r #"
fn foo ( foo : i32 ) -> i32 { foo }
fn main ( ) {
let _x = foo (
4 ,
) ;
} " #,
) ;
}
#[ test ]
fn never_hide_param_when_multiple_params ( ) {
check_with_config (
InlayHintsConfig {
parameter_hints : true ,
type_hints : false ,
chaining_hints : false ,
max_length : None ,
} ,
r #"
fn foo ( bar : i32 , baz : i32 ) -> i32 { bar + baz }
fn main ( ) {
let _x = foo (
4 ,
//^ bar
8 ,
//^ baz
) ;
} " #,
) ;
}
2020-03-10 02:55:46 -05:00
#[ test ]
fn hints_disabled ( ) {
2020-06-30 11:04:25 -05:00
check_with_config (
InlayHintsConfig {
type_hints : false ,
parameter_hints : false ,
chaining_hints : false ,
max_length : None ,
} ,
2020-07-09 09:12:53 -05:00
r #"
fn foo ( a : i32 , b : i32 ) -> i32 { a + b }
fn main ( ) {
let _x = foo ( 4 , 4 ) ;
} " #,
2020-03-10 02:55:46 -05:00
) ;
}
#[ test ]
fn type_hints_only ( ) {
2020-06-30 11:04:25 -05:00
check_with_config (
InlayHintsConfig {
type_hints : true ,
parameter_hints : false ,
chaining_hints : false ,
max_length : None ,
2020-03-10 02:55:46 -05:00
} ,
2020-07-09 09:12:53 -05:00
r #"
fn foo ( a : i32 , b : i32 ) -> i32 { a + b }
fn main ( ) {
let _x = foo ( 4 , 4 ) ;
//^^ i32
} " #,
2020-06-30 11:04:25 -05:00
) ;
2020-03-10 02:55:46 -05:00
}
2020-06-30 11:04:25 -05:00
2019-12-07 16:54:18 -06:00
#[ test ]
2019-12-19 08:18:09 -06:00
fn default_generic_types_should_not_be_displayed ( ) {
2020-06-30 11:04:25 -05:00
check (
2019-12-07 16:54:18 -06:00
r #"
2020-06-30 11:04:25 -05:00
struct Test < K , T = u8 > { k : K , t : T }
2019-12-07 16:54:18 -06:00
fn main ( ) {
2020-05-29 12:14:04 -05:00
let zz = Test { t : 23 u8 , k : 33 } ;
2020-06-30 11:04:25 -05:00
//^^ Test<i32>
2020-01-22 08:44:05 -06:00
let zz_ref = & zz ;
2020-06-30 11:04:25 -05:00
//^^^^^^ &Test<i32>
2020-07-20 15:50:41 -05:00
let test = | | zz ;
//^^^^ || -> Test<i32>
2019-12-07 16:54:18 -06:00
} " #,
) ;
}
2019-07-19 16:20:09 -05:00
#[ test ]
2019-07-27 16:50:26 -05:00
fn let_statement ( ) {
2020-06-30 11:04:25 -05:00
check (
2019-07-19 16:20:09 -05:00
r #"
2019-07-27 16:50:26 -05:00
#[ derive(PartialEq) ]
2020-06-30 11:04:25 -05:00
enum Option < T > { None , Some ( T ) }
2019-07-27 16:50:26 -05:00
#[ derive(PartialEq) ]
2020-06-30 11:04:25 -05:00
struct Test { a : Option < u32 > , b : u8 }
2019-07-19 16:20:09 -05:00
fn main ( ) {
struct InnerStruct { }
let test = 54 ;
2020-06-30 11:04:25 -05:00
//^^^^ i32
2019-07-26 06:10:29 -05:00
let test : i32 = 33 ;
let mut test = 33 ;
2020-06-30 11:04:25 -05:00
//^^^^^^^^ i32
2019-07-26 06:10:29 -05:00
let _ = 22 ;
let test = " test " ;
2020-06-30 11:04:25 -05:00
//^^^^ &str
2019-07-19 16:20:09 -05:00
let test = InnerStruct { } ;
2019-07-26 06:10:29 -05:00
2020-06-30 11:04:25 -05:00
let test = unresolved ( ) ;
2019-07-26 06:10:29 -05:00
2019-07-19 16:20:09 -05:00
let test = ( 42 , 'a' ) ;
2020-06-30 11:04:25 -05:00
//^^^^ (i32, char)
let ( a , ( b , ( c , ) ) = ( 2 , ( 3 , ( 9.2 , ) ) ;
//^ i32 ^ i32 ^ f64
2019-12-07 12:14:01 -06:00
let & x = & 92 ;
2020-06-30 11:04:25 -05:00
//^ i32
2019-07-27 16:50:26 -05:00
} " #,
2019-07-21 15:28:05 -05:00
) ;
2019-07-27 16:50:26 -05:00
}
#[ test ]
2019-12-23 09:53:35 -06:00
fn closure_parameters ( ) {
2020-06-30 11:04:25 -05:00
check (
2019-07-27 16:50:26 -05:00
r #"
fn main ( ) {
let mut start = 0 ;
2020-06-30 11:04:25 -05:00
//^^^^^^^^^ i32
( 0 .. 2 ) . for_each ( | increment | { start + = increment ; } ) ;
//^^^^^^^^^ i32
2019-12-23 09:53:35 -06:00
2020-06-30 11:04:25 -05:00
let multiply =
//^^^^^^^^ |…| -> i32
| a , b | a * b
//^ i32 ^ i32
;
let _ : i32 = multiply ( 1 , 2 ) ;
2020-01-22 08:44:05 -06:00
let multiply_ref = & multiply ;
2020-06-30 11:04:25 -05:00
//^^^^^^^^^^^^ &|…| -> i32
2019-12-23 09:53:35 -06:00
let return_42 = | | 42 ;
2020-06-30 11:04:25 -05:00
//^^^^^^^^^ || -> i32
2019-07-27 16:50:26 -05:00
} " #,
) ;
}
#[ test ]
fn if_expr ( ) {
2020-06-30 11:04:25 -05:00
check (
2019-07-27 16:50:26 -05:00
r #"
2020-06-30 11:04:25 -05:00
enum Option < T > { None , Some ( T ) }
use Option ::* ;
2019-07-27 16:50:26 -05:00
2020-06-30 11:04:25 -05:00
struct Test { a : Option < u32 > , b : u8 }
2020-02-24 01:29:34 -06:00
2019-07-27 16:50:26 -05:00
fn main ( ) {
2020-02-24 01:29:34 -06:00
let test = Some ( Test { a : Some ( 3 ) , b : 1 } ) ;
2020-06-30 11:04:25 -05:00
//^^^^ Option<Test>
2020-02-24 01:29:34 -06:00
if let None = & test { } ;
2019-07-27 16:50:26 -05:00
if let test = & test { } ;
2020-06-30 11:04:25 -05:00
//^^^^ &Option<Test>
2020-02-24 01:29:34 -06:00
if let Some ( test ) = & test { } ;
2020-06-30 11:04:25 -05:00
//^^^^ &Test
if let Some ( Test { a , b } ) = & test { } ;
//^ &Option<u32> ^ &u8
if let Some ( Test { a : x , b : y } ) = & test { } ;
//^ &Option<u32> ^ &u8
if let Some ( Test { a : Some ( x ) , b : y } ) = & test { } ;
//^ &u32 ^ &u8
if let Some ( Test { a : None , b : y } ) = & test { } ;
//^ &u8
2020-02-24 01:29:34 -06:00
if let Some ( Test { b : y , .. } ) = & test { } ;
2020-06-30 11:04:25 -05:00
//^ &u8
2020-02-24 01:29:34 -06:00
if test = = None { }
2019-07-27 16:50:26 -05:00
} " #,
) ;
}
#[ test ]
fn while_expr ( ) {
2020-06-30 11:04:25 -05:00
check (
2019-07-27 16:50:26 -05:00
r #"
2020-06-30 11:04:25 -05:00
enum Option < T > { None , Some ( T ) }
use Option ::* ;
2019-07-27 16:50:26 -05:00
2020-06-30 11:04:25 -05:00
struct Test { a : Option < u32 > , b : u8 }
2020-02-24 01:29:34 -06:00
2019-07-27 16:50:26 -05:00
fn main ( ) {
2020-02-24 01:29:34 -06:00
let test = Some ( Test { a : Some ( 3 ) , b : 1 } ) ;
2020-06-30 11:04:25 -05:00
//^^^^ Option<Test>
while let Some ( Test { a : Some ( x ) , b : y } ) = & test { } ;
//^ &u32 ^ &u8
2019-07-27 16:50:26 -05:00
} " #,
) ;
}
#[ test ]
fn match_arm_list ( ) {
2020-06-30 11:04:25 -05:00
check (
2019-07-27 16:50:26 -05:00
r #"
2020-06-30 11:04:25 -05:00
enum Option < T > { None , Some ( T ) }
use Option ::* ;
2019-07-27 16:50:26 -05:00
2020-06-30 11:04:25 -05:00
struct Test { a : Option < u32 > , b : u8 }
2020-02-24 01:29:34 -06:00
2019-07-27 16:50:26 -05:00
fn main ( ) {
2020-02-24 01:29:34 -06:00
match Some ( Test { a : Some ( 3 ) , b : 1 } ) {
None = > ( ) ,
2019-07-27 16:50:26 -05:00
test = > ( ) ,
2020-06-30 11:04:25 -05:00
//^^^^ Option<Test>
2020-02-24 01:29:34 -06:00
Some ( Test { a : Some ( x ) , b : y } ) = > ( ) ,
2020-06-30 11:04:25 -05:00
//^ u32 ^ u8
2019-07-27 16:50:26 -05:00
_ = > { }
}
} " #,
) ;
2019-07-19 16:20:09 -05:00
}
2019-11-19 10:40:38 -06:00
#[ test ]
fn hint_truncation ( ) {
2020-06-30 11:04:25 -05:00
check_with_config (
2020-07-09 09:12:53 -05:00
InlayHintsConfig { max_length : Some ( 8 ) , .. Default ::default ( ) } ,
2019-11-19 10:40:38 -06:00
r #"
struct Smol < T > ( T ) ;
struct VeryLongOuterName < T > ( T ) ;
fn main ( ) {
let a = Smol ( 0 u32 ) ;
2020-06-30 11:04:25 -05:00
//^ Smol<u32>
2019-11-19 10:40:38 -06:00
let b = VeryLongOuterName ( 0 usize ) ;
2020-06-30 11:04:25 -05:00
//^ VeryLongOuterName<…>
2019-11-19 10:40:38 -06:00
let c = Smol ( Smol ( 0 u32 ) )
2020-06-30 11:04:25 -05:00
//^ Smol<Smol<…>>
2019-11-19 10:40:38 -06:00
} " #,
) ;
}
2020-01-14 11:02:01 -06:00
#[ test ]
fn function_call_parameter_hint ( ) {
2020-06-30 11:04:25 -05:00
check (
2020-01-14 11:02:01 -06:00
r #"
2020-06-30 11:04:25 -05:00
enum Option < T > { None , Some ( T ) }
use Option ::* ;
2020-02-23 03:49:53 -06:00
struct FileId { }
struct SmolStr { }
struct TextRange { }
struct SyntaxKind { }
struct NavigationTarget { }
2020-01-14 11:02:01 -06:00
struct Test { }
impl Test {
2020-06-30 11:04:25 -05:00
fn method ( & self , mut param : i32 ) -> i32 { param * 2 }
2020-02-23 03:49:53 -06:00
fn from_syntax (
file_id : FileId ,
name : SmolStr ,
2020-06-30 11:04:25 -05:00
focus_range : Option < TextRange > ,
2020-02-23 03:49:53 -06:00
full_range : TextRange ,
kind : SyntaxKind ,
2020-06-30 11:04:25 -05:00
docs : Option < String > ,
2020-02-23 03:49:53 -06:00
) -> NavigationTarget {
NavigationTarget { }
}
2020-01-14 11:02:01 -06:00
}
2020-01-18 06:40:32 -06:00
fn test_func ( mut foo : i32 , bar : i32 , msg : & str , _ : i32 , last : i32 ) -> i32 {
2020-01-14 11:02:01 -06:00
foo + bar
}
fn main ( ) {
let not_literal = 1 ;
2020-06-30 11:04:25 -05:00
//^^^^^^^^^^^ i32
let _ : i32 = test_func ( 1 , 2 , " hello " , 3 , not_literal ) ;
//^ foo ^ bar ^^^^^^^ msg ^^^^^^^^^^^ last
2020-01-14 11:02:01 -06:00
let t : Test = Test { } ;
t . method ( 123 ) ;
2020-06-30 11:04:25 -05:00
//^^^ param
Test ::method ( & t , 3456 ) ;
2020-10-29 07:02:34 -05:00
//^^ self ^^^^ param
2020-02-23 03:49:53 -06:00
Test ::from_syntax (
FileId { } ,
2020-06-30 11:04:25 -05:00
//^^^^^^^^^ file_id
2020-02-23 03:49:53 -06:00
" impl " . into ( ) ,
2020-06-30 11:04:25 -05:00
//^^^^^^^^^^^^^ name
2020-02-24 01:29:34 -06:00
None ,
2020-06-30 11:04:25 -05:00
//^^^^ focus_range
2020-02-23 03:49:53 -06:00
TextRange { } ,
2020-06-30 11:04:25 -05:00
//^^^^^^^^^^^^ full_range
2020-02-23 03:49:53 -06:00
SyntaxKind { } ,
2020-06-30 11:04:25 -05:00
//^^^^^^^^^^^^^ kind
2020-02-24 01:29:34 -06:00
None ,
2020-06-30 11:04:25 -05:00
//^^^^ docs
2020-02-23 03:49:53 -06:00
) ;
2020-01-14 11:02:01 -06:00
} " #,
) ;
}
2020-02-23 03:49:53 -06:00
#[ test ]
fn omitted_parameters_hints_heuristics ( ) {
2020-06-30 11:04:25 -05:00
check_with_config (
2020-07-09 09:12:53 -05:00
InlayHintsConfig { max_length : Some ( 8 ) , .. Default ::default ( ) } ,
2020-02-23 03:49:53 -06:00
r #"
fn map ( f : i32 ) { }
fn filter ( predicate : i32 ) { }
struct TestVarContainer {
test_var : i32 ,
}
2020-05-03 07:07:57 -05:00
impl TestVarContainer {
fn test_var ( & self ) -> i32 {
self . test_var
}
}
2020-02-23 03:49:53 -06:00
struct Test { }
impl Test {
fn map ( self , f : i32 ) -> Self {
self
}
fn filter ( self , predicate : i32 ) -> Self {
self
}
2020-04-08 16:48:16 -05:00
fn field ( self , value : i32 ) -> Self {
self
}
2020-02-23 03:49:53 -06:00
fn no_hints_expected ( & self , _ : i32 , test_var : i32 ) { }
2020-04-09 05:47:48 -05:00
fn frob ( & self , frob : bool ) { }
2020-02-23 03:49:53 -06:00
}
2020-04-08 16:48:16 -05:00
struct Param { }
2020-04-08 18:07:21 -05:00
fn different_order ( param : & Param ) { }
fn different_order_mut ( param : & mut Param ) { }
2020-04-18 02:53:48 -05:00
fn has_underscore ( _param : bool ) { }
2020-05-03 07:50:35 -05:00
fn enum_matches_param_name ( completion_kind : CompletionKind ) { }
2020-08-12 16:43:01 -05:00
fn param_destructuring_omitted_1 ( ( a , b ) : ( u32 , u32 ) ) { }
fn param_destructuring_omitted_2 ( TestVarContainer { test_var : _ } : TestVarContainer ) { }
2020-04-08 16:48:16 -05:00
2020-04-09 05:47:48 -05:00
fn twiddle ( twiddle : bool ) { }
2020-04-18 02:53:48 -05:00
fn doo ( _doo : bool ) { }
2020-04-09 05:47:48 -05:00
2020-05-03 07:50:35 -05:00
enum CompletionKind {
Keyword ,
}
2020-02-23 03:49:53 -06:00
fn main ( ) {
let container : TestVarContainer = TestVarContainer { test_var : 42 } ;
let test : Test = Test { } ;
map ( 22 ) ;
filter ( 33 ) ;
2020-04-08 16:48:16 -05:00
let test_processed : Test = test . map ( 1 ) . filter ( 2 ) . field ( 3 ) ;
2020-02-23 03:49:53 -06:00
let test_var : i32 = 55 ;
test_processed . no_hints_expected ( 22 , test_var ) ;
test_processed . no_hints_expected ( 33 , container . test_var ) ;
2020-05-03 07:07:57 -05:00
test_processed . no_hints_expected ( 44 , container . test_var ( ) ) ;
2020-04-09 05:47:48 -05:00
test_processed . frob ( false ) ;
twiddle ( true ) ;
2020-04-18 02:53:48 -05:00
doo ( true ) ;
2020-04-08 16:48:16 -05:00
2020-05-03 07:07:57 -05:00
let mut param_begin : Param = Param { } ;
2020-04-08 18:07:21 -05:00
different_order ( & param_begin ) ;
different_order ( & mut param_begin ) ;
2020-04-08 16:48:16 -05:00
2020-04-18 02:53:48 -05:00
let param : bool = true ;
has_underscore ( param ) ;
2020-05-03 07:50:35 -05:00
enum_matches_param_name ( CompletionKind ::Keyword ) ;
2020-04-08 16:48:16 -05:00
let a : f64 = 7.0 ;
let b : f64 = 4.0 ;
let _ : f64 = a . div_euclid ( b ) ;
let _ : f64 = a . abs_sub ( b ) ;
2020-08-12 16:43:01 -05:00
let range : ( u32 , u32 ) = ( 3 , 5 ) ;
param_destructuring_omitted_1 ( range ) ;
param_destructuring_omitted_2 ( container ) ;
2020-02-23 03:49:53 -06:00
} " #,
) ;
}
2020-03-08 16:21:08 -05:00
#[ test ]
fn unit_structs_have_no_type_hints ( ) {
2020-06-30 11:04:25 -05:00
check_with_config (
2020-07-09 09:12:53 -05:00
InlayHintsConfig { max_length : Some ( 8 ) , .. Default ::default ( ) } ,
2020-03-08 16:21:08 -05:00
r #"
2020-06-30 11:04:25 -05:00
enum Result < T , E > { Ok ( T ) , Err ( E ) }
use Result ::* ;
2020-03-08 16:21:08 -05:00
struct SyntheticSyntax ;
fn main ( ) {
match Ok ( ( ) ) {
Ok ( _ ) = > ( ) ,
Err ( SyntheticSyntax ) = > ( ) ,
}
} " #,
) ;
}
2020-03-24 13:33:00 -05:00
#[ test ]
fn chaining_hints_ignore_comments ( ) {
2020-06-30 14:55:21 -05:00
check_expect (
2020-07-09 09:12:53 -05:00
InlayHintsConfig {
parameter_hints : false ,
type_hints : false ,
chaining_hints : true ,
max_length : None ,
} ,
2020-03-24 13:33:00 -05:00
r #"
2020-06-30 14:55:21 -05:00
struct A ( B ) ;
impl A { fn into_b ( self ) -> B { self . 0 } }
struct B ( C ) ;
impl B { fn into_c ( self ) -> C { self . 0 } }
struct C ;
fn main ( ) {
let c = A ( B ( C ) )
. into_b ( ) // This is a comment
. into_c ( ) ;
}
" #,
expect! [ [ r #"
[
InlayHint {
2020-10-07 04:30:42 -05:00
range : 148 .. 173 ,
2020-06-30 14:55:21 -05:00
kind : ChainingHint ,
label : " B " ,
} ,
InlayHint {
2020-10-07 04:30:42 -05:00
range : 148 .. 155 ,
2020-06-30 14:55:21 -05:00
kind : ChainingHint ,
label : " A " ,
} ,
]
" #]],
) ;
2020-03-24 13:33:00 -05:00
}
#[ test ]
fn chaining_hints_without_newlines ( ) {
2020-06-30 11:04:25 -05:00
check_with_config (
2020-07-09 09:12:53 -05:00
InlayHintsConfig {
parameter_hints : false ,
type_hints : false ,
chaining_hints : true ,
max_length : None ,
} ,
2020-03-24 13:33:00 -05:00
r #"
2020-06-30 11:04:25 -05:00
struct A ( B ) ;
impl A { fn into_b ( self ) -> B { self . 0 } }
struct B ( C ) ;
impl B { fn into_c ( self ) -> C { self . 0 } }
struct C ;
2020-03-24 13:33:00 -05:00
2020-06-30 11:04:25 -05:00
fn main ( ) {
let c = A ( B ( C ) ) . into_b ( ) . into_c ( ) ;
} " #,
2020-03-24 13:33:00 -05:00
) ;
}
#[ test ]
fn struct_access_chaining_hints ( ) {
2020-06-30 14:55:21 -05:00
check_expect (
2020-07-09 09:12:53 -05:00
InlayHintsConfig {
parameter_hints : false ,
type_hints : false ,
chaining_hints : true ,
max_length : None ,
} ,
2020-03-24 13:33:00 -05:00
r #"
2020-06-30 11:04:25 -05:00
struct A { pub b : B }
struct B { pub c : C }
struct C ( pub bool ) ;
struct D ;
2020-03-31 13:25:03 -05:00
2020-06-30 11:04:25 -05:00
impl D {
fn foo ( & self ) -> i32 { 42 }
}
2020-03-24 13:33:00 -05:00
2020-06-30 11:04:25 -05:00
fn main ( ) {
let x = A { b : B { c : C ( true ) } }
. b
. c
. 0 ;
let x = D
. foo ( ) ;
} " #,
2020-06-30 14:55:21 -05:00
expect! [ [ r #"
[
InlayHint {
2020-10-07 04:30:42 -05:00
range : 144 .. 191 ,
2020-06-30 14:55:21 -05:00
kind : ChainingHint ,
label : " C " ,
} ,
InlayHint {
2020-10-07 04:30:42 -05:00
range : 144 .. 180 ,
2020-06-30 14:55:21 -05:00
kind : ChainingHint ,
label : " B " ,
} ,
]
" #]],
) ;
2020-03-24 13:33:00 -05:00
}
#[ test ]
fn generic_chaining_hints ( ) {
2020-06-30 14:55:21 -05:00
check_expect (
2020-07-09 09:12:53 -05:00
InlayHintsConfig {
parameter_hints : false ,
type_hints : false ,
chaining_hints : true ,
max_length : None ,
} ,
2020-03-24 13:33:00 -05:00
r #"
2020-06-30 14:55:21 -05:00
struct A < T > ( T ) ;
struct B < T > ( T ) ;
struct C < T > ( T ) ;
struct X < T , R > ( T , R ) ;
impl < T > A < T > {
fn new ( t : T ) -> Self { A ( t ) }
fn into_b ( self ) -> B < T > { B ( self . 0 ) }
}
impl < T > B < T > {
fn into_c ( self ) -> C < T > { C ( self . 0 ) }
}
fn main ( ) {
let c = A ::new ( X ( 42 , true ) )
. into_b ( )
. into_c ( ) ;
}
" #,
expect! [ [ r #"
[
InlayHint {
2020-10-07 04:30:42 -05:00
range : 247 .. 284 ,
2020-06-30 14:55:21 -05:00
kind : ChainingHint ,
label : " B<X<i32, bool>> " ,
} ,
InlayHint {
2020-10-07 04:30:42 -05:00
range : 247 .. 266 ,
2020-06-30 14:55:21 -05:00
kind : ChainingHint ,
label : " A<X<i32, bool>> " ,
} ,
]
" #]],
) ;
2020-03-24 13:33:00 -05:00
}
2020-09-13 12:24:04 -05:00
#[ test ]
fn incomplete_for_no_hint ( ) {
check (
r #"
fn main ( ) {
let data = & [ 1 i32 , 2 , 3 ] ;
//^^^^ &[i32; _]
for i
} " #,
) ;
check (
r #"
2020-10-03 00:37:58 -05:00
pub struct Vec < T > { }
impl < T > Vec < T > {
pub fn new ( ) -> Self { Vec { } }
pub fn push ( & mut self , t : T ) { }
}
impl < T > IntoIterator for Vec < T > {
type Item = T ;
}
2020-09-13 12:24:04 -05:00
fn main ( ) {
2020-10-03 00:37:58 -05:00
let mut data = Vec ::new ( ) ;
//^^^^^^^^ Vec<&str>
data . push ( " foo " ) ;
2020-10-03 00:56:02 -05:00
for i in
2020-09-13 12:24:04 -05:00
println! ( " Unit expr " ) ;
2020-10-03 00:37:58 -05:00
}
" #,
2020-09-13 12:24:04 -05:00
) ;
}
#[ test ]
fn complete_for_hint ( ) {
check (
r #"
2020-10-03 00:37:58 -05:00
pub struct Vec < T > { }
impl < T > Vec < T > {
pub fn new ( ) -> Self { Vec { } }
pub fn push ( & mut self , t : T ) { }
}
impl < T > IntoIterator for Vec < T > {
type Item = T ;
}
2020-09-13 12:24:04 -05:00
fn main ( ) {
2020-10-03 00:37:58 -05:00
let mut data = Vec ::new ( ) ;
//^^^^^^^^ Vec<&str>
data . push ( " foo " ) ;
for i in data {
//^ &str
let z = i ;
//^ &str
2020-09-13 12:24:04 -05:00
}
2020-10-03 00:37:58 -05:00
}
2020-10-06 07:40:27 -05:00
" #,
) ;
}
#[ test ]
fn multi_dyn_trait_bounds ( ) {
check_with_config (
InlayHintsConfig {
type_hints : true ,
parameter_hints : false ,
chaining_hints : false ,
max_length : None ,
} ,
r #"
pub struct Vec < T > { }
impl < T > Vec < T > {
pub fn new ( ) -> Self { Vec { } }
}
pub struct Box < T > { }
trait Display { }
trait Sync { }
fn main ( ) {
let _v = Vec ::< Box < & ( dyn Display + Sync ) > > ::new ( ) ;
//^^ Vec<Box<&(dyn Display + Sync)>>
let _v = Vec ::< Box < * const ( dyn Display + Sync ) > > ::new ( ) ;
//^^ Vec<Box<*const (dyn Display + Sync)>>
let _v = Vec ::< Box < dyn Display + Sync > > ::new ( ) ;
//^^ Vec<Box<dyn Display + Sync>>
}
2020-10-06 12:07:34 -05:00
" #,
) ;
}
#[ test ]
fn shorten_iterator_hints ( ) {
check_with_config (
InlayHintsConfig {
parameter_hints : false ,
type_hints : true ,
2020-10-07 04:30:42 -05:00
chaining_hints : false ,
2020-10-06 12:07:34 -05:00
max_length : None ,
} ,
2020-10-07 03:14:42 -05:00
r #"
2020-10-07 04:30:42 -05:00
use core ::iter ;
2020-10-06 12:07:34 -05:00
2020-10-06 14:05:57 -05:00
struct MyIter ;
2020-10-07 03:14:42 -05:00
impl Iterator for MyIter {
2020-10-06 14:05:57 -05:00
type Item = ( ) ;
fn next ( & mut self ) -> Option < Self ::Item > {
None
}
}
2020-10-06 12:07:34 -05:00
fn main ( ) {
2020-10-06 14:05:57 -05:00
let _x = MyIter ;
//^^ MyIter
2020-10-06 12:07:34 -05:00
let _x = iter ::repeat ( 0 ) ;
//^^ impl Iterator<Item = i32>
fn generic < T : Clone > ( t : T ) {
let _x = iter ::repeat ( t ) ;
//^^ impl Iterator<Item = T>
2020-10-07 04:30:42 -05:00
let _chained = iter ::repeat ( t ) . take ( 10 ) ;
//^^^^^^^^ impl Iterator<Item = T>
}
}
" #,
) ;
}
#[ test ]
fn shorten_iterator_chaining_hints ( ) {
check_expect (
InlayHintsConfig {
parameter_hints : false ,
type_hints : false ,
chaining_hints : true ,
max_length : None ,
} ,
r #"
use core ::iter ;
struct MyIter ;
impl Iterator for MyIter {
type Item = ( ) ;
fn next ( & mut self ) -> Option < Self ::Item > {
None
2020-10-06 12:07:34 -05:00
}
}
2020-10-07 04:30:42 -05:00
fn main ( ) {
let _x = MyIter . by_ref ( )
. take ( 5 )
. by_ref ( )
. take ( 5 )
. by_ref ( ) ;
}
2020-10-03 00:37:58 -05:00
" #,
2020-10-07 04:30:42 -05:00
expect! [ [ r #"
[
InlayHint {
range : 175 .. 242 ,
kind : ChainingHint ,
label : " impl Iterator<Item = ()> " ,
} ,
InlayHint {
range : 175 .. 225 ,
kind : ChainingHint ,
2020-10-07 05:13:32 -05:00
label : " impl Iterator<Item = ()> " ,
2020-10-07 04:30:42 -05:00
} ,
InlayHint {
range : 175 .. 207 ,
kind : ChainingHint ,
label : " impl Iterator<Item = ()> " ,
} ,
InlayHint {
range : 175 .. 190 ,
kind : ChainingHint ,
label : " &mut MyIter " ,
} ,
]
" #]],
2020-09-13 12:24:04 -05:00
) ;
}
2020-10-10 11:51:02 -05:00
#[ test ]
fn shorten_iterators_in_associated_params ( ) {
check_with_config (
InlayHintsConfig {
parameter_hints : false ,
type_hints : true ,
2020-10-10 13:37:20 -05:00
chaining_hints : false ,
2020-10-10 11:51:02 -05:00
max_length : None ,
} ,
r #"
use core ::iter ;
pub struct SomeIter < T > { }
impl < T > SomeIter < T > {
pub fn new ( ) -> Self { SomeIter { } }
pub fn push ( & mut self , t : T ) { }
}
impl < T > Iterator for SomeIter < T > {
type Item = T ;
fn next ( & mut self ) -> Option < Self ::Item > {
None
}
}
fn main ( ) {
let mut some_iter = SomeIter ::new ( ) ;
//^^^^^^^^^^^^^ SomeIter<Take<Repeat<i32>>>
some_iter . push ( iter ::repeat ( 2 ) . take ( 2 ) ) ;
2020-10-10 13:37:20 -05:00
let iter_of_iters = some_iter . take ( 2 ) ;
//^^^^^^^^^^^^^ impl Iterator<Item = impl Iterator<Item = i32>>
2020-10-10 11:51:02 -05:00
}
2020-10-22 12:42:39 -05:00
" #,
) ;
}
#[ test ]
fn hide_param_hints_for_clones ( ) {
check_with_config (
InlayHintsConfig {
parameter_hints : true ,
type_hints : false ,
chaining_hints : false ,
max_length : None ,
} ,
r #"
fn foo ( bar : i32 , baz : String , qux : f32 ) { }
fn main ( ) {
let bar = 3 ;
let baz = & " baz " ;
let fez = 1.0 ;
foo ( bar . clone ( ) , baz . clone ( ) , fez . clone ( ) ) ;
//^^^^^^^^^^^ qux
}
2020-10-10 11:51:02 -05:00
" #,
) ;
}
2020-10-28 06:29:42 -05:00
#[ test ]
fn infer_call_method_return_associated_types_with_generic ( ) {
check (
r #"
pub trait Default {
fn default ( ) -> Self ;
}
pub trait Foo {
type Bar : Default ;
}
pub fn quux < T : Foo > ( ) -> T ::Bar {
let y = Default ::default ( ) ;
//^ <T as Foo>::Bar
y
}
" #,
) ;
}
2020-10-29 07:02:34 -05:00
#[ test ]
fn self_param_hints ( ) {
check (
r #"
struct Foo ;
impl Foo {
fn foo ( self : Self ) { }
fn bar ( self : & Self ) { }
}
fn main ( ) {
Foo ::foo ( Foo ) ;
//^^^ self
Foo ::bar ( & Foo ) ;
//^^^^ self
}
" #,
)
}
2019-07-19 16:20:09 -05:00
}