2023-12-05 14:42:39 +00:00
use std ::iter ;
2023-12-03 19:20:38 +00:00
use hir ::{ DescendPreference , Semantics } ;
2021-06-22 17:39:59 +00:00
use ide_db ::{
2023-05-02 06:52:08 +00:00
base_db ::{ FileId , FilePosition , FileRange } ,
2022-01-04 17:29:20 +00:00
defs ::{ Definition , IdentClass } ,
2022-03-06 18:01:30 +00:00
helpers ::pick_best_token ,
2021-10-02 09:18:18 +00:00
search ::{ FileReference , ReferenceCategory , SearchScope } ,
2023-05-15 18:13:05 +00:00
syntax_helpers ::node_ext ::{
for_each_break_and_continue_expr , for_each_tail_expr , full_path_of_name_ref , walk_expr ,
} ,
2022-04-25 16:51:59 +00:00
FxHashSet , RootDatabase ,
2021-06-22 17:39:59 +00:00
} ;
2021-06-24 15:19:27 +00:00
use syntax ::{
2021-09-27 10:54:24 +00:00
ast ::{ self , HasLoopBody } ,
2021-09-02 15:30:02 +00:00
match_ast , AstNode ,
2022-02-13 11:48:04 +00:00
SyntaxKind ::{ self , IDENT , INT_NUMBER } ,
2024-01-16 12:36:07 +00:00
SyntaxToken , TextRange , T ,
2021-06-24 15:19:27 +00:00
} ;
2021-06-22 17:39:59 +00:00
2024-01-16 12:36:07 +00:00
use crate ::{ navigation_target ::ToNav , NavigationTarget , TryToNav } ;
2021-06-22 17:39:59 +00:00
2021-08-28 22:45:55 +00:00
#[ derive(PartialEq, Eq, Hash) ]
2021-06-23 23:32:56 +00:00
pub struct HighlightedRange {
2021-06-22 17:39:59 +00:00
pub range : TextRange ,
2021-10-02 10:02:06 +00:00
// FIXME: This needs to be more precise. Reference category makes sense only
// for references, but we also have defs. And things like exit points are
// neither.
pub category : Option < ReferenceCategory > ,
2021-06-22 17:39:59 +00:00
}
2021-07-22 01:44:16 +00:00
#[ derive(Default, Clone) ]
pub struct HighlightRelatedConfig {
pub references : bool ,
pub exit_points : bool ,
pub break_points : bool ,
2023-05-02 06:52:08 +00:00
pub closure_captures : bool ,
2021-07-22 01:44:16 +00:00
pub yield_points : bool ,
}
2021-06-23 15:05:00 +00:00
// Feature: Highlight Related
2021-06-22 17:39:59 +00:00
//
2021-06-23 16:11:48 +00:00
// Highlights constructs related to the thing under the cursor:
2022-06-14 08:40:57 +00:00
//
// . if on an identifier, highlights all references to that identifier in the current file
2023-05-15 18:13:05 +00:00
// .. additionally, if the identifier is a trait in a where clause, type parameter trait bound or use item, highlights all references to that trait's assoc items in the corresponding scope
2023-11-13 12:13:39 +00:00
// . if on an `async` or `await` token, highlights all yield points for that async context
2022-06-14 08:40:57 +00:00
// . if on a `return` or `fn` keyword, `?` character or `->` return type arrow, highlights all exit points for that context
// . if on a `break`, `loop`, `while` or `for` token, highlights all break points for that loop or block context
2023-05-15 18:13:05 +00:00
// . if on a `move` or `|` token that belongs to a closure, highlights all captures of the closure.
2021-08-16 19:25:22 +00:00
//
2023-05-15 18:13:05 +00:00
// Note: `?`, `|` and `->` do not currently trigger this behavior in the VSCode editor.
2021-06-23 12:56:40 +00:00
pub ( crate ) fn highlight_related (
2022-07-20 13:02:08 +00:00
sema : & Semantics < '_ , RootDatabase > ,
2021-07-22 01:44:16 +00:00
config : HighlightRelatedConfig ,
2023-08-16 08:07:18 +00:00
pos @ FilePosition { offset , file_id } : FilePosition ,
2021-06-23 23:32:56 +00:00
) -> Option < Vec < HighlightedRange > > {
let _p = profile ::span ( " highlight_related " ) ;
2021-11-16 20:26:34 +00:00
let syntax = sema . parse ( file_id ) . syntax ( ) . clone ( ) ;
2021-06-23 12:56:40 +00:00
2021-11-16 20:26:34 +00:00
let token = pick_best_token ( syntax . token_at_offset ( offset ) , | kind | match kind {
2021-09-02 15:30:02 +00:00
T! [ ? ] = > 4 , // prefer `?` when the cursor is sandwiched like in `await$0?`
2023-05-15 17:35:27 +00:00
T! [ ->] = > 4 ,
kind if kind . is_keyword ( ) = > 3 ,
IDENT | INT_NUMBER = > 2 ,
T! [ | ] = > 1 ,
2021-06-23 12:56:40 +00:00
_ = > 0 ,
} ) ? ;
2023-05-02 06:52:08 +00:00
// most if not all of these should be re-implemented with information seeded from hir
2021-06-23 12:56:40 +00:00
match token . kind ( ) {
2021-08-18 13:02:31 +00:00
T! [ ? ] if config . exit_points & & token . parent ( ) . and_then ( ast ::TryExpr ::cast ) . is_some ( ) = > {
2021-08-16 19:25:22 +00:00
highlight_exit_points ( sema , token )
}
2021-08-18 13:02:31 +00:00
T! [ fn ] | T! [ return ] | T! [ ->] if config . exit_points = > highlight_exit_points ( sema , token ) ,
2021-07-22 01:44:16 +00:00
T! [ await ] | T! [ async ] if config . yield_points = > highlight_yield_points ( token ) ,
2021-08-18 13:02:31 +00:00
T! [ for ] if config . break_points & & token . parent ( ) . and_then ( ast ::ForExpr ::cast ) . is_some ( ) = > {
2021-07-22 01:44:16 +00:00
highlight_break_points ( token )
}
2022-02-13 11:48:04 +00:00
T! [ break ] | T! [ loop ] | T! [ while ] | T! [ continue ] if config . break_points = > {
highlight_break_points ( token )
}
2023-05-02 06:56:48 +00:00
T! [ | ] if config . closure_captures = > highlight_closure_captures ( sema , token , file_id ) ,
T! [ move ] if config . closure_captures = > highlight_closure_captures ( sema , token , file_id ) ,
2024-01-16 12:36:07 +00:00
_ if config . references = > highlight_references ( sema , token , pos ) ,
2021-07-22 01:44:16 +00:00
_ = > None ,
2021-06-23 12:56:40 +00:00
}
}
2023-05-02 06:52:08 +00:00
fn highlight_closure_captures (
sema : & Semantics < '_ , RootDatabase > ,
2023-05-02 06:56:48 +00:00
token : SyntaxToken ,
2023-05-02 06:52:08 +00:00
file_id : FileId ,
) -> Option < Vec < HighlightedRange > > {
2023-05-02 06:56:48 +00:00
let closure = token . parent_ancestors ( ) . take ( 2 ) . find_map ( ast ::ClosureExpr ::cast ) ? ;
let search_range = closure . body ( ) ? . syntax ( ) . text_range ( ) ;
let ty = & sema . type_of_expr ( & closure . into ( ) ) ? . original ;
2023-05-02 06:52:08 +00:00
let c = ty . as_closure ( ) ? ;
Some (
c . captured_items ( sema . db )
. into_iter ( )
. map ( | capture | capture . local ( ) )
. flat_map ( | local | {
let usages = Definition ::Local ( local )
. usages ( sema )
2023-07-09 21:20:18 +00:00
. in_scope ( & SearchScope ::file_range ( FileRange { file_id , range : search_range } ) )
2023-05-02 06:52:08 +00:00
. include_self_refs ( )
. all ( )
. references
. remove ( & file_id )
. into_iter ( )
. flatten ( )
. map ( | FileReference { category , range , .. } | HighlightedRange {
range ,
category ,
} ) ;
let category = local . is_mut ( sema . db ) . then_some ( ReferenceCategory ::Write ) ;
local
. sources ( sema . db )
. into_iter ( )
2023-12-06 10:53:28 +00:00
. flat_map ( | x | x . to_nav ( sema . db ) )
2023-05-02 06:52:08 +00:00
. filter ( | decl | decl . file_id = = file_id )
. filter_map ( | decl | decl . focus_range )
. map ( move | range | HighlightedRange { range , category } )
. chain ( usages )
} )
. collect ( ) ,
)
}
2021-06-23 14:43:53 +00:00
fn highlight_references (
2022-07-20 13:02:08 +00:00
sema : & Semantics < '_ , RootDatabase > ,
2021-11-16 20:26:34 +00:00
token : SyntaxToken ,
2023-08-16 08:07:18 +00:00
FilePosition { file_id , offset } : FilePosition ,
2021-06-23 23:32:56 +00:00
) -> Option < Vec < HighlightedRange > > {
2023-12-05 14:42:39 +00:00
let defs = if let Some ( ( range , resolution ) ) =
sema . check_for_format_args_template ( token . clone ( ) , offset )
{
match resolution . map ( Definition ::from ) {
Some ( def ) = > iter ::once ( def ) . collect ( ) ,
None = > return Some ( vec! [ HighlightedRange { range , category : None } ] ) ,
}
} else {
find_defs ( sema , token . clone ( ) )
} ;
2021-08-24 01:14:03 +00:00
let usages = defs
. iter ( )
2021-09-02 15:30:02 +00:00
. filter_map ( | & d | {
2021-08-24 01:14:03 +00:00
d . usages ( sema )
2023-07-09 21:20:18 +00:00
. in_scope ( & SearchScope ::single_file ( file_id ) )
2021-08-24 01:14:03 +00:00
. include_self_refs ( )
. all ( )
. references
. remove ( & file_id )
} )
. flatten ( )
2023-05-02 06:52:08 +00:00
. map ( | FileReference { category , range , .. } | HighlightedRange { range , category } ) ;
2022-03-04 18:49:08 +00:00
let mut res = FxHashSet ::default ( ) ;
for & def in & defs {
2023-05-15 18:13:05 +00:00
// highlight trait usages
if let Definition ::Trait ( t ) = def {
let trait_item_use_scope = ( | | {
let name_ref = token . parent ( ) . and_then ( ast ::NameRef ::cast ) ? ;
let path = full_path_of_name_ref ( & name_ref ) ? ;
let parent = path . syntax ( ) . parent ( ) ? ;
match_ast! {
match parent {
ast ::UseTree ( it ) = > it . syntax ( ) . ancestors ( ) . find ( | it | {
ast ::SourceFile ::can_cast ( it . kind ( ) ) | | ast ::Module ::can_cast ( it . kind ( ) )
} ) ,
ast ::PathType ( it ) = > it
. syntax ( )
. ancestors ( )
. nth ( 2 )
. and_then ( ast ::TypeBoundList ::cast ) ?
. syntax ( )
. parent ( )
. filter ( | it | ast ::WhereClause ::can_cast ( it . kind ( ) ) | | ast ::TypeParam ::can_cast ( it . kind ( ) ) ) ?
. ancestors ( )
. find ( | it | {
ast ::Item ::can_cast ( it . kind ( ) )
} ) ,
_ = > None ,
}
}
} ) ( ) ;
if let Some ( trait_item_use_scope ) = trait_item_use_scope {
res . extend (
t . items_with_supertraits ( sema . db )
. into_iter ( )
. filter_map ( | item | {
Definition ::from ( item )
. usages ( sema )
2023-07-09 21:20:18 +00:00
. set_scope ( Some ( & SearchScope ::file_range ( FileRange {
2023-05-15 18:13:05 +00:00
file_id ,
range : trait_item_use_scope . text_range ( ) ,
} ) ) )
. include_self_refs ( )
. all ( )
. references
. remove ( & file_id )
} )
. flatten ( )
. map ( | FileReference { category , range , .. } | HighlightedRange {
range ,
category ,
} ) ,
) ;
}
}
// highlight the defs themselves
2022-03-04 18:49:08 +00:00
match def {
2023-02-18 20:32:55 +00:00
Definition ::Local ( local ) = > {
let category = local . is_mut ( sema . db ) . then_some ( ReferenceCategory ::Write ) ;
local
. sources ( sema . db )
. into_iter ( )
2023-12-06 10:53:28 +00:00
. flat_map ( | x | x . to_nav ( sema . db ) )
2023-02-18 20:32:55 +00:00
. filter ( | decl | decl . file_id = = file_id )
. filter_map ( | decl | decl . focus_range )
. map ( | range | HighlightedRange { range , category } )
. for_each ( | x | {
res . insert ( x ) ;
} ) ;
}
def = > {
2023-12-06 10:53:28 +00:00
let navs = match def {
2023-02-18 20:32:55 +00:00
Definition ::Module ( module ) = > {
2023-12-06 10:53:28 +00:00
NavigationTarget ::from_module_to_decl ( sema . db , module )
}
def = > match def . try_to_nav ( sema . db ) {
Some ( it ) = > it ,
None = > continue ,
} ,
} ;
for nav in navs {
if nav . file_id ! = file_id {
continue ;
}
let hl_range = nav . focus_range . map ( | range | {
2024-01-16 12:36:07 +00:00
let category = matches! ( def , Definition ::Local ( l ) if l . is_mut ( sema . db ) )
2023-12-06 10:53:28 +00:00
. then_some ( ReferenceCategory ::Write ) ;
HighlightedRange { range , category }
} ) ;
if let Some ( hl_range ) = hl_range {
res . insert ( hl_range ) ;
2023-02-18 20:32:55 +00:00
}
}
}
2022-03-04 18:49:08 +00:00
}
}
2021-06-23 14:43:53 +00:00
2022-03-04 18:49:08 +00:00
res . extend ( usages ) ;
2021-08-28 19:37:27 +00:00
if res . is_empty ( ) {
None
} else {
2021-08-28 22:45:55 +00:00
Some ( res . into_iter ( ) . collect ( ) )
2021-08-28 19:37:27 +00:00
}
2021-06-23 14:43:53 +00:00
}
2021-06-23 15:21:47 +00:00
fn highlight_exit_points (
2022-07-20 13:02:08 +00:00
sema : & Semantics < '_ , RootDatabase > ,
2021-06-23 15:21:47 +00:00
token : SyntaxToken ,
2021-06-23 23:32:56 +00:00
) -> Option < Vec < HighlightedRange > > {
2021-06-23 15:21:47 +00:00
fn hl (
2022-07-20 13:02:08 +00:00
sema : & Semantics < '_ , RootDatabase > ,
2023-05-02 06:37:40 +00:00
def_ranges : [ Option < TextRange > ; 2 ] ,
2021-06-23 15:21:47 +00:00
body : Option < ast ::Expr > ,
2021-06-23 23:32:56 +00:00
) -> Option < Vec < HighlightedRange > > {
2021-06-23 14:43:53 +00:00
let mut highlights = Vec ::new ( ) ;
2023-05-02 06:37:40 +00:00
highlights . extend (
def_ranges
. into_iter ( )
. flatten ( )
. map ( | range | HighlightedRange { category : None , range } ) ,
) ;
2021-06-23 14:43:53 +00:00
let body = body ? ;
2021-09-26 14:29:42 +00:00
walk_expr ( & body , & mut | expr | match expr {
2021-06-24 15:19:27 +00:00
ast ::Expr ::ReturnExpr ( expr ) = > {
if let Some ( token ) = expr . return_token ( ) {
2021-10-02 10:02:06 +00:00
highlights . push ( HighlightedRange { category : None , range : token . text_range ( ) } ) ;
2021-06-24 14:50:56 +00:00
}
2021-06-24 15:19:27 +00:00
}
ast ::Expr ::TryExpr ( try_ ) = > {
if let Some ( token ) = try_ . question_mark_token ( ) {
2021-10-02 10:02:06 +00:00
highlights . push ( HighlightedRange { category : None , range : token . text_range ( ) } ) ;
2021-06-24 14:50:56 +00:00
}
2021-06-24 15:19:27 +00:00
}
2022-04-05 15:42:07 +00:00
ast ::Expr ::MethodCallExpr ( _ ) | ast ::Expr ::CallExpr ( _ ) | ast ::Expr ::MacroExpr ( _ ) = > {
2021-08-03 15:28:51 +00:00
if sema . type_of_expr ( & expr ) . map_or ( false , | ty | ty . original . is_never ( ) ) {
2021-10-02 10:02:06 +00:00
highlights . push ( HighlightedRange {
category : None ,
range : expr . syntax ( ) . text_range ( ) ,
} ) ;
2021-06-23 14:43:53 +00:00
}
}
2021-06-24 15:19:27 +00:00
_ = > ( ) ,
2021-06-23 14:43:53 +00:00
} ) ;
let tail = match body {
ast ::Expr ::BlockExpr ( b ) = > b . tail_expr ( ) ,
e = > Some ( e ) ,
} ;
2021-06-24 14:50:56 +00:00
2021-06-23 14:43:53 +00:00
if let Some ( tail ) = tail {
2021-06-26 23:11:57 +00:00
for_each_tail_expr ( & tail , & mut | tail | {
2021-06-24 18:57:02 +00:00
let range = match tail {
ast ::Expr ::BreakExpr ( b ) = > b
. break_token ( )
. map_or_else ( | | tail . syntax ( ) . text_range ( ) , | tok | tok . text_range ( ) ) ,
_ = > tail . syntax ( ) . text_range ( ) ,
} ;
2021-10-02 10:02:06 +00:00
highlights . push ( HighlightedRange { category : None , range } )
2021-06-24 15:19:27 +00:00
} ) ;
2021-06-23 14:43:53 +00:00
}
Some ( highlights )
}
2022-06-10 14:30:09 +00:00
for anc in token . parent_ancestors ( ) {
2021-06-23 14:43:53 +00:00
return match_ast! {
match anc {
2023-05-02 06:37:40 +00:00
ast ::Fn ( fn_ ) = > hl ( sema , [ fn_ . fn_token ( ) . map ( | it | it . text_range ( ) ) , None ] , fn_ . body ( ) . map ( ast ::Expr ::BlockExpr ) ) ,
ast ::ClosureExpr ( closure ) = > hl (
sema ,
closure . param_list ( ) . map_or ( [ None ; 2 ] , | p | [ p . l_paren_token ( ) . map ( | it | it . text_range ( ) ) , p . r_paren_token ( ) . map ( | it | it . text_range ( ) ) ] ) ,
closure . body ( )
) ,
2021-09-26 09:12:57 +00:00
ast ::BlockExpr ( block_expr ) = > if matches! ( block_expr . modifier ( ) , Some ( ast ::BlockModifier ::Async ( _ ) | ast ::BlockModifier ::Try ( _ ) | ast ::BlockModifier ::Const ( _ ) ) ) {
2023-05-02 06:37:40 +00:00
hl (
sema ,
[ block_expr . modifier ( ) . and_then ( | modifier | match modifier {
ast ::BlockModifier ::Async ( t ) | ast ::BlockModifier ::Try ( t ) | ast ::BlockModifier ::Const ( t ) = > Some ( t . text_range ( ) ) ,
_ = > None ,
} ) , None ] ,
Some ( block_expr . into ( ) )
)
2021-06-23 14:43:53 +00:00
} else {
continue ;
} ,
_ = > continue ,
}
} ;
}
2021-06-23 12:56:40 +00:00
None
}
2021-06-24 18:57:02 +00:00
fn highlight_break_points ( token : SyntaxToken ) -> Option < Vec < HighlightedRange > > {
fn hl (
2022-02-13 11:48:04 +00:00
cursor_token_kind : SyntaxKind ,
2021-06-24 18:57:02 +00:00
token : Option < SyntaxToken > ,
label : Option < ast ::Label > ,
2021-09-26 09:12:57 +00:00
body : Option < ast ::StmtList > ,
2021-06-24 18:57:02 +00:00
) -> Option < Vec < HighlightedRange > > {
let mut highlights = Vec ::new ( ) ;
let range = cover_range (
token . map ( | tok | tok . text_range ( ) ) ,
label . as_ref ( ) . map ( | it | it . syntax ( ) . text_range ( ) ) ,
) ;
2021-10-02 10:02:06 +00:00
highlights . extend ( range . map ( | range | HighlightedRange { category : None , range } ) ) ;
2022-02-13 11:48:04 +00:00
for_each_break_and_continue_expr ( label , body , & mut | expr | {
let range : Option < TextRange > = match ( cursor_token_kind , expr ) {
( T! [ for ] | T! [ while ] | T! [ loop ] | T! [ break ] , ast ::Expr ::BreakExpr ( break_ ) ) = > {
cover_range (
break_ . break_token ( ) . map ( | it | it . text_range ( ) ) ,
break_ . lifetime ( ) . map ( | it | it . syntax ( ) . text_range ( ) ) ,
)
}
(
T! [ for ] | T! [ while ] | T! [ loop ] | T! [ continue ] ,
ast ::Expr ::ContinueExpr ( continue_ ) ,
) = > cover_range (
continue_ . continue_token ( ) . map ( | it | it . text_range ( ) ) ,
continue_ . lifetime ( ) . map ( | it | it . syntax ( ) . text_range ( ) ) ,
2022-02-13 11:04:51 +00:00
) ,
_ = > None ,
} ;
2021-10-02 10:02:06 +00:00
highlights . extend ( range . map ( | range | HighlightedRange { category : None , range } ) ) ;
2021-06-24 18:57:02 +00:00
} ) ;
Some ( highlights )
}
let parent = token . parent ( ) ? ;
let lbl = match_ast! {
match parent {
ast ::BreakExpr ( b ) = > b . lifetime ( ) ,
2022-02-13 11:48:04 +00:00
ast ::ContinueExpr ( c ) = > c . lifetime ( ) ,
2021-06-24 18:57:02 +00:00
ast ::LoopExpr ( l ) = > l . label ( ) . and_then ( | it | it . lifetime ( ) ) ,
ast ::ForExpr ( f ) = > f . label ( ) . and_then ( | it | it . lifetime ( ) ) ,
ast ::WhileExpr ( w ) = > w . label ( ) . and_then ( | it | it . lifetime ( ) ) ,
2021-09-26 09:12:57 +00:00
ast ::BlockExpr ( b ) = > Some ( b . label ( ) . and_then ( | it | it . lifetime ( ) ) ? ) ,
2021-06-24 18:57:02 +00:00
_ = > return None ,
}
} ;
let lbl = lbl . as_ref ( ) ;
let label_matches = | def_lbl : Option < ast ::Label > | match lbl {
Some ( lbl ) = > {
Some ( lbl . text ( ) ) = = def_lbl . and_then ( | it | it . lifetime ( ) ) . as_ref ( ) . map ( | it | it . text ( ) )
}
None = > true ,
} ;
2022-02-13 11:48:04 +00:00
let token_kind = token . kind ( ) ;
2022-06-10 14:30:09 +00:00
for anc in token . parent_ancestors ( ) . flat_map ( ast ::Expr ::cast ) {
2021-06-24 18:57:02 +00:00
return match anc {
2022-02-13 11:48:04 +00:00
ast ::Expr ::LoopExpr ( l ) if label_matches ( l . label ( ) ) = > hl (
token_kind ,
l . loop_token ( ) ,
l . label ( ) ,
l . loop_body ( ) . and_then ( | it | it . stmt_list ( ) ) ,
) ,
ast ::Expr ::ForExpr ( f ) if label_matches ( f . label ( ) ) = > hl (
token_kind ,
f . for_token ( ) ,
f . label ( ) ,
f . loop_body ( ) . and_then ( | it | it . stmt_list ( ) ) ,
) ,
ast ::Expr ::WhileExpr ( w ) if label_matches ( w . label ( ) ) = > hl (
token_kind ,
w . while_token ( ) ,
w . label ( ) ,
w . loop_body ( ) . and_then ( | it | it . stmt_list ( ) ) ,
) ,
2021-09-26 09:12:57 +00:00
ast ::Expr ::BlockExpr ( e ) if e . label ( ) . is_some ( ) & & label_matches ( e . label ( ) ) = > {
2022-02-13 11:48:04 +00:00
hl ( token_kind , None , e . label ( ) , e . stmt_list ( ) )
2021-06-24 18:57:02 +00:00
}
_ = > continue ,
} ;
}
None
}
2021-06-23 23:32:56 +00:00
fn highlight_yield_points ( token : SyntaxToken ) -> Option < Vec < HighlightedRange > > {
2021-06-23 14:16:32 +00:00
fn hl (
async_token : Option < SyntaxToken > ,
2021-06-23 15:05:00 +00:00
body : Option < ast ::Expr > ,
2021-06-23 23:32:56 +00:00
) -> Option < Vec < HighlightedRange > > {
2021-07-22 06:03:54 +00:00
let mut highlights =
2021-10-02 10:02:06 +00:00
vec! [ HighlightedRange { category : None , range : async_token ? . text_range ( ) } ] ;
2021-06-23 14:16:32 +00:00
if let Some ( body ) = body {
2021-09-26 14:29:42 +00:00
walk_expr ( & body , & mut | expr | {
2021-06-24 15:19:27 +00:00
if let ast ::Expr ::AwaitExpr ( expr ) = expr {
if let Some ( token ) = expr . await_token ( ) {
highlights
2021-10-02 10:02:06 +00:00
. push ( HighlightedRange { category : None , range : token . text_range ( ) } ) ;
2021-06-23 14:16:32 +00:00
}
}
2021-06-23 14:43:53 +00:00
} ) ;
2021-06-23 14:16:32 +00:00
}
Some ( highlights )
}
2022-06-10 14:30:09 +00:00
for anc in token . parent_ancestors ( ) {
2021-06-23 14:16:32 +00:00
return match_ast! {
match anc {
2021-06-23 15:05:00 +00:00
ast ::Fn ( fn_ ) = > hl ( fn_ . async_token ( ) , fn_ . body ( ) . map ( ast ::Expr ::BlockExpr ) ) ,
2021-09-26 09:12:57 +00:00
ast ::BlockExpr ( block_expr ) = > {
if block_expr . async_token ( ) . is_none ( ) {
continue ;
}
hl ( block_expr . async_token ( ) , Some ( block_expr . into ( ) ) )
} ,
2021-06-23 15:05:00 +00:00
ast ::ClosureExpr ( closure ) = > hl ( closure . async_token ( ) , closure . body ( ) ) ,
2021-06-23 14:16:32 +00:00
_ = > continue ,
}
} ;
}
2021-06-23 12:56:40 +00:00
None
}
2021-06-24 18:57:02 +00:00
fn cover_range ( r0 : Option < TextRange > , r1 : Option < TextRange > ) -> Option < TextRange > {
match ( r0 , r1 ) {
( Some ( r0 ) , Some ( r1 ) ) = > Some ( r0 . cover ( r1 ) ) ,
( Some ( range ) , None ) = > Some ( range ) ,
( None , Some ( range ) ) = > Some ( range ) ,
( None , None ) = > None ,
}
}
2023-12-05 14:42:39 +00:00
fn find_defs ( sema : & Semantics < '_ , RootDatabase > , token : SyntaxToken ) -> FxHashSet < Definition > {
sema . descend_into_macros ( DescendPreference ::None , token )
2021-11-16 20:26:34 +00:00
. into_iter ( )
2022-08-05 12:16:36 +00:00
. filter_map ( | token | IdentClass ::classify_token ( sema , & token ) )
2024-01-18 12:59:49 +00:00
. flat_map ( IdentClass ::definitions_no_ops )
2021-08-28 19:37:27 +00:00
. collect ( )
2021-08-24 01:14:03 +00:00
}
2021-06-22 17:39:59 +00:00
#[ cfg(test) ]
mod tests {
use crate ::fixture ;
use super ::* ;
2023-05-02 06:52:08 +00:00
const ENABLED_CONFIG : HighlightRelatedConfig = HighlightRelatedConfig {
break_points : true ,
exit_points : true ,
references : true ,
closure_captures : true ,
yield_points : true ,
} ;
2022-03-04 18:49:08 +00:00
#[ track_caller ]
2021-06-22 17:39:59 +00:00
fn check ( ra_fixture : & str ) {
2023-05-02 06:52:08 +00:00
check_with_config ( ra_fixture , ENABLED_CONFIG ) ;
2021-07-23 00:59:31 +00:00
}
2022-03-04 18:49:08 +00:00
#[ track_caller ]
2021-07-23 00:59:31 +00:00
fn check_with_config ( ra_fixture : & str , config : HighlightRelatedConfig ) {
let ( analysis , pos , annotations ) = fixture ::annotations ( ra_fixture ) ;
2021-10-16 11:32:55 +00:00
let hls = analysis . highlight_related ( config , pos ) . unwrap ( ) . unwrap_or_default ( ) ;
2021-06-22 17:39:59 +00:00
let mut expected = annotations
. into_iter ( )
2022-12-30 08:30:23 +00:00
. map ( | ( r , access ) | ( r . range , ( ! access . is_empty ( ) ) . then_some ( access ) ) )
2021-06-22 17:39:59 +00:00
. collect ::< Vec < _ > > ( ) ;
let mut actual = hls
. into_iter ( )
. map ( | hl | {
(
hl . range ,
2021-10-02 10:02:06 +00:00
hl . category . map ( | it | {
2021-06-22 17:39:59 +00:00
match it {
2021-10-02 09:18:18 +00:00
ReferenceCategory ::Read = > " read " ,
ReferenceCategory ::Write = > " write " ,
2022-09-13 12:47:26 +00:00
ReferenceCategory ::Import = > " import " ,
2021-06-22 17:39:59 +00:00
}
. to_string ( )
} ) ,
)
} )
. collect ::< Vec < _ > > ( ) ;
actual . sort_by_key ( | ( range , _ ) | range . start ( ) ) ;
expected . sort_by_key ( | ( range , _ ) | range . start ( ) ) ;
assert_eq! ( expected , actual ) ;
}
2021-11-25 15:34:32 +00:00
#[ test ]
fn test_hl_tuple_fields ( ) {
check (
r #"
struct Tuple ( u32 , u32 ) ;
fn foo ( t : Tuple ) {
t . 0 $ 0 ;
// ^ read
t . 0 ;
// ^ read
}
" #,
) ;
}
2021-06-22 17:39:59 +00:00
#[ test ]
fn test_hl_module ( ) {
check (
r #"
//- /lib.rs
mod foo $ 0 ;
// ^^^
//- /foo.rs
struct Foo ;
" #,
) ;
}
#[ test ]
fn test_hl_self_in_crate_root ( ) {
check (
r #"
2021-12-20 16:48:47 +00:00
use crate $ 0 ;
2022-09-13 12:47:26 +00:00
//^^^^^ import
2021-12-20 16:48:47 +00:00
use self ;
2022-09-13 12:47:26 +00:00
//^^^^ import
2021-12-20 16:48:47 +00:00
mod __ {
use super ;
2022-09-13 12:47:26 +00:00
//^^^^^ import
2021-12-20 16:48:47 +00:00
}
" #,
) ;
check (
r #"
//- /main.rs crate:main deps:lib
use lib $ 0 ;
2022-09-13 12:47:26 +00:00
//^^^ import
2021-12-20 16:48:47 +00:00
//- /lib.rs crate:lib
2021-06-22 17:39:59 +00:00
" #,
) ;
}
#[ test ]
fn test_hl_self_in_module ( ) {
check (
r #"
//- /lib.rs
mod foo ;
//- /foo.rs
use self $ 0 ;
2022-09-13 12:47:26 +00:00
// ^^^^ import
2021-06-22 17:39:59 +00:00
" #,
) ;
}
#[ test ]
fn test_hl_local ( ) {
check (
r #"
fn foo ( ) {
let mut bar = 3 ;
// ^^^ write
bar $ 0 ;
// ^^^ read
}
2021-06-23 14:16:32 +00:00
" #,
) ;
}
2021-09-14 00:49:06 +00:00
#[ test ]
fn test_hl_local_in_attr ( ) {
check (
r #"
//- proc_macros: identity
#[ proc_macros::identity ]
fn foo ( ) {
let mut bar = 3 ;
// ^^^ write
bar $ 0 ;
// ^^^ read
}
" #,
) ;
}
2021-08-28 19:37:27 +00:00
#[ test ]
fn test_multi_macro_usage ( ) {
check (
r #"
macro_rules ! foo {
( $ident :ident ) = > {
fn $ident ( ) -> $ident { loop { } }
struct $ident ;
}
}
foo! ( bar $ 0 ) ;
// ^^^
fn foo ( ) {
let bar : bar = bar ( ) ;
// ^^^
// ^^^
}
" #,
) ;
check (
r #"
macro_rules ! foo {
( $ident :ident ) = > {
fn $ident ( ) -> $ident { loop { } }
struct $ident ;
}
}
foo! ( bar ) ;
// ^^^
fn foo ( ) {
let bar : bar $ 0 = bar ( ) ;
// ^^^
}
" #,
) ;
}
2021-06-23 14:16:32 +00:00
#[ test ]
fn test_hl_yield_points ( ) {
check (
r #"
pub async fn foo ( ) {
// ^^^^^
let x = foo ( )
. await $ 0
// ^^^^^
. await ;
// ^^^^^
| | { 0. await } ;
( async { 0. await } ) . await
// ^^^^^
}
" #,
) ;
}
#[ test ]
fn test_hl_yield_points2 ( ) {
check (
r #"
pub async $ 0 fn foo ( ) {
// ^^^^^
let x = foo ( )
. await
// ^^^^^
. await ;
// ^^^^^
| | { 0. await } ;
( async { 0. await } ) . await
// ^^^^^
}
" #,
) ;
}
2023-05-18 22:30:27 +00:00
#[ test ]
fn test_hl_let_else_yield_points ( ) {
check (
r #"
pub async fn foo ( ) {
// ^^^^^
let x = foo ( )
. await $ 0
// ^^^^^
. await ;
// ^^^^^
| | { 0. await } ;
let Some ( _ ) = None else {
foo ( ) . await
// ^^^^^
} ;
( async { 0. await } ) . await
// ^^^^^
}
" #,
) ;
}
2021-06-23 14:16:32 +00:00
#[ test ]
fn test_hl_yield_nested_fn ( ) {
check (
r #"
async fn foo ( ) {
async fn foo2 ( ) {
// ^^^^^
async fn foo3 ( ) {
0. await
}
0. await $ 0
// ^^^^^
}
0. await
}
" #,
) ;
}
#[ test ]
fn test_hl_yield_nested_async_blocks ( ) {
check (
r #"
async fn foo ( ) {
( async {
// ^^^^^
( async {
0. await
} ) . await $ 0 }
// ^^^^^
) . await ;
}
2021-06-23 14:43:53 +00:00
" #,
) ;
}
#[ test ]
fn test_hl_exit_points ( ) {
check (
r #"
2023-05-02 06:37:40 +00:00
fn foo ( ) -> u32 {
//^^
2021-06-23 14:43:53 +00:00
if true {
return $ 0 0 ;
// ^^^^^^
}
0 ? ;
// ^
0xDEAD_BEEF
// ^^^^^^^^^^^
}
" #,
) ;
}
#[ test ]
fn test_hl_exit_points2 ( ) {
check (
r #"
2023-05-02 06:37:40 +00:00
fn foo ( ) ->$ 0 u32 {
//^^
2021-06-23 14:43:53 +00:00
if true {
return 0 ;
// ^^^^^^
}
0 ? ;
// ^
0xDEAD_BEEF
// ^^^^^^^^^^^
}
" #,
) ;
}
2021-08-16 19:25:22 +00:00
#[ test ]
fn test_hl_exit_points3 ( ) {
check (
r #"
2023-05-02 06:37:40 +00:00
fn $ 0 foo ( ) -> u32 {
//^^
2021-08-16 19:25:22 +00:00
if true {
return 0 ;
// ^^^^^^
}
0 ? ;
// ^
0xDEAD_BEEF
// ^^^^^^^^^^^
}
" #,
) ;
}
2023-05-18 22:30:27 +00:00
#[ test ]
fn test_hl_let_else_exit_points ( ) {
check (
r #"
fn $ 0 foo ( ) -> u32 {
//^^
let Some ( bar ) = None else {
return 0 ;
// ^^^^^^
} ;
0 ? ;
// ^
0xDEAD_BEEF
// ^^^^^^^^^^^
}
" #,
) ;
}
2021-06-23 14:43:53 +00:00
#[ test ]
fn test_hl_prefer_ref_over_tail_exit ( ) {
check (
r #"
fn foo ( ) -> u32 {
// ^^^
if true {
return 0 ;
}
0 ? ;
foo $ 0 ( )
// ^^^
}
2021-06-23 15:21:47 +00:00
" #,
) ;
}
#[ test ]
fn test_hl_never_call_is_exit_point ( ) {
check (
r #"
struct Never ;
impl Never {
fn never ( self ) -> ! { loop { } }
}
macro_rules ! never {
( ) = > { never ( ) }
}
fn never ( ) -> ! { loop { } }
2023-05-02 06:37:40 +00:00
fn foo ( ) ->$ 0 u32 {
//^^
2021-06-23 15:21:47 +00:00
never ( ) ;
// ^^^^^^^
never! ( ) ;
2022-07-01 12:43:57 +00:00
// ^^^^^^^^
2021-06-23 15:21:47 +00:00
Never . never ( ) ;
// ^^^^^^^^^^^^^
0
// ^
}
2021-06-24 15:19:27 +00:00
" #,
) ;
}
#[ test ]
fn test_hl_inner_tail_exit_points ( ) {
check (
r #"
2023-05-02 06:37:40 +00:00
fn foo ( ) ->$ 0 u32 {
//^^
2021-06-24 15:19:27 +00:00
if true {
unsafe {
return 5 ;
// ^^^^^^
5
// ^
}
2021-07-31 18:00:09 +00:00
} else if false {
0
// ^
2021-06-24 15:19:27 +00:00
} else {
match 5 {
6 = > 100 ,
// ^^^
7 = > loop {
break 5 ;
2021-06-24 18:57:02 +00:00
// ^^^^^
2021-06-24 15:19:27 +00:00
}
8 = > ' a : loop {
' b : loop {
break 'a 5 ;
2021-06-24 18:57:02 +00:00
// ^^^^^
2021-06-24 15:19:27 +00:00
break 'b 5 ;
break 5 ;
} ;
}
//
_ = > 500 ,
// ^^^
}
}
}
2021-06-24 18:57:02 +00:00
" #,
) ;
}
2021-06-24 19:01:37 +00:00
#[ test ]
fn test_hl_inner_tail_exit_points_labeled_block ( ) {
check (
r #"
2023-05-02 06:37:40 +00:00
fn foo ( ) ->$ 0 u32 {
//^^
2021-06-24 19:01:37 +00:00
' foo : {
break 'foo 0 ;
// ^^^^^
loop {
break ;
break 'foo 0 ;
// ^^^^^
}
0
// ^
}
}
" #,
) ;
}
2022-12-31 11:08:25 +00:00
#[ test ]
fn test_hl_inner_tail_exit_points_loops ( ) {
check (
r #"
2023-05-02 06:37:40 +00:00
fn foo ( ) ->$ 0 u32 {
//^^
2022-12-31 11:08:25 +00:00
' foo : while { return 0 ; true } {
// ^^^^^^
break 'foo 0 ;
// ^^^^^
return 0 ;
// ^^^^^^
}
}
" #,
) ;
}
2021-06-24 18:57:02 +00:00
#[ test ]
fn test_hl_break_loop ( ) {
check (
r #"
fn foo ( ) {
' outer : loop {
// ^^^^^^^^^^^^
break ;
// ^^^^^
' inner : loop {
break ;
' innermost : loop {
break 'outer ;
// ^^^^^^^^^^^^
break 'inner ;
}
break $ 0 ' outer ;
// ^^^^^^^^^^^^
break ;
}
break ;
// ^^^^^
}
}
" #,
) ;
}
2021-06-24 19:14:43 +00:00
#[ test ]
fn test_hl_break_loop2 ( ) {
check (
r #"
fn foo ( ) {
' outer : loop {
break ;
' inner : loop {
// ^^^^^^^^^^^^
break ;
// ^^^^^
' innermost : loop {
break 'outer ;
break 'inner ;
// ^^^^^^^^^^^^
}
break 'outer ;
break $ 0 ;
// ^^^^^
}
break ;
}
}
" #,
) ;
}
2021-06-24 18:57:02 +00:00
#[ test ]
fn test_hl_break_for ( ) {
check (
r #"
fn foo ( ) {
' outer : for _ in ( ) {
// ^^^^^^^^^^^
break ;
// ^^^^^
' inner : for _ in ( ) {
break ;
' innermost : for _ in ( ) {
break 'outer ;
// ^^^^^^^^^^^^
break 'inner ;
}
break $ 0 ' outer ;
// ^^^^^^^^^^^^
break ;
}
break ;
// ^^^^^
}
}
" #,
) ;
}
2022-02-13 03:05:52 +00:00
#[ test ]
fn test_hl_break_for_but_not_continue ( ) {
check (
r #"
fn foo ( ) {
' outer : for _ in ( ) {
// ^^^^^^^^^^^
break ;
// ^^^^^
continue ;
' inner : for _ in ( ) {
break ;
continue ;
' innermost : for _ in ( ) {
continue 'outer ;
break 'outer ;
// ^^^^^^^^^^^^
continue 'inner ;
break 'inner ;
}
break $ 0 ' outer ;
// ^^^^^^^^^^^^
continue 'outer ;
break ;
continue ;
}
break ;
// ^^^^^
continue ;
}
}
" #,
) ;
}
#[ test ]
fn test_hl_continue_for_but_not_break ( ) {
check (
r #"
fn foo ( ) {
' outer : for _ in ( ) {
// ^^^^^^^^^^^
break ;
continue ;
// ^^^^^^^^
' inner : for _ in ( ) {
break ;
continue ;
' innermost : for _ in ( ) {
continue 'outer ;
// ^^^^^^^^^^^^^^^
break 'outer ;
continue 'inner ;
break 'inner ;
}
break 'outer ;
continue $ 0 ' outer ;
// ^^^^^^^^^^^^^^^
break ;
continue ;
}
break ;
continue ;
// ^^^^^^^^
}
}
" #,
) ;
}
#[ test ]
fn test_hl_break_and_continue ( ) {
check (
r #"
fn foo ( ) {
2022-02-13 11:48:04 +00:00
' outer : fo $ 0 r _ in ( ) {
2022-02-13 03:05:52 +00:00
// ^^^^^^^^^^^
break ;
// ^^^^^
continue ;
// ^^^^^^^^
' inner : for _ in ( ) {
break ;
continue ;
' innermost : for _ in ( ) {
continue 'outer ;
// ^^^^^^^^^^^^^^^
break 'outer ;
// ^^^^^^^^^^^^
continue 'inner ;
break 'inner ;
}
break 'outer ;
// ^^^^^^^^^^^^
continue 'outer ;
// ^^^^^^^^^^^^^^^
break ;
continue ;
}
break ;
// ^^^^^
continue ;
// ^^^^^^^^
}
}
" #,
) ;
}
2021-06-24 18:57:02 +00:00
#[ test ]
fn test_hl_break_while ( ) {
check (
r #"
fn foo ( ) {
' outer : while true {
// ^^^^^^^^^^^^^
break ;
// ^^^^^
' inner : while true {
break ;
' innermost : while true {
break 'outer ;
// ^^^^^^^^^^^^
break 'inner ;
}
break $ 0 ' outer ;
// ^^^^^^^^^^^^
break ;
}
break ;
// ^^^^^
}
}
" #,
) ;
}
#[ test ]
fn test_hl_break_labeled_block ( ) {
check (
r #"
fn foo ( ) {
' outer : {
// ^^^^^^^
break ;
// ^^^^^
' inner : {
break ;
' innermost : {
break 'outer ;
// ^^^^^^^^^^^^
break 'inner ;
}
break $ 0 ' outer ;
// ^^^^^^^^^^^^
break ;
}
break ;
// ^^^^^
}
}
" #,
) ;
}
#[ test ]
fn test_hl_break_unlabeled_loop ( ) {
check (
r #"
fn foo ( ) {
loop {
// ^^^^
break $ 0 ;
// ^^^^^
}
}
" #,
) ;
}
#[ test ]
fn test_hl_break_unlabeled_block_in_loop ( ) {
check (
r #"
fn foo ( ) {
loop {
// ^^^^
{
break $ 0 ;
// ^^^^^
}
}
}
2021-06-22 17:39:59 +00:00
" #,
) ;
}
2021-07-23 00:59:31 +00:00
2021-08-24 01:14:03 +00:00
#[ test ]
fn test_hl_field_shorthand ( ) {
check (
r #"
struct Struct { field : u32 }
//^^^^^
fn function ( field : u32 ) {
//^^^^^
Struct { field $ 0 }
//^^^^^ read
}
" #,
) ;
}
2021-07-23 00:59:31 +00:00
#[ test ]
fn test_hl_disabled_ref_local ( ) {
2023-05-02 06:52:08 +00:00
let config = HighlightRelatedConfig { references : false , .. ENABLED_CONFIG } ;
2021-07-23 00:59:31 +00:00
2022-03-04 18:49:08 +00:00
check_with_config (
r #"
2021-07-23 00:59:31 +00:00
fn foo ( ) {
2022-03-04 19:09:32 +00:00
let x $ 0 = 5 ;
2021-07-23 00:59:31 +00:00
let y = x * 2 ;
2022-03-04 18:49:08 +00:00
}
" #,
config ,
) ;
2021-07-23 00:59:31 +00:00
}
#[ test ]
fn test_hl_disabled_ref_local_preserved_break ( ) {
2023-05-02 06:52:08 +00:00
let config = HighlightRelatedConfig { references : false , .. ENABLED_CONFIG } ;
2021-07-23 00:59:31 +00:00
2022-03-04 18:49:08 +00:00
check_with_config (
r #"
2021-07-23 00:59:31 +00:00
fn foo ( ) {
2022-03-04 19:09:32 +00:00
let x $ 0 = 5 ;
2021-07-23 00:59:31 +00:00
let y = x * 2 ;
loop {
break ;
}
2022-03-04 18:49:08 +00:00
}
" #,
config . clone ( ) ,
) ;
2021-07-23 00:59:31 +00:00
2022-03-04 18:49:08 +00:00
check_with_config (
r #"
2021-07-23 00:59:31 +00:00
fn foo ( ) {
let x = 5 ;
let y = x * 2 ;
2022-03-04 19:09:32 +00:00
loop $ 0 {
2021-07-23 00:59:31 +00:00
// ^^^^
break ;
// ^^^^^
}
2022-03-04 18:49:08 +00:00
}
" #,
config ,
) ;
2021-07-23 00:59:31 +00:00
}
#[ test ]
fn test_hl_disabled_ref_local_preserved_yield ( ) {
2023-05-02 06:52:08 +00:00
let config = HighlightRelatedConfig { references : false , .. ENABLED_CONFIG } ;
2021-07-23 00:59:31 +00:00
2022-03-04 18:49:08 +00:00
check_with_config (
r #"
2021-07-23 00:59:31 +00:00
async fn foo ( ) {
2022-03-04 19:09:32 +00:00
let x $ 0 = 5 ;
2021-07-23 00:59:31 +00:00
let y = x * 2 ;
0. await ;
2022-03-04 18:49:08 +00:00
}
" #,
config . clone ( ) ,
) ;
2021-07-23 00:59:31 +00:00
2022-03-04 18:49:08 +00:00
check_with_config (
r #"
2021-07-23 00:59:31 +00:00
async fn foo ( ) {
// ^^^^^
let x = 5 ;
let y = x * 2 ;
2022-03-04 19:09:32 +00:00
0. await $ 0 ;
2021-07-23 00:59:31 +00:00
// ^^^^^
2022-03-04 18:49:08 +00:00
}
" #,
config ,
) ;
2021-07-23 00:59:31 +00:00
}
#[ test ]
fn test_hl_disabled_ref_local_preserved_exit ( ) {
2023-05-02 06:52:08 +00:00
let config = HighlightRelatedConfig { references : false , .. ENABLED_CONFIG } ;
2021-07-23 00:59:31 +00:00
2022-03-04 18:49:08 +00:00
check_with_config (
r #"
2021-07-23 00:59:31 +00:00
fn foo ( ) -> i32 {
2022-03-04 19:09:32 +00:00
let x $ 0 = 5 ;
2021-07-23 00:59:31 +00:00
let y = x * 2 ;
if true {
return y ;
}
0 ?
2022-03-04 18:49:08 +00:00
}
" #,
config . clone ( ) ,
) ;
2021-07-23 00:59:31 +00:00
2022-03-04 18:49:08 +00:00
check_with_config (
r #"
2023-05-02 06:37:40 +00:00
fn foo ( ) ->$ 0 i32 {
//^^
2021-07-23 00:59:31 +00:00
let x = 5 ;
let y = x * 2 ;
if true {
return y ;
// ^^^^^^
}
0 ?
// ^
2022-03-04 18:49:08 +00:00
" #,
config ,
) ;
2021-07-23 00:59:31 +00:00
}
#[ test ]
fn test_hl_disabled_break ( ) {
2023-05-02 06:52:08 +00:00
let config = HighlightRelatedConfig { break_points : false , .. ENABLED_CONFIG } ;
2021-07-23 00:59:31 +00:00
2022-03-04 18:49:08 +00:00
check_with_config (
r #"
2021-07-23 00:59:31 +00:00
fn foo ( ) {
loop {
2022-03-04 19:09:32 +00:00
break $ 0 ;
2021-07-23 00:59:31 +00:00
}
2022-03-04 18:49:08 +00:00
}
" #,
config ,
) ;
2021-07-23 00:59:31 +00:00
}
#[ test ]
fn test_hl_disabled_yield ( ) {
2023-05-02 06:52:08 +00:00
let config = HighlightRelatedConfig { yield_points : false , .. ENABLED_CONFIG } ;
2021-07-23 00:59:31 +00:00
2022-03-04 18:49:08 +00:00
check_with_config (
r #"
2022-03-04 19:09:32 +00:00
async $ 0 fn foo ( ) {
2021-07-23 00:59:31 +00:00
0. await ;
2022-03-04 18:49:08 +00:00
}
" #,
config ,
) ;
2021-07-23 00:59:31 +00:00
}
#[ test ]
fn test_hl_disabled_exit ( ) {
2023-05-02 06:52:08 +00:00
let config = HighlightRelatedConfig { exit_points : false , .. ENABLED_CONFIG } ;
2021-07-23 00:59:31 +00:00
2022-03-04 18:49:08 +00:00
check_with_config (
r #"
2022-03-04 19:09:32 +00:00
fn foo ( ) ->$ 0 i32 {
2021-07-23 00:59:31 +00:00
if true {
return - 1 ;
}
42
2022-03-04 18:49:08 +00:00
} " #,
config ,
) ;
}
2021-07-23 00:59:31 +00:00
2022-03-04 18:49:08 +00:00
#[ test ]
fn test_hl_multi_local ( ) {
check (
r #"
fn foo ( (
foo $ 0
//^^^
| foo
//^^^
| foo
//^^^
) : ( ) ) {
foo ;
//^^^read
let foo ;
}
" #,
) ;
check (
r #"
fn foo ( (
foo
//^^^
| foo $ 0
//^^^
| foo
//^^^
) : ( ) ) {
foo ;
//^^^read
let foo ;
}
" #,
) ;
check (
r #"
fn foo ( (
foo
//^^^
| foo
//^^^
| foo
//^^^
) : ( ) ) {
foo $ 0 ;
//^^^read
let foo ;
}
2022-07-20 11:59:31 +00:00
" #,
) ;
}
#[ test ]
fn test_hl_trait_impl_methods ( ) {
check (
r #"
trait Trait {
fn func $ 0 ( self ) { }
//^^^^
}
impl Trait for ( ) {
fn func ( self ) { }
//^^^^
}
fn main ( ) {
< ( ) > ::func ( ( ) ) ;
//^^^^
( ) . func ( ) ;
//^^^^
}
" #,
) ;
check (
r #"
trait Trait {
fn func ( self ) { }
}
impl Trait for ( ) {
fn func $ 0 ( self ) { }
//^^^^
}
fn main ( ) {
< ( ) > ::func ( ( ) ) ;
//^^^^
( ) . func ( ) ;
//^^^^
}
" #,
) ;
check (
r #"
trait Trait {
fn func ( self ) { }
}
impl Trait for ( ) {
fn func ( self ) { }
//^^^^
}
fn main ( ) {
< ( ) > ::func ( ( ) ) ;
//^^^^
( ) . func $ 0 ( ) ;
//^^^^
}
2022-10-05 15:45:32 +00:00
" #,
) ;
}
#[ test ]
fn test_assoc_type_highlighting ( ) {
check (
r #"
trait Trait {
type Output ;
// ^^^^^^
}
impl Trait for ( ) {
type Output $ 0 = ( ) ;
// ^^^^^^
}
2023-05-02 06:52:08 +00:00
" #,
) ;
}
#[ test ]
fn test_closure_capture_pipe ( ) {
check (
r #"
fn f ( ) {
let x = 1 ;
// ^
let c = $ 0 | y | x + y ;
// ^ read
}
" #,
) ;
}
#[ test ]
fn test_closure_capture_move ( ) {
check (
r #"
fn f ( ) {
let x = 1 ;
// ^
let c = move $ 0 | y | x + y ;
// ^ read
}
2023-05-15 18:13:05 +00:00
" #,
) ;
}
#[ test ]
fn test_trait_highlights_assoc_item_uses ( ) {
check (
r #"
trait Foo {
//^^^
type T ;
const C : usize ;
fn f ( ) { }
fn m ( & self ) { }
}
impl Foo for i32 {
//^^^
type T = i32 ;
const C : usize = 0 ;
fn f ( ) { }
fn m ( & self ) { }
}
fn f < T : Foo $ 0 > ( t : T ) {
//^^^
let _ : T ::T ;
//^
t . m ( ) ;
//^
T ::C ;
//^
T ::f ( ) ;
//^
}
fn f2 < T : Foo > ( t : T ) {
//^^^
let _ : T ::T ;
t . m ( ) ;
T ::C ;
T ::f ( ) ;
}
2023-12-05 14:42:39 +00:00
" #,
) ;
}
#[ test ]
fn implicit_format_args ( ) {
check (
r #"
//- minicore: fmt
fn test ( ) {
let a = " foo " ;
// ^
format_args! ( " hello {a} {a$0} {} " , a ) ;
// ^read
// ^read
// ^read
}
2022-03-04 18:49:08 +00:00
" #,
) ;
2021-07-23 00:59:31 +00:00
}
2021-06-22 17:39:59 +00:00
}