Refactor symbol resolve API

Introduce ReferenceResolution to avoid nesting to many non-nominal
types.
This commit is contained in:
Aleksey Kladov 2018-12-08 21:18:29 +03:00
parent 7a79cde107
commit 7fd6a41127
4 changed files with 59 additions and 24 deletions

View file

@ -27,6 +27,7 @@ use crate::{
symbol_index::{SymbolIndex, SymbolsDatabase},
AnalysisChange, Cancelable, CrateId, Diagnostic, FileId,
FileSystemEdit, FilePosition, Query, SourceChange, SourceFileNodeEdit,
ReferenceResolution,
};
#[derive(Debug, Default)]
@ -206,10 +207,11 @@ impl AnalysisImpl {
pub fn approximately_resolve_symbol(
&self,
position: FilePosition,
) -> Cancelable<Option<(TextRange, Vec<(FileId, FileSymbol)>)>> {
) -> Cancelable<Option<ReferenceResolution>> {
let file = self.db.source_file(position.file_id);
let syntax = file.syntax();
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(
&*self.db,
position.file_id,
@ -218,24 +220,25 @@ impl AnalysisImpl {
let scope = fn_descr.scope(&*self.db);
// First try to resolve the symbol locally
if let Some(entry) = scope.resolve_local_name(name_ref) {
let vec = vec![(
rr.add_resolution(
position.file_id,
FileSymbol {
name: entry.name().clone(),
node_range: entry.ptr().range(),
kind: NAME,
},
)];
return Ok(Some((name_ref.syntax().range(), vec)));
);
return Ok(Some(rr));
};
}
// If that fails try the index based approach.
return Ok(Some((
name_ref.syntax().range(),
self.index_resolve(name_ref)?,
)));
for (file_id, symbol) in self.index_resolve(name_ref)? {
rr.add_resolution(file_id, symbol);
}
return Ok(Some(rr));
}
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 module.has_semi() {
let parent_module =
@ -250,7 +253,8 @@ impl AnalysisImpl {
node_range: TextRange::offset_len(0.into(), 0.into()),
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 =
ctry!(ra_syntax::algo::find_leaf_at_offset(syntax, position.offset).left_biased())
.range();
Ok(Some((range, vec![])))
Ok(None)
}
pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> {

View file

@ -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
/// entry point for asking semantic information about the world. When the world
/// state is advanced using `AnalysisHost::apply_change` method, all existing
@ -236,7 +260,7 @@ impl Analysis {
pub fn approximately_resolve_symbol(
&self,
position: FilePosition,
) -> Cancelable<Option<(TextRange, Vec<(FileId, FileSymbol)>)>> {
) -> Cancelable<Option<ReferenceResolution>> {
self.imp.approximately_resolve_symbol(position)
}
pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> {