From d993f329a01deb3cdc011c3eb1dfd859302fec04 Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Sat, 4 Jan 2020 17:46:01 -0500 Subject: Basic DocumentHighlightKind support for assignments --- crates/ra_ide/src/lib.rs | 2 +- crates/ra_ide/src/references.rs | 73 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 69 insertions(+), 6 deletions(-) (limited to 'crates/ra_ide') diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index 7b187eba3..837315ca7 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs @@ -75,7 +75,7 @@ pub use crate::{ 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 5a3ec4eb9..b9d8a6b1e 100644 --- a/crates/ra_ide/src/references.rs +++ b/crates/ra_ide/src/references.rs @@ -19,8 +19,8 @@ use once_cell::unsync::Lazy; 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 @@ impl ReferenceSearchResult { } // 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 @@ impl IntoIterator for ReferenceSearchResult { 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 @@ mod tests { ); } + #[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() -- cgit v1.2.3