@@ -19,8 +19,8 @@ use once_cell::unsync::Lazy;
1919use ra_db:: { SourceDatabase , SourceDatabaseExt } ;
2020use ra_prof:: profile;
2121use ra_syntax:: {
22- algo:: find_node_at_offset, ast, AstNode , SourceFile , SyntaxKind , SyntaxNode , TextUnit ,
23- TokenAtOffset ,
22+ algo:: find_node_at_offset, ast, match_ast , AstNode , SourceFile , SyntaxKind , SyntaxNode ,
23+ TextUnit , TokenAtOffset ,
2424} ;
2525
2626use crate :: {
@@ -46,6 +46,7 @@ pub struct ReferenceSearchResult {
4646pub struct Reference {
4747 pub file_range : FileRange ,
4848 pub kind : ReferenceKind ,
49+ pub access : Option < ReferenceAccess > ,
4950}
5051
5152#[ derive( Debug , Clone , PartialEq ) ]
@@ -54,6 +55,12 @@ pub enum ReferenceKind {
5455 Other ,
5556}
5657
58+ #[ derive( Debug , Clone , PartialEq ) ]
59+ pub enum ReferenceAccess {
60+ Read ,
61+ Write ,
62+ }
63+
5764impl ReferenceSearchResult {
5865 pub fn declaration ( & self ) -> & NavigationTarget {
5966 & self . declaration
@@ -72,7 +79,7 @@ impl ReferenceSearchResult {
7279}
7380
7481// allow turning ReferenceSearchResult into an iterator
75- // over FileRanges
82+ // over References
7683impl IntoIterator for ReferenceSearchResult {
7784 type Item = Reference ;
7885 type IntoIter = std:: vec:: IntoIter < Reference > ;
@@ -85,6 +92,7 @@ impl IntoIterator for ReferenceSearchResult {
8592 range : self . declaration . range ( ) ,
8693 } ,
8794 kind : self . declaration_kind ,
95+ access : None ,
8896 } ) ;
8997 v. append ( & mut self . references ) ;
9098 v. into_iter ( )
@@ -201,7 +209,13 @@ fn process_definition(
201209 } else {
202210 ReferenceKind :: Other
203211 } ;
204- refs. push ( Reference { file_range : FileRange { file_id, range } , kind } ) ;
212+ let access = access_mode ( d. kind , & name_ref) ;
213+
214+ refs. push ( Reference {
215+ file_range : FileRange { file_id, range } ,
216+ kind,
217+ access,
218+ } ) ;
205219 }
206220 }
207221 }
@@ -210,11 +224,46 @@ fn process_definition(
210224 refs
211225}
212226
227+ fn access_mode ( kind : NameKind , name_ref : & ast:: NameRef ) -> Option < ReferenceAccess > {
228+ match kind {
229+ NameKind :: Local ( _) | NameKind :: Field ( _) => {
230+ //LetExpr or BinExpr
231+ name_ref. syntax ( ) . ancestors ( ) . find_map ( |node| {
232+ match_ast ! {
233+ match ( node) {
234+ ast:: BinExpr ( expr) => {
235+ match expr. op_kind( ) {
236+ Some ( kind) if kind. is_assignment( ) => {
237+ if let Some ( lhs) = expr. lhs( ) {
238+ if lhs. syntax( ) . text_range( ) == name_ref. syntax( ) . text_range( ) {
239+ return Some ( ReferenceAccess :: Write ) ;
240+ }
241+ }
242+
243+ if let Some ( rhs) = expr. rhs( ) {
244+ if rhs. syntax( ) . text_range( ) . is_subrange( & name_ref. syntax( ) . text_range( ) ) {
245+ return Some ( ReferenceAccess :: Read ) ;
246+ }
247+ }
248+ } ,
249+ _ => { return Some ( ReferenceAccess :: Read ) } ,
250+ }
251+ None
252+ } ,
253+ _ => { None }
254+ }
255+ }
256+ } )
257+ }
258+ _ => None ,
259+ }
260+ }
261+
213262#[ cfg( test) ]
214263mod tests {
215264 use crate :: {
216265 mock_analysis:: { analysis_and_position, single_file_with_position, MockAnalysis } ,
217- Reference , ReferenceKind , ReferenceSearchResult , SearchScope ,
266+ Reference , ReferenceAccess , ReferenceKind , ReferenceSearchResult , SearchScope ,
218267 } ;
219268
220269 #[ test]
@@ -515,6 +564,20 @@ mod tests {
515564 ) ;
516565 }
517566
567+ #[ test]
568+ fn test_basic_highlight_read ( ) {
569+ let code = r#"
570+ fn foo() {
571+ let i<|> = 0;
572+ i = i + 1;
573+ }"# ;
574+
575+ let refs = get_all_refs ( code) ;
576+ assert_eq ! ( refs. len( ) , 3 ) ;
577+ assert_eq ! ( refs. references[ 0 ] . access, Some ( ReferenceAccess :: Write ) ) ;
578+ assert_eq ! ( refs. references[ 1 ] . access, Some ( ReferenceAccess :: Read ) ) ;
579+ }
580+
518581 fn get_all_refs ( text : & str ) -> ReferenceSearchResult {
519582 let ( analysis, position) = single_file_with_position ( text) ;
520583 analysis. find_all_refs ( position, None ) . unwrap ( ) . unwrap ( )
0 commit comments