From d993f329a01deb3cdc011c3eb1dfd859302fec04 Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Sat, 4 Jan 2020 17:46:01 -0500 Subject: [PATCH 1/6] Basic DocumentHighlightKind support for assignments --- crates/ra_ide/src/lib.rs | 2 +- crates/ra_ide/src/references.rs | 73 +++++++++++++++++-- crates/ra_lsp_server/src/conv.rs | 14 +++- .../ra_lsp_server/src/main_loop/handlers.rs | 34 ++++++--- crates/ra_syntax/src/ast/expr_extensions.rs | 1 + 5 files changed, 107 insertions(+), 17 deletions(-) diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index 7b187eba354..837315ca702 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs @@ -75,7 +75,7 @@ inlay_hints::{InlayHint, InlayKind}, line_index::{LineCol, LineIndex}, line_index_utils::translate_offset_with_edit, - references::{Reference, ReferenceKind, ReferenceSearchResult, SearchScope}, + references::{Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, SearchScope}, runnables::{Runnable, RunnableKind}, source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, syntax_highlighting::HighlightedRange, diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs index 5a3ec4eb91e..b9d8a6b1eea 100644 --- a/crates/ra_ide/src/references.rs +++ b/crates/ra_ide/src/references.rs @@ -19,8 +19,8 @@ use ra_db::{SourceDatabase, SourceDatabaseExt}; use ra_prof::profile; use ra_syntax::{ - algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, TextUnit, - TokenAtOffset, + algo::find_node_at_offset, ast, match_ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, + TextUnit, TokenAtOffset, }; use crate::{ @@ -46,6 +46,7 @@ pub struct ReferenceSearchResult { pub struct Reference { pub file_range: FileRange, pub kind: ReferenceKind, + pub access: Option, } #[derive(Debug, Clone, PartialEq)] @@ -54,6 +55,12 @@ pub enum ReferenceKind { Other, } +#[derive(Debug, Clone, PartialEq)] +pub enum ReferenceAccess { + Read, + Write, +} + impl ReferenceSearchResult { pub fn declaration(&self) -> &NavigationTarget { &self.declaration @@ -72,7 +79,7 @@ pub fn len(&self) -> usize { } // allow turning ReferenceSearchResult into an iterator -// over FileRanges +// over References impl IntoIterator for ReferenceSearchResult { type Item = Reference; type IntoIter = std::vec::IntoIter; @@ -85,6 +92,7 @@ fn into_iter(mut self) -> Self::IntoIter { range: self.declaration.range(), }, kind: self.declaration_kind, + access: None, }); v.append(&mut self.references); v.into_iter() @@ -201,7 +209,13 @@ fn process_definition( } else { ReferenceKind::Other }; - refs.push(Reference { file_range: FileRange { file_id, range }, kind }); + let access = access_mode(d.kind, &name_ref); + + refs.push(Reference { + file_range: FileRange { file_id, range }, + kind, + access, + }); } } } @@ -210,11 +224,46 @@ fn process_definition( refs } +fn access_mode(kind: NameKind, name_ref: &ast::NameRef) -> Option { + match kind { + NameKind::Local(_) | NameKind::Field(_) => { + //LetExpr or BinExpr + name_ref.syntax().ancestors().find_map(|node| { + match_ast! { + match (node) { + ast::BinExpr(expr) => { + match expr.op_kind() { + Some(kind) if kind.is_assignment() => { + if let Some(lhs) = expr.lhs() { + if lhs.syntax().text_range() == name_ref.syntax().text_range() { + return Some(ReferenceAccess::Write); + } + } + + if let Some(rhs) = expr.rhs() { + if rhs.syntax().text_range().is_subrange(&name_ref.syntax().text_range()) { + return Some(ReferenceAccess::Read); + } + } + }, + _ => { return Some(ReferenceAccess::Read) }, + } + None + }, + _ => {None} + } + } + }) + } + _ => None, + } +} + #[cfg(test)] mod tests { use crate::{ mock_analysis::{analysis_and_position, single_file_with_position, MockAnalysis}, - Reference, ReferenceKind, ReferenceSearchResult, SearchScope, + Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, SearchScope, }; #[test] @@ -515,6 +564,20 @@ fn foo() { ); } + #[test] + fn test_basic_highlight_read() { + let code = r#" + fn foo() { + let i<|> = 0; + i = i + 1; + }"#; + + let refs = get_all_refs(code); + assert_eq!(refs.len(), 3); + assert_eq!(refs.references[0].access, Some(ReferenceAccess::Write)); + assert_eq!(refs.references[1].access, Some(ReferenceAccess::Read)); + } + fn get_all_refs(text: &str) -> ReferenceSearchResult { let (analysis, position) = single_file_with_position(text); analysis.find_all_refs(position, None).unwrap().unwrap() diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index c260b51c47d..1b93195d7c6 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs @@ -9,7 +9,7 @@ use ra_ide::{ translate_offset_with_edit, CompletionItem, CompletionItemKind, FileId, FilePosition, FileRange, FileSystemEdit, Fold, FoldKind, InsertTextFormat, LineCol, LineIndex, - NavigationTarget, RangeInfo, Severity, SourceChange, SourceFileEdit, + NavigationTarget, RangeInfo, ReferenceAccess, Severity, SourceChange, SourceFileEdit, }; use ra_syntax::{SyntaxKind, TextRange, TextUnit}; use ra_text_edit::{AtomTextEdit, TextEdit}; @@ -53,6 +53,18 @@ fn conv(self) -> ::Output { } } +impl Conv for ReferenceAccess { + type Output = ::lsp_types::DocumentHighlightKind; + + fn conv(self) -> Self::Output { + use lsp_types::DocumentHighlightKind::*; + match self { + ReferenceAccess::Read => Read, + ReferenceAccess::Write => Write, + } + } +} + impl Conv for CompletionItemKind { type Output = ::lsp_types::CompletionItemKind; diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index a5b6f48af32..a592f0a1266 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -536,18 +536,32 @@ pub fn handle_references( let locations = if params.context.include_declaration { refs.into_iter() - .filter_map(|r| { - let line_index = world.analysis().file_line_index(r.file_range.file_id).ok()?; - to_location(r.file_range.file_id, r.file_range.range, &world, &line_index).ok() + .filter_map(|reference| { + let line_index = + world.analysis().file_line_index(reference.file_range.file_id).ok()?; + to_location( + reference.file_range.file_id, + reference.file_range.range, + &world, + &line_index, + ) + .ok() }) .collect() } else { // Only iterate over the references if include_declaration was false refs.references() .iter() - .filter_map(|r| { - let line_index = world.analysis().file_line_index(r.file_range.file_id).ok()?; - to_location(r.file_range.file_id, r.file_range.range, &world, &line_index).ok() + .filter_map(|reference| { + let line_index = + world.analysis().file_line_index(reference.file_range.file_id).ok()?; + to_location( + reference.file_range.file_id, + reference.file_range.range, + &world, + &line_index, + ) + .ok() }) .collect() }; @@ -836,10 +850,10 @@ pub fn handle_document_highlight( Ok(Some( refs.into_iter() - .filter(|r| r.file_range.file_id == file_id) - .map(|r| DocumentHighlight { - range: r.file_range.range.conv_with(&line_index), - kind: None, + .filter(|reference| reference.file_range.file_id == file_id) + .map(|reference| DocumentHighlight { + range: reference.file_range.range.conv_with(&line_index), + kind: reference.access.map(|it| it.conv()), }) .collect(), )) diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs index 23b6aa90147..3dfecfe7625 100644 --- a/crates/ra_syntax/src/ast/expr_extensions.rs +++ b/crates/ra_syntax/src/ast/expr_extensions.rs @@ -144,6 +144,7 @@ pub fn is_assignment(&self) -> bool { } } } + impl ast::BinExpr { pub fn op_details(&self) -> Option<(SyntaxToken, BinOp)> { self.syntax().children_with_tokens().filter_map(|it| it.into_token()).find_map(|c| { From 6c89d86ade392ddd4088ecdb444ea7bd002a3cff Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Sat, 4 Jan 2020 19:25:29 -0500 Subject: [PATCH 2/6] Tweaks --- crates/ra_ide/src/references.rs | 48 ++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs index b9d8a6b1eea..7d31ef6bddc 100644 --- a/crates/ra_ide/src/references.rs +++ b/crates/ra_ide/src/references.rs @@ -232,22 +232,26 @@ fn access_mode(kind: NameKind, name_ref: &ast::NameRef) -> Option { - match expr.op_kind() { - Some(kind) if kind.is_assignment() => { - if let Some(lhs) = expr.lhs() { - if lhs.syntax().text_range() == name_ref.syntax().text_range() { - return Some(ReferenceAccess::Write); - } + if expr.op_kind()?.is_assignment() { + // If the variable or field ends on the LHS's end then it's a Write (covers fields and locals). + // FIXME: This is not terribly accurate. + if let Some(lhs) = expr.lhs() { + if lhs.syntax().text_range().end() == name_ref.syntax().text_range().end() { + return Some(ReferenceAccess::Write); + } else if name_ref.syntax().text_range().is_subrange(&lhs.syntax().text_range()) { + return Some(ReferenceAccess::Read); } + } - if let Some(rhs) = expr.rhs() { - if rhs.syntax().text_range().is_subrange(&name_ref.syntax().text_range()) { - return Some(ReferenceAccess::Read); - } + // If the variable is on the RHS then it's a Read. + if let Some(rhs) = expr.rhs() { + if name_ref.syntax().text_range().is_subrange(&rhs.syntax().text_range()) { + return Some(ReferenceAccess::Read); } - }, - _ => { return Some(ReferenceAccess::Read) }, + } } + + // Cannot determine access None }, _ => {None} @@ -565,7 +569,7 @@ fn foo() { } #[test] - fn test_basic_highlight_read() { + fn test_basic_highlight_read_write() { let code = r#" fn foo() { let i<|> = 0; @@ -578,6 +582,24 @@ fn foo() { assert_eq!(refs.references[1].access, Some(ReferenceAccess::Read)); } + #[test] + fn test_basic_highlight_field_read_write() { + let code = r#" + struct S { + f: u32, + } + + fn foo() { + let mut s = S{f: 0}; + s.f<|> = 0; + }"#; + + let refs = get_all_refs(code); + assert_eq!(refs.len(), 3); + //assert_eq!(refs.references[0].access, Some(ReferenceAccess::Write)); + assert_eq!(refs.references[1].access, Some(ReferenceAccess::Write)); + } + fn get_all_refs(text: &str) -> ReferenceSearchResult { let (analysis, position) = single_file_with_position(text); analysis.find_all_refs(position, None).unwrap().unwrap() From cc96ddfe695c2b3d2e9f28c3c5205a83a99a8ac3 Mon Sep 17 00:00:00 2001 From: kjeremy Date: Thu, 9 Jan 2020 16:01:43 -0500 Subject: [PATCH 3/6] Simplify and update tests to account for access --- crates/ra_ide/src/references.rs | 99 +++++++++++++++++---------------- 1 file changed, 52 insertions(+), 47 deletions(-) diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs index 7d31ef6bddc..5b8ed370c5c 100644 --- a/crates/ra_ide/src/references.rs +++ b/crates/ra_ide/src/references.rs @@ -55,7 +55,7 @@ pub enum ReferenceKind { Other, } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq)] pub enum ReferenceAccess { Read, Write, @@ -225,49 +225,41 @@ fn process_definition( } fn access_mode(kind: NameKind, name_ref: &ast::NameRef) -> Option { + // Only Locals and Fields have accesses for now. match kind { - NameKind::Local(_) | NameKind::Field(_) => { - //LetExpr or BinExpr - name_ref.syntax().ancestors().find_map(|node| { - match_ast! { - match (node) { - ast::BinExpr(expr) => { - if expr.op_kind()?.is_assignment() { - // If the variable or field ends on the LHS's end then it's a Write (covers fields and locals). - // FIXME: This is not terribly accurate. - if let Some(lhs) = expr.lhs() { - if lhs.syntax().text_range().end() == name_ref.syntax().text_range().end() { - return Some(ReferenceAccess::Write); - } else if name_ref.syntax().text_range().is_subrange(&lhs.syntax().text_range()) { - return Some(ReferenceAccess::Read); - } - } + NameKind::Local(_) | NameKind::Field(_) => {} + _ => return None, + }; - // If the variable is on the RHS then it's a Read. - if let Some(rhs) = expr.rhs() { - if name_ref.syntax().text_range().is_subrange(&rhs.syntax().text_range()) { - return Some(ReferenceAccess::Read); - } - } + let mode = name_ref.syntax().ancestors().find_map(|node| { + match_ast! { + match (node) { + ast::BinExpr(expr) => { + if expr.op_kind()?.is_assignment() { + // If the variable or field ends on the LHS's end then it's a Write (covers fields and locals). + // FIXME: This is not terribly accurate. + if let Some(lhs) = expr.lhs() { + if lhs.syntax().text_range().end() == name_ref.syntax().text_range().end() { + return Some(ReferenceAccess::Write); } - - // Cannot determine access - None - }, - _ => {None} + } } - } - }) + return Some(ReferenceAccess::Read); + }, + _ => {None} + } } - _ => None, - } + }); + + // Default Locals and Fields to read + mode.or(Some(ReferenceAccess::Read)) } #[cfg(test)] mod tests { use crate::{ mock_analysis::{analysis_and_position, single_file_with_position, MockAnalysis}, - Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, SearchScope, + Reference, ReferenceKind, ReferenceSearchResult, SearchScope, }; #[test] @@ -314,10 +306,10 @@ fn main() { "i BIND_PAT FileId(1) [33; 34)", ReferenceKind::Other, &[ - "FileId(1) [67; 68) Other", - "FileId(1) [71; 72) Other", - "FileId(1) [101; 102) Other", - "FileId(1) [127; 128) Other", + "FileId(1) [67; 68) Other Write", + "FileId(1) [71; 72) Other Read", + "FileId(1) [101; 102) Other Write", + "FileId(1) [127; 128) Other Write", ], ); } @@ -334,7 +326,7 @@ fn foo(i : u32) -> u32 { refs, "i BIND_PAT FileId(1) [12; 13)", ReferenceKind::Other, - &["FileId(1) [38; 39) Other"], + &["FileId(1) [38; 39) Other Read"], ); } @@ -350,7 +342,7 @@ fn foo(i<|> : u32) -> u32 { refs, "i BIND_PAT FileId(1) [12; 13)", ReferenceKind::Other, - &["FileId(1) [38; 39) Other"], + &["FileId(1) [38; 39) Other Read"], ); } @@ -372,7 +364,7 @@ fn main(s: Foo) { refs, "spam RECORD_FIELD_DEF FileId(1) [66; 79) [70; 74)", ReferenceKind::Other, - &["FileId(1) [152; 156) Other"], + &["FileId(1) [152; 156) Other Read"], ); } @@ -577,9 +569,12 @@ fn foo() { }"#; let refs = get_all_refs(code); - assert_eq!(refs.len(), 3); - assert_eq!(refs.references[0].access, Some(ReferenceAccess::Write)); - assert_eq!(refs.references[1].access, Some(ReferenceAccess::Read)); + check_result( + refs, + "i BIND_PAT FileId(1) [36; 37)", + ReferenceKind::Other, + &["FileId(1) [55; 56) Other Write", "FileId(1) [59; 60) Other Read"], + ); } #[test] @@ -595,9 +590,12 @@ fn foo() { }"#; let refs = get_all_refs(code); - assert_eq!(refs.len(), 3); - //assert_eq!(refs.references[0].access, Some(ReferenceAccess::Write)); - assert_eq!(refs.references[1].access, Some(ReferenceAccess::Write)); + check_result( + refs, + "f RECORD_FIELD_DEF FileId(1) [32; 38) [32; 33)", + ReferenceKind::Other, + &["FileId(1) [96; 97) Other Read", "FileId(1) [117; 118) Other Write"], + ); } fn get_all_refs(text: &str) -> ReferenceSearchResult { @@ -620,7 +618,14 @@ fn check_result( impl Reference { fn debug_render(&self) -> String { - format!("{:?} {:?} {:?}", self.file_range.file_id, self.file_range.range, self.kind) + let mut s = format!( + "{:?} {:?} {:?}", + self.file_range.file_id, self.file_range.range, self.kind + ); + if let Some(access) = self.access { + s.push_str(&format!(" {:?}", access)); + } + s } fn assert_match(&self, expected: &str) { From 49fd6a5228bfb2200611e6a9a9b24d01368bb279 Mon Sep 17 00:00:00 2001 From: kjeremy Date: Thu, 9 Jan 2020 16:27:10 -0500 Subject: [PATCH 4/6] Split Declaration out into it's own type --- crates/ra_ide/src/lib.rs | 4 +- crates/ra_ide/src/references.rs | 100 +++++++++++++++++--------------- 2 files changed, 55 insertions(+), 49 deletions(-) diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index 837315ca702..4d8deb21c8b 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs @@ -75,7 +75,9 @@ inlay_hints::{InlayHint, InlayKind}, line_index::{LineCol, LineIndex}, line_index_utils::translate_offset_with_edit, - references::{Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, SearchScope}, + references::{ + Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, SearchScope, + }, runnables::{Runnable, RunnableKind}, source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, syntax_highlighting::HighlightedRange, diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs index 5b8ed370c5c..2d20de1d047 100644 --- a/crates/ra_ide/src/references.rs +++ b/crates/ra_ide/src/references.rs @@ -37,11 +37,17 @@ #[derive(Debug, Clone)] pub struct ReferenceSearchResult { - declaration: NavigationTarget, - declaration_kind: ReferenceKind, + declaration: Declaration, references: Vec, } +#[derive(Debug, Clone)] +pub struct Declaration { + pub nav: NavigationTarget, + pub kind: ReferenceKind, + pub access: Option, +} + #[derive(Debug, Clone)] pub struct Reference { pub file_range: FileRange, @@ -62,10 +68,14 @@ pub enum ReferenceAccess { } impl ReferenceSearchResult { - pub fn declaration(&self) -> &NavigationTarget { + pub fn declaration(&self) -> &Declaration { &self.declaration } + pub fn decl_target(&self) -> &NavigationTarget { + &self.declaration.nav + } + pub fn references(&self) -> &[Reference] { &self.references } @@ -88,11 +98,11 @@ fn into_iter(mut self) -> Self::IntoIter { let mut v = Vec::with_capacity(self.len()); v.push(Reference { file_range: FileRange { - file_id: self.declaration.file_id(), - range: self.declaration.range(), + file_id: self.declaration.nav.file_id(), + range: self.declaration.nav.range(), }, - kind: self.declaration_kind, - access: None, + kind: self.declaration.kind, + access: self.declaration.access, }); v.append(&mut self.references); v.into_iter() @@ -139,15 +149,14 @@ pub(crate) fn find_all_refs( } }; + let declaration = Declaration { nav: declaration, kind: ReferenceKind::Other, access: None }; + let references = process_definition(db, def, name, search_scope) .into_iter() .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind) .collect(); - Some(RangeInfo::new( - range, - ReferenceSearchResult { declaration, references, declaration_kind: ReferenceKind::Other }, - )) + Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })) } fn find_name<'a>( @@ -259,7 +268,7 @@ fn access_mode(kind: NameKind, name_ref: &ast::NameRef) -> Option u32 { let refs = get_all_refs(code); check_result( refs, - "i BIND_PAT FileId(1) [12; 13)", - ReferenceKind::Other, + "i BIND_PAT FileId(1) [12; 13) Other", &["FileId(1) [38; 39) Other Read"], ); } @@ -340,8 +346,7 @@ fn foo(i<|> : u32) -> u32 { let refs = get_all_refs(code); check_result( refs, - "i BIND_PAT FileId(1) [12; 13)", - ReferenceKind::Other, + "i BIND_PAT FileId(1) [12; 13) Other", &["FileId(1) [38; 39) Other Read"], ); } @@ -362,8 +367,7 @@ fn main(s: Foo) { let refs = get_all_refs(code); check_result( refs, - "spam RECORD_FIELD_DEF FileId(1) [66; 79) [70; 74)", - ReferenceKind::Other, + "spam RECORD_FIELD_DEF FileId(1) [66; 79) [70; 74) Other", &["FileId(1) [152; 156) Other Read"], ); } @@ -379,7 +383,7 @@ fn f<|>(&self) { } "#; let refs = get_all_refs(code); - check_result(refs, "f FN_DEF FileId(1) [88; 104) [91; 92)", ReferenceKind::Other, &[]); + check_result(refs, "f FN_DEF FileId(1) [88; 104) [91; 92) Other", &[]); } #[test] @@ -394,7 +398,7 @@ enum Foo { "#; let refs = get_all_refs(code); - check_result(refs, "B ENUM_VARIANT FileId(1) [83; 84) [83; 84)", ReferenceKind::Other, &[]); + check_result(refs, "B ENUM_VARIANT FileId(1) [83; 84) [83; 84) Other", &[]); } #[test] @@ -435,8 +439,7 @@ fn f() { let refs = analysis.find_all_refs(pos, None).unwrap().unwrap(); check_result( refs, - "Foo STRUCT_DEF FileId(2) [16; 50) [27; 30)", - ReferenceKind::Other, + "Foo STRUCT_DEF FileId(2) [16; 50) [27; 30) Other", &["FileId(1) [52; 55) StructLiteral", "FileId(3) [77; 80) StructLiteral"], ); } @@ -466,8 +469,7 @@ pub struct Foo { let refs = analysis.find_all_refs(pos, None).unwrap().unwrap(); check_result( refs, - "foo SOURCE_FILE FileId(2) [0; 35)", - ReferenceKind::Other, + "foo SOURCE_FILE FileId(2) [0; 35) Other", &["FileId(1) [13; 16) Other"], ); } @@ -496,8 +498,7 @@ pub(super) struct Foo<|> { let refs = analysis.find_all_refs(pos, None).unwrap().unwrap(); check_result( refs, - "Foo STRUCT_DEF FileId(3) [0; 41) [18; 21)", - ReferenceKind::Other, + "Foo STRUCT_DEF FileId(3) [0; 41) [18; 21) Other", &["FileId(2) [20; 23) Other", "FileId(2) [46; 49) StructLiteral"], ); } @@ -525,8 +526,7 @@ pub fn quux<|>() {} let refs = analysis.find_all_refs(pos, None).unwrap().unwrap(); check_result( refs, - "quux FN_DEF FileId(1) [18; 34) [25; 29)", - ReferenceKind::Other, + "quux FN_DEF FileId(1) [18; 34) [25; 29) Other", &["FileId(2) [16; 20) Other", "FileId(3) [16; 20) Other"], ); @@ -534,8 +534,7 @@ pub fn quux<|>() {} analysis.find_all_refs(pos, Some(SearchScope::single_file(bar))).unwrap().unwrap(); check_result( refs, - "quux FN_DEF FileId(1) [18; 34) [25; 29)", - ReferenceKind::Other, + "quux FN_DEF FileId(1) [18; 34) [25; 29) Other", &["FileId(3) [16; 20) Other"], ); } @@ -554,8 +553,7 @@ fn foo() { let refs = get_all_refs(code); check_result( refs, - "m1 MACRO_CALL FileId(1) [9; 63) [46; 48)", - ReferenceKind::Other, + "m1 MACRO_CALL FileId(1) [9; 63) [46; 48) Other", &["FileId(1) [96; 98) Other", "FileId(1) [114; 116) Other"], ); } @@ -571,8 +569,7 @@ fn foo() { let refs = get_all_refs(code); check_result( refs, - "i BIND_PAT FileId(1) [36; 37)", - ReferenceKind::Other, + "i BIND_PAT FileId(1) [36; 37) Other", &["FileId(1) [55; 56) Other Write", "FileId(1) [59; 60) Other Read"], ); } @@ -592,8 +589,7 @@ fn foo() { let refs = get_all_refs(code); check_result( refs, - "f RECORD_FIELD_DEF FileId(1) [32; 38) [32; 33)", - ReferenceKind::Other, + "f RECORD_FIELD_DEF FileId(1) [32; 38) [32; 33) Other", &["FileId(1) [96; 97) Other Read", "FileId(1) [117; 118) Other Write"], ); } @@ -603,19 +599,27 @@ fn get_all_refs(text: &str) -> ReferenceSearchResult { analysis.find_all_refs(position, None).unwrap().unwrap() } - fn check_result( - res: ReferenceSearchResult, - expected_decl: &str, - decl_kind: ReferenceKind, - expected_refs: &[&str], - ) { + fn check_result(res: ReferenceSearchResult, expected_decl: &str, expected_refs: &[&str]) { res.declaration().assert_match(expected_decl); - assert_eq!(res.declaration_kind, decl_kind); - assert_eq!(res.references.len(), expected_refs.len()); res.references().iter().enumerate().for_each(|(i, r)| r.assert_match(expected_refs[i])); } + impl Declaration { + fn debug_render(&self) -> String { + let mut s = format!("{} {:?}", self.nav.debug_render(), self.kind); + if let Some(access) = self.access { + s.push_str(&format!(" {:?}", access)); + } + s + } + + fn assert_match(&self, expected: &str) { + let actual = self.debug_render(); + test_utils::assert_eq_text!(expected.trim(), actual.trim(),); + } + } + impl Reference { fn debug_render(&self) -> String { let mut s = format!( From 32540abcb3c22cbd62662a255fc59972e0c5a06b Mon Sep 17 00:00:00 2001 From: kjeremy Date: Fri, 10 Jan 2020 14:56:58 -0500 Subject: [PATCH 5/6] Add AccessMode to decls --- crates/ra_ide/src/references.rs | 65 +++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 8 deletions(-) diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs index 2d20de1d047..4e52e0e7bfb 100644 --- a/crates/ra_ide/src/references.rs +++ b/crates/ra_ide/src/references.rs @@ -19,8 +19,9 @@ use ra_db::{SourceDatabase, SourceDatabaseExt}; use ra_prof::profile; use ra_syntax::{ - algo::find_node_at_offset, ast, match_ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, - TextUnit, TokenAtOffset, + algo::find_node_at_offset, + ast::{self, NameOwner}, + match_ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, TextRange, TextUnit, TokenAtOffset, }; use crate::{ @@ -149,7 +150,13 @@ pub(crate) fn find_all_refs( } }; - let declaration = Declaration { nav: declaration, kind: ReferenceKind::Other, access: None }; + let decl_range = declaration.range(); + + let declaration = Declaration { + nav: declaration, + kind: ReferenceKind::Other, + access: decl_access(&def.kind, &name, &syntax, decl_range), + }; let references = process_definition(db, def, name, search_scope) .into_iter() @@ -218,12 +225,11 @@ fn process_definition( } else { ReferenceKind::Other }; - let access = access_mode(d.kind, &name_ref); refs.push(Reference { file_range: FileRange { file_id, range }, kind, - access, + access: reference_access(&d.kind, &name_ref), }); } } @@ -233,7 +239,34 @@ fn process_definition( refs } -fn access_mode(kind: NameKind, name_ref: &ast::NameRef) -> Option { +fn decl_access( + kind: &NameKind, + name: &str, + syntax: &SyntaxNode, + range: TextRange, +) -> Option { + match kind { + NameKind::Local(_) | NameKind::Field(_) => {} + _ => return None, + }; + + let stmt = find_node_at_offset::(syntax, range.start())?; + if let Some(_) = stmt.initializer() { + let pat = stmt.pat()?; + match pat { + ast::Pat::BindPat(it) => { + if it.name()?.text().as_str() == name { + return Some(ReferenceAccess::Write); + } + } + _ => {} + } + } + + None +} + +fn reference_access(kind: &NameKind, name_ref: &ast::NameRef) -> Option { // Only Locals and Fields have accesses for now. match kind { NameKind::Local(_) | NameKind::Field(_) => {} @@ -311,7 +344,7 @@ fn main() { let refs = get_all_refs(code); check_result( refs, - "i BIND_PAT FileId(1) [33; 34) Other", + "i BIND_PAT FileId(1) [33; 34) Other Write", &[ "FileId(1) [67; 68) Other Write", "FileId(1) [71; 72) Other Read", @@ -569,7 +602,7 @@ fn foo() { let refs = get_all_refs(code); check_result( refs, - "i BIND_PAT FileId(1) [36; 37) Other", + "i BIND_PAT FileId(1) [36; 37) Other Write", &["FileId(1) [55; 56) Other Write", "FileId(1) [59; 60) Other Read"], ); } @@ -594,6 +627,22 @@ fn foo() { ); } + #[test] + fn test_basic_highlight_decl_no_write() { + let code = r#" + fn foo() { + let i<|>; + i = 1; + }"#; + + let refs = get_all_refs(code); + check_result( + refs, + "i BIND_PAT FileId(1) [36; 37) Other", + &["FileId(1) [51; 52) Other Write"], + ); + } + fn get_all_refs(text: &str) -> ReferenceSearchResult { let (analysis, position) = single_file_with_position(text); analysis.find_all_refs(position, None).unwrap().unwrap() From a633a6275ab823396f57b1e93d45e58d98f8d32f Mon Sep 17 00:00:00 2001 From: kjeremy Date: Fri, 10 Jan 2020 15:30:17 -0500 Subject: [PATCH 6/6] Fix Write being sent down the wire. Not sure what the deal is here but it wasn't sending Write. --- crates/ra_lsp_server/src/conv.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index 1b93195d7c6..562699b7cdc 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs @@ -57,10 +57,10 @@ impl Conv for ReferenceAccess { type Output = ::lsp_types::DocumentHighlightKind; fn conv(self) -> Self::Output { - use lsp_types::DocumentHighlightKind::*; + use lsp_types::DocumentHighlightKind; match self { - ReferenceAccess::Read => Read, - ReferenceAccess::Write => Write, + ReferenceAccess::Read => DocumentHighlightKind::Read, + ReferenceAccess::Write => DocumentHighlightKind::Write, } } }