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 ++++++++++++++++++++++++-- crates/ra_lsp_server/src/conv.rs | 14 ++++- crates/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 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() diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index c260b51c4..1b93195d7 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs @@ -9,7 +9,7 @@ use lsp_types::{ 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 @@ impl Conv for SyntaxKind { } } +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 a5b6f48af..a592f0a12 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 23b6aa901..3dfecfe76 100644 --- a/crates/ra_syntax/src/ast/expr_extensions.rs +++ b/crates/ra_syntax/src/ast/expr_extensions.rs @@ -144,6 +144,7 @@ impl BinOp { } } } + 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| { -- cgit v1.2.3