diff options
-rw-r--r-- | crates/ra_ide/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/references.rs | 73 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/conv.rs | 14 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 34 | ||||
-rw-r--r-- | 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::{ | |||
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; | |||
19 | use ra_db::{SourceDatabase, SourceDatabaseExt}; | 19 | use ra_db::{SourceDatabase, SourceDatabaseExt}; |
20 | use ra_prof::profile; | 20 | use ra_prof::profile; |
21 | use ra_syntax::{ | 21 | use 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 | ||
26 | use crate::{ | 26 | use crate::{ |
@@ -46,6 +46,7 @@ pub struct ReferenceSearchResult { | |||
46 | pub struct Reference { | 46 | pub 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)] | ||
59 | pub enum ReferenceAccess { | ||
60 | Read, | ||
61 | Write, | ||
62 | } | ||
63 | |||
57 | impl ReferenceSearchResult { | 64 | impl 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 |
76 | impl IntoIterator for ReferenceSearchResult { | 83 | impl 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 | ||
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 | |||
213 | #[cfg(test)] | 262 | #[cfg(test)] |
214 | mod tests { | 263 | mod 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::{ | |||
9 | use ra_ide::{ | 9 | use 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 | }; |
14 | use ra_syntax::{SyntaxKind, TextRange, TextUnit}; | 14 | use ra_syntax::{SyntaxKind, TextRange, TextUnit}; |
15 | use ra_text_edit::{AtomTextEdit, TextEdit}; | 15 | use ra_text_edit::{AtomTextEdit, TextEdit}; |
@@ -53,6 +53,18 @@ impl Conv for SyntaxKind { | |||
53 | } | 53 | } |
54 | } | 54 | } |
55 | 55 | ||
56 | impl 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 | |||
56 | impl Conv for CompletionItemKind { | 68 | impl 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 | |||
147 | impl ast::BinExpr { | 148 | impl 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| { |