mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 12:54:58 +00:00
Refactor symbol resolve API
Introduce ReferenceResolution to avoid nesting to many non-nominal types.
This commit is contained in:
parent
7a79cde107
commit
7fd6a41127
4 changed files with 59 additions and 24 deletions
|
@ -27,6 +27,7 @@ use crate::{
|
||||||
symbol_index::{SymbolIndex, SymbolsDatabase},
|
symbol_index::{SymbolIndex, SymbolsDatabase},
|
||||||
AnalysisChange, Cancelable, CrateId, Diagnostic, FileId,
|
AnalysisChange, Cancelable, CrateId, Diagnostic, FileId,
|
||||||
FileSystemEdit, FilePosition, Query, SourceChange, SourceFileNodeEdit,
|
FileSystemEdit, FilePosition, Query, SourceChange, SourceFileNodeEdit,
|
||||||
|
ReferenceResolution,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
@ -206,10 +207,11 @@ impl AnalysisImpl {
|
||||||
pub fn approximately_resolve_symbol(
|
pub fn approximately_resolve_symbol(
|
||||||
&self,
|
&self,
|
||||||
position: FilePosition,
|
position: FilePosition,
|
||||||
) -> Cancelable<Option<(TextRange, Vec<(FileId, FileSymbol)>)>> {
|
) -> Cancelable<Option<ReferenceResolution>> {
|
||||||
let file = self.db.source_file(position.file_id);
|
let file = self.db.source_file(position.file_id);
|
||||||
let syntax = file.syntax();
|
let syntax = file.syntax();
|
||||||
if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) {
|
if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) {
|
||||||
|
let mut rr = ReferenceResolution::new(name_ref.syntax().range());
|
||||||
if let Some(fn_descr) = source_binder::function_from_child_node(
|
if let Some(fn_descr) = source_binder::function_from_child_node(
|
||||||
&*self.db,
|
&*self.db,
|
||||||
position.file_id,
|
position.file_id,
|
||||||
|
@ -218,24 +220,25 @@ impl AnalysisImpl {
|
||||||
let scope = fn_descr.scope(&*self.db);
|
let scope = fn_descr.scope(&*self.db);
|
||||||
// First try to resolve the symbol locally
|
// First try to resolve the symbol locally
|
||||||
if let Some(entry) = scope.resolve_local_name(name_ref) {
|
if let Some(entry) = scope.resolve_local_name(name_ref) {
|
||||||
let vec = vec![(
|
rr.add_resolution(
|
||||||
position.file_id,
|
position.file_id,
|
||||||
FileSymbol {
|
FileSymbol {
|
||||||
name: entry.name().clone(),
|
name: entry.name().clone(),
|
||||||
node_range: entry.ptr().range(),
|
node_range: entry.ptr().range(),
|
||||||
kind: NAME,
|
kind: NAME,
|
||||||
},
|
},
|
||||||
)];
|
);
|
||||||
return Ok(Some((name_ref.syntax().range(), vec)));
|
return Ok(Some(rr));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// If that fails try the index based approach.
|
// If that fails try the index based approach.
|
||||||
return Ok(Some((
|
for (file_id, symbol) in self.index_resolve(name_ref)? {
|
||||||
name_ref.syntax().range(),
|
rr.add_resolution(file_id, symbol);
|
||||||
self.index_resolve(name_ref)?,
|
}
|
||||||
)));
|
return Ok(Some(rr));
|
||||||
}
|
}
|
||||||
if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) {
|
if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) {
|
||||||
|
let mut rr = ReferenceResolution::new(name.syntax().range());
|
||||||
if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
|
if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
|
||||||
if module.has_semi() {
|
if module.has_semi() {
|
||||||
let parent_module =
|
let parent_module =
|
||||||
|
@ -250,7 +253,8 @@ impl AnalysisImpl {
|
||||||
node_range: TextRange::offset_len(0.into(), 0.into()),
|
node_range: TextRange::offset_len(0.into(), 0.into()),
|
||||||
kind: MODULE,
|
kind: MODULE,
|
||||||
};
|
};
|
||||||
return Ok(Some((name.syntax().range(), vec![(file_id, symbol)])));
|
rr.add_resolution(file_id, symbol);
|
||||||
|
return Ok(Some(rr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
@ -258,10 +262,7 @@ impl AnalysisImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let range =
|
Ok(None)
|
||||||
ctry!(ra_syntax::algo::find_leaf_at_offset(syntax, position.offset).left_biased())
|
|
||||||
.range();
|
|
||||||
Ok(Some((range, vec![])))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> {
|
pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> {
|
||||||
|
|
|
@ -178,6 +178,30 @@ impl Query {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Result of "goto def" query.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ReferenceResolution {
|
||||||
|
/// The range of the reference itself. Client does not know what constitutes
|
||||||
|
/// a reference, it handles us only the offset. It's helpful to tell the
|
||||||
|
/// client where the reference was.
|
||||||
|
pub reference_range: TextRange,
|
||||||
|
/// What this reference resolves to.
|
||||||
|
pub resolves_to: Vec<(FileId, FileSymbol)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReferenceResolution {
|
||||||
|
fn new(reference_range: TextRange) -> ReferenceResolution {
|
||||||
|
ReferenceResolution {
|
||||||
|
reference_range,
|
||||||
|
resolves_to: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_resolution(&mut self, file_id: FileId, symbol: FileSymbol) {
|
||||||
|
self.resolves_to.push((file_id, symbol))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Analysis is a snapshot of a world state at a moment in time. It is the main
|
/// Analysis is a snapshot of a world state at a moment in time. It is the main
|
||||||
/// entry point for asking semantic information about the world. When the world
|
/// entry point for asking semantic information about the world. When the world
|
||||||
/// state is advanced using `AnalysisHost::apply_change` method, all existing
|
/// state is advanced using `AnalysisHost::apply_change` method, all existing
|
||||||
|
@ -236,7 +260,7 @@ impl Analysis {
|
||||||
pub fn approximately_resolve_symbol(
|
pub fn approximately_resolve_symbol(
|
||||||
&self,
|
&self,
|
||||||
position: FilePosition,
|
position: FilePosition,
|
||||||
) -> Cancelable<Option<(TextRange, Vec<(FileId, FileSymbol)>)>> {
|
) -> Cancelable<Option<ReferenceResolution>> {
|
||||||
self.imp.approximately_resolve_symbol(position)
|
self.imp.approximately_resolve_symbol(position)
|
||||||
}
|
}
|
||||||
pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> {
|
pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> {
|
||||||
|
|
|
@ -23,7 +23,10 @@ fn approximate_resolve_works_in_items() {
|
||||||
|
|
||||||
let symbols = analysis.approximately_resolve_symbol(pos).unwrap().unwrap();
|
let symbols = analysis.approximately_resolve_symbol(pos).unwrap().unwrap();
|
||||||
assert_eq_dbg(
|
assert_eq_dbg(
|
||||||
r#"([23; 26), [(FileId(1), FileSymbol { name: "Foo", node_range: [0; 11), kind: STRUCT_DEF })])"#,
|
r#"ReferenceResolution {
|
||||||
|
reference_range: [23; 26),
|
||||||
|
resolves_to: [(FileId(1), FileSymbol { name: "Foo", node_range: [0; 11), kind: STRUCT_DEF })]
|
||||||
|
}"#,
|
||||||
&symbols,
|
&symbols,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -41,7 +44,10 @@ fn test_resolve_module() {
|
||||||
|
|
||||||
let symbols = analysis.approximately_resolve_symbol(pos).unwrap().unwrap();
|
let symbols = analysis.approximately_resolve_symbol(pos).unwrap().unwrap();
|
||||||
assert_eq_dbg(
|
assert_eq_dbg(
|
||||||
r#"([4; 7), [(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })])"#,
|
r#"ReferenceResolution {
|
||||||
|
reference_range: [4; 7),
|
||||||
|
resolves_to: [(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]
|
||||||
|
}"#,
|
||||||
&symbols,
|
&symbols,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -56,7 +62,10 @@ fn test_resolve_module() {
|
||||||
|
|
||||||
let symbols = analysis.approximately_resolve_symbol(pos).unwrap().unwrap();
|
let symbols = analysis.approximately_resolve_symbol(pos).unwrap().unwrap();
|
||||||
assert_eq_dbg(
|
assert_eq_dbg(
|
||||||
r#"([4; 7), [(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })])"#,
|
r#"ReferenceResolution {
|
||||||
|
reference_range: [4; 7),
|
||||||
|
resolves_to: [(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]
|
||||||
|
}"#,
|
||||||
&symbols,
|
&symbols,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -203,11 +203,12 @@ pub fn handle_goto_definition(
|
||||||
params: req::TextDocumentPositionParams,
|
params: req::TextDocumentPositionParams,
|
||||||
) -> Result<Option<req::GotoDefinitionResponse>> {
|
) -> Result<Option<req::GotoDefinitionResponse>> {
|
||||||
let position = params.try_conv_with(&world)?;
|
let position = params.try_conv_with(&world)?;
|
||||||
let mut res = Vec::new();
|
let rr = match world.analysis().approximately_resolve_symbol(position)? {
|
||||||
for (file_id, symbol) in match world.analysis().approximately_resolve_symbol(position)? {
|
|
||||||
None => return Ok(None),
|
None => return Ok(None),
|
||||||
Some(it) => it.1,
|
Some(it) => it,
|
||||||
} {
|
};
|
||||||
|
let mut res = Vec::new();
|
||||||
|
for (file_id, symbol) in rr.resolves_to {
|
||||||
let line_index = world.analysis().file_line_index(file_id);
|
let line_index = world.analysis().file_line_index(file_id);
|
||||||
let location = to_location(file_id, symbol.node_range, &world, &line_index)?;
|
let location = to_location(file_id, symbol.node_range, &world, &line_index)?;
|
||||||
res.push(location)
|
res.push(location)
|
||||||
|
@ -510,17 +511,17 @@ pub fn handle_hover(
|
||||||
// TODO: Cut down on number of allocations
|
// TODO: Cut down on number of allocations
|
||||||
let position = params.try_conv_with(&world)?;
|
let position = params.try_conv_with(&world)?;
|
||||||
let line_index = world.analysis().file_line_index(position.file_id);
|
let line_index = world.analysis().file_line_index(position.file_id);
|
||||||
let (range, resolved) = match world.analysis().approximately_resolve_symbol(position)? {
|
let rr = match world.analysis().approximately_resolve_symbol(position)? {
|
||||||
None => return Ok(None),
|
None => return Ok(None),
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
};
|
};
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
for (file_id, symbol) in resolved {
|
for (file_id, symbol) in rr.resolves_to {
|
||||||
if let Some(docs) = world.analysis().doc_text_for(file_id, symbol)? {
|
if let Some(docs) = world.analysis().doc_text_for(file_id, symbol)? {
|
||||||
result.push(docs);
|
result.push(docs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let range = range.conv_with(&line_index);
|
let range = rr.reference_range.conv_with(&line_index);
|
||||||
if result.len() > 0 {
|
if result.len() > 0 {
|
||||||
return Ok(Some(Hover {
|
return Ok(Some(Hover {
|
||||||
contents: HoverContents::Scalar(MarkedString::String(result.join("\n\n---\n"))),
|
contents: HoverContents::Scalar(MarkedString::String(result.join("\n\n---\n"))),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue