Basic DocumentHighlightKind support for assignments
This commit is contained in:
parent
19eb7fa1db
commit
d993f329a0
@ -75,7 +75,7 @@ pub use crate::{
|
|||||||
inlay_hints::{InlayHint, InlayKind},
|
inlay_hints::{InlayHint, InlayKind},
|
||||||
line_index::{LineCol, LineIndex},
|
line_index::{LineCol, LineIndex},
|
||||||
line_index_utils::translate_offset_with_edit,
|
line_index_utils::translate_offset_with_edit,
|
||||||
references::{Reference, ReferenceKind, ReferenceSearchResult, SearchScope},
|
references::{Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, SearchScope},
|
||||||
runnables::{Runnable, RunnableKind},
|
runnables::{Runnable, RunnableKind},
|
||||||
source_change::{FileSystemEdit, SourceChange, SourceFileEdit},
|
source_change::{FileSystemEdit, SourceChange, SourceFileEdit},
|
||||||
syntax_highlighting::HighlightedRange,
|
syntax_highlighting::HighlightedRange,
|
||||||
|
@ -19,8 +19,8 @@ use once_cell::unsync::Lazy;
|
|||||||
use ra_db::{SourceDatabase, SourceDatabaseExt};
|
use ra_db::{SourceDatabase, SourceDatabaseExt};
|
||||||
use ra_prof::profile;
|
use ra_prof::profile;
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, TextUnit,
|
algo::find_node_at_offset, ast, match_ast, AstNode, SourceFile, SyntaxKind, SyntaxNode,
|
||||||
TokenAtOffset,
|
TextUnit, TokenAtOffset,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -46,6 +46,7 @@ pub struct ReferenceSearchResult {
|
|||||||
pub struct Reference {
|
pub struct Reference {
|
||||||
pub file_range: FileRange,
|
pub file_range: FileRange,
|
||||||
pub kind: ReferenceKind,
|
pub kind: ReferenceKind,
|
||||||
|
pub access: Option<ReferenceAccess>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
@ -54,6 +55,12 @@ pub enum ReferenceKind {
|
|||||||
Other,
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum ReferenceAccess {
|
||||||
|
Read,
|
||||||
|
Write,
|
||||||
|
}
|
||||||
|
|
||||||
impl ReferenceSearchResult {
|
impl ReferenceSearchResult {
|
||||||
pub fn declaration(&self) -> &NavigationTarget {
|
pub fn declaration(&self) -> &NavigationTarget {
|
||||||
&self.declaration
|
&self.declaration
|
||||||
@ -72,7 +79,7 @@ impl ReferenceSearchResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// allow turning ReferenceSearchResult into an iterator
|
// allow turning ReferenceSearchResult into an iterator
|
||||||
// over FileRanges
|
// over References
|
||||||
impl IntoIterator for ReferenceSearchResult {
|
impl IntoIterator for ReferenceSearchResult {
|
||||||
type Item = Reference;
|
type Item = Reference;
|
||||||
type IntoIter = std::vec::IntoIter<Reference>;
|
type IntoIter = std::vec::IntoIter<Reference>;
|
||||||
@ -85,6 +92,7 @@ impl IntoIterator for ReferenceSearchResult {
|
|||||||
range: self.declaration.range(),
|
range: self.declaration.range(),
|
||||||
},
|
},
|
||||||
kind: self.declaration_kind,
|
kind: self.declaration_kind,
|
||||||
|
access: None,
|
||||||
});
|
});
|
||||||
v.append(&mut self.references);
|
v.append(&mut self.references);
|
||||||
v.into_iter()
|
v.into_iter()
|
||||||
@ -201,7 +209,13 @@ fn process_definition(
|
|||||||
} else {
|
} else {
|
||||||
ReferenceKind::Other
|
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
|
refs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn access_mode(kind: NameKind, name_ref: &ast::NameRef) -> Option<ReferenceAccess> {
|
||||||
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
mock_analysis::{analysis_and_position, single_file_with_position, MockAnalysis},
|
mock_analysis::{analysis_and_position, single_file_with_position, MockAnalysis},
|
||||||
Reference, ReferenceKind, ReferenceSearchResult, SearchScope,
|
Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult, SearchScope,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[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 {
|
fn get_all_refs(text: &str) -> ReferenceSearchResult {
|
||||||
let (analysis, position) = single_file_with_position(text);
|
let (analysis, position) = single_file_with_position(text);
|
||||||
analysis.find_all_refs(position, None).unwrap().unwrap()
|
analysis.find_all_refs(position, None).unwrap().unwrap()
|
||||||
|
@ -9,7 +9,7 @@ use lsp_types::{
|
|||||||
use ra_ide::{
|
use ra_ide::{
|
||||||
translate_offset_with_edit, CompletionItem, CompletionItemKind, FileId, FilePosition,
|
translate_offset_with_edit, CompletionItem, CompletionItemKind, FileId, FilePosition,
|
||||||
FileRange, FileSystemEdit, Fold, FoldKind, InsertTextFormat, LineCol, LineIndex,
|
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_syntax::{SyntaxKind, TextRange, TextUnit};
|
||||||
use ra_text_edit::{AtomTextEdit, TextEdit};
|
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 {
|
impl Conv for CompletionItemKind {
|
||||||
type Output = ::lsp_types::CompletionItemKind;
|
type Output = ::lsp_types::CompletionItemKind;
|
||||||
|
|
||||||
|
@ -536,18 +536,32 @@ pub fn handle_references(
|
|||||||
|
|
||||||
let locations = if params.context.include_declaration {
|
let locations = if params.context.include_declaration {
|
||||||
refs.into_iter()
|
refs.into_iter()
|
||||||
.filter_map(|r| {
|
.filter_map(|reference| {
|
||||||
let line_index = world.analysis().file_line_index(r.file_range.file_id).ok()?;
|
let line_index =
|
||||||
to_location(r.file_range.file_id, r.file_range.range, &world, &line_index).ok()
|
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()
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
// Only iterate over the references if include_declaration was false
|
// Only iterate over the references if include_declaration was false
|
||||||
refs.references()
|
refs.references()
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|r| {
|
.filter_map(|reference| {
|
||||||
let line_index = world.analysis().file_line_index(r.file_range.file_id).ok()?;
|
let line_index =
|
||||||
to_location(r.file_range.file_id, r.file_range.range, &world, &line_index).ok()
|
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()
|
.collect()
|
||||||
};
|
};
|
||||||
@ -836,10 +850,10 @@ pub fn handle_document_highlight(
|
|||||||
|
|
||||||
Ok(Some(
|
Ok(Some(
|
||||||
refs.into_iter()
|
refs.into_iter()
|
||||||
.filter(|r| r.file_range.file_id == file_id)
|
.filter(|reference| reference.file_range.file_id == file_id)
|
||||||
.map(|r| DocumentHighlight {
|
.map(|reference| DocumentHighlight {
|
||||||
range: r.file_range.range.conv_with(&line_index),
|
range: reference.file_range.range.conv_with(&line_index),
|
||||||
kind: None,
|
kind: reference.access.map(|it| it.conv()),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
))
|
))
|
||||||
|
@ -144,6 +144,7 @@ impl BinOp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ast::BinExpr {
|
impl ast::BinExpr {
|
||||||
pub fn op_details(&self) -> Option<(SyntaxToken, BinOp)> {
|
pub fn op_details(&self) -> Option<(SyntaxToken, BinOp)> {
|
||||||
self.syntax().children_with_tokens().filter_map(|it| it.into_token()).find_map(|c| {
|
self.syntax().children_with_tokens().filter_map(|it| it.into_token()).find_map(|c| {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user