aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_ide/src/lib.rs2
-rw-r--r--crates/ra_ide/src/references.rs73
-rw-r--r--crates/ra_lsp_server/src/conv.rs14
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs34
-rw-r--r--crates/ra_syntax/src/ast/expr_extensions.rs1
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::{
75 inlay_hints::{InlayHint, InlayKind}, 75 inlay_hints::{InlayHint, InlayKind},
76 line_index::{LineCol, LineIndex}, 76 line_index::{LineCol, LineIndex},
77 line_index_utils::translate_offset_with_edit, 77 line_index_utils::translate_offset_with_edit,
78 references::{Reference, ReferenceKind, ReferenceSearchResult, SearchScope}, 78 references::{Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, SearchScope},
79 runnables::{Runnable, RunnableKind}, 79 runnables::{Runnable, RunnableKind},
80 source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, 80 source_change::{FileSystemEdit, SourceChange, SourceFileEdit},
81 syntax_highlighting::HighlightedRange, 81 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;
19use ra_db::{SourceDatabase, SourceDatabaseExt}; 19use ra_db::{SourceDatabase, SourceDatabaseExt};
20use ra_prof::profile; 20use ra_prof::profile;
21use ra_syntax::{ 21use ra_syntax::{
22 algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, TextUnit, 22 algo::find_node_at_offset, ast, match_ast, AstNode, SourceFile, SyntaxKind, SyntaxNode,
23 TokenAtOffset, 23 TextUnit, TokenAtOffset,
24}; 24};
25 25
26use crate::{ 26use crate::{
@@ -46,6 +46,7 @@ pub struct ReferenceSearchResult {
46pub struct Reference { 46pub struct Reference {
47 pub file_range: FileRange, 47 pub file_range: FileRange,
48 pub kind: ReferenceKind, 48 pub kind: ReferenceKind,
49 pub access: Option<ReferenceAccess>,
49} 50}
50 51
51#[derive(Debug, Clone, PartialEq)] 52#[derive(Debug, Clone, PartialEq)]
@@ -54,6 +55,12 @@ pub enum ReferenceKind {
54 Other, 55 Other,
55} 56}
56 57
58#[derive(Debug, Clone, PartialEq)]
59pub enum ReferenceAccess {
60 Read,
61 Write,
62}
63
57impl ReferenceSearchResult { 64impl ReferenceSearchResult {
58 pub fn declaration(&self) -> &NavigationTarget { 65 pub fn declaration(&self) -> &NavigationTarget {
59 &self.declaration 66 &self.declaration
@@ -72,7 +79,7 @@ impl ReferenceSearchResult {
72} 79}
73 80
74// allow turning ReferenceSearchResult into an iterator 81// allow turning ReferenceSearchResult into an iterator
75// over FileRanges 82// over References
76impl IntoIterator for ReferenceSearchResult { 83impl IntoIterator for ReferenceSearchResult {
77 type Item = Reference; 84 type Item = Reference;
78 type IntoIter = std::vec::IntoIter<Reference>; 85 type IntoIter = std::vec::IntoIter<Reference>;
@@ -85,6 +92,7 @@ impl IntoIterator for ReferenceSearchResult {
85 range: self.declaration.range(), 92 range: self.declaration.range(),
86 }, 93 },
87 kind: self.declaration_kind, 94 kind: self.declaration_kind,
95 access: None,
88 }); 96 });
89 v.append(&mut self.references); 97 v.append(&mut self.references);
90 v.into_iter() 98 v.into_iter()
@@ -201,7 +209,13 @@ fn process_definition(
201 } else { 209 } else {
202 ReferenceKind::Other 210 ReferenceKind::Other
203 }; 211 };
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 });
205 } 219 }
206 } 220 }
207 } 221 }
@@ -210,11 +224,46 @@ fn process_definition(
210 refs 224 refs
211} 225}
212 226
227fn 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
213#[cfg(test)] 262#[cfg(test)]
214mod tests { 263mod tests {
215 use crate::{ 264 use crate::{
216 mock_analysis::{analysis_and_position, single_file_with_position, MockAnalysis}, 265 mock_analysis::{analysis_and_position, single_file_with_position, MockAnalysis},
217 Reference, ReferenceKind, ReferenceSearchResult, SearchScope, 266 Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, SearchScope,
218 }; 267 };
219 268
220 #[test] 269 #[test]
@@ -515,6 +564,20 @@ mod tests {
515 ); 564 );
516 } 565 }
517 566
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
518 fn get_all_refs(text: &str) -> ReferenceSearchResult { 581 fn get_all_refs(text: &str) -> ReferenceSearchResult {
519 let (analysis, position) = single_file_with_position(text); 582 let (analysis, position) = single_file_with_position(text);
520 analysis.find_all_refs(position, None).unwrap().unwrap() 583 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::{
9use ra_ide::{ 9use ra_ide::{
10 translate_offset_with_edit, CompletionItem, CompletionItemKind, FileId, FilePosition, 10 translate_offset_with_edit, CompletionItem, CompletionItemKind, FileId, FilePosition,
11 FileRange, FileSystemEdit, Fold, FoldKind, InsertTextFormat, LineCol, LineIndex, 11 FileRange, FileSystemEdit, Fold, FoldKind, InsertTextFormat, LineCol, LineIndex,
12 NavigationTarget, RangeInfo, Severity, SourceChange, SourceFileEdit, 12 NavigationTarget, RangeInfo, ReferenceAccess, Severity, SourceChange, SourceFileEdit,
13}; 13};
14use ra_syntax::{SyntaxKind, TextRange, TextUnit}; 14use ra_syntax::{SyntaxKind, TextRange, TextUnit};
15use ra_text_edit::{AtomTextEdit, TextEdit}; 15use ra_text_edit::{AtomTextEdit, TextEdit};
@@ -53,6 +53,18 @@ impl Conv for SyntaxKind {
53 } 53 }
54} 54}
55 55
56impl Conv for ReferenceAccess {
57 type Output = ::lsp_types::DocumentHighlightKind;
58
59 fn conv(self) -> Self::Output {
60 use lsp_types::DocumentHighlightKind::*;
61 match self {
62 ReferenceAccess::Read => Read,
63 ReferenceAccess::Write => Write,
64 }
65 }
66}
67
56impl Conv for CompletionItemKind { 68impl Conv for CompletionItemKind {
57 type Output = ::lsp_types::CompletionItemKind; 69 type Output = ::lsp_types::CompletionItemKind;
58 70
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(
536 536
537 let locations = if params.context.include_declaration { 537 let locations = if params.context.include_declaration {
538 refs.into_iter() 538 refs.into_iter()
539 .filter_map(|r| { 539 .filter_map(|reference| {
540 let line_index = world.analysis().file_line_index(r.file_range.file_id).ok()?; 540 let line_index =
541 to_location(r.file_range.file_id, r.file_range.range, &world, &line_index).ok() 541 world.analysis().file_line_index(reference.file_range.file_id).ok()?;
542 to_location(
543 reference.file_range.file_id,
544 reference.file_range.range,
545 &world,
546 &line_index,
547 )
548 .ok()
542 }) 549 })
543 .collect() 550 .collect()
544 } else { 551 } else {
545 // Only iterate over the references if include_declaration was false 552 // Only iterate over the references if include_declaration was false
546 refs.references() 553 refs.references()
547 .iter() 554 .iter()
548 .filter_map(|r| { 555 .filter_map(|reference| {
549 let line_index = world.analysis().file_line_index(r.file_range.file_id).ok()?; 556 let line_index =
550 to_location(r.file_range.file_id, r.file_range.range, &world, &line_index).ok() 557 world.analysis().file_line_index(reference.file_range.file_id).ok()?;
558 to_location(
559 reference.file_range.file_id,
560 reference.file_range.range,
561 &world,
562 &line_index,
563 )
564 .ok()
551 }) 565 })
552 .collect() 566 .collect()
553 }; 567 };
@@ -836,10 +850,10 @@ pub fn handle_document_highlight(
836 850
837 Ok(Some( 851 Ok(Some(
838 refs.into_iter() 852 refs.into_iter()
839 .filter(|r| r.file_range.file_id == file_id) 853 .filter(|reference| reference.file_range.file_id == file_id)
840 .map(|r| DocumentHighlight { 854 .map(|reference| DocumentHighlight {
841 range: r.file_range.range.conv_with(&line_index), 855 range: reference.file_range.range.conv_with(&line_index),
842 kind: None, 856 kind: reference.access.map(|it| it.conv()),
843 }) 857 })
844 .collect(), 858 .collect(),
845 )) 859 ))
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 {
144 } 144 }
145 } 145 }
146} 146}
147
147impl ast::BinExpr { 148impl ast::BinExpr {
148 pub fn op_details(&self) -> Option<(SyntaxToken, BinOp)> { 149 pub fn op_details(&self) -> Option<(SyntaxToken, BinOp)> {
149 self.syntax().children_with_tokens().filter_map(|it| it.into_token()).find_map(|c| { 150 self.syntax().children_with_tokens().filter_map(|it| it.into_token()).find_map(|c| {