move resolve_local to Scopes
This commit is contained in:
parent
7207eef716
commit
16f67ee384
6 changed files with 105 additions and 109 deletions
|
@ -6,8 +6,8 @@ use std::{
|
|||
};
|
||||
|
||||
use ra_syntax::{
|
||||
TextRange, TextUnit, SyntaxNodeRef,
|
||||
ast::{self, AstNode, DocCommentsOwner, NameOwner},
|
||||
TextRange, TextUnit,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
@ -39,6 +39,32 @@ impl FunctionDescriptor {
|
|||
FunctionDescriptor { fn_id }
|
||||
}
|
||||
|
||||
pub(crate) fn guess_for_name_ref(
|
||||
db: &impl HirDatabase,
|
||||
file_id: FileId,
|
||||
name_ref: ast::NameRef,
|
||||
) -> Option<FunctionDescriptor> {
|
||||
FunctionDescriptor::guess_for_node(db, file_id, name_ref.syntax())
|
||||
}
|
||||
|
||||
pub(crate) fn guess_for_bind_pat(
|
||||
db: &impl HirDatabase,
|
||||
file_id: FileId,
|
||||
bind_pat: ast::BindPat,
|
||||
) -> Option<FunctionDescriptor> {
|
||||
FunctionDescriptor::guess_for_node(db, file_id, bind_pat.syntax())
|
||||
}
|
||||
|
||||
fn guess_for_node(
|
||||
db: &impl HirDatabase,
|
||||
file_id: FileId,
|
||||
node: SyntaxNodeRef,
|
||||
) -> Option<FunctionDescriptor> {
|
||||
let fn_def = node.ancestors().find_map(ast::FnDef::cast)?;
|
||||
let res = FunctionDescriptor::guess_from_source(db, file_id, fn_def);
|
||||
Some(res)
|
||||
}
|
||||
|
||||
pub(crate) fn scope(&self, db: &impl HirDatabase) -> Arc<FnScopes> {
|
||||
db.fn_scopes(self.fn_id)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use ra_syntax::{
|
||||
AstNode, SmolStr, SyntaxNodeRef, TextRange,
|
||||
algo::generate,
|
||||
ast::{self, ArgListOwner, LoopBodyOwner, NameOwner},
|
||||
AstNode, SmolStr, SyntaxNodeRef,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
@ -70,6 +70,27 @@ impl FnScopes {
|
|||
.nth(0);
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn find_all_refs(&self, pat: ast::BindPat) -> Vec<ReferenceDescriptor> {
|
||||
let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap();
|
||||
let name_ptr = LocalSyntaxPtr::new(pat.syntax());
|
||||
let refs: Vec<_> = fn_def
|
||||
.syntax()
|
||||
.descendants()
|
||||
.filter_map(ast::NameRef::cast)
|
||||
.filter(|name_ref| match self.resolve_local_name(*name_ref) {
|
||||
None => false,
|
||||
Some(entry) => entry.ptr() == name_ptr,
|
||||
})
|
||||
.map(|name_ref| ReferenceDescriptor {
|
||||
name: name_ref.syntax().text().to_string(),
|
||||
range: name_ref.syntax().range(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
refs
|
||||
}
|
||||
|
||||
fn root_scope(&mut self) -> ScopeId {
|
||||
self.scopes.alloc(ScopeData {
|
||||
parent: None,
|
||||
|
@ -262,6 +283,12 @@ fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ReferenceDescriptor {
|
||||
pub range: TextRange,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ra_editor::find_node_at_offset;
|
||||
|
|
|
@ -11,15 +11,9 @@ mod function;
|
|||
mod module;
|
||||
mod path;
|
||||
|
||||
use ra_syntax::{
|
||||
ast::{self, AstNode},
|
||||
TextRange,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
hir::db::HirDatabase,
|
||||
loc2id::{DefId, DefLoc},
|
||||
syntax_ptr::LocalSyntaxPtr,
|
||||
Cancelable,
|
||||
};
|
||||
|
||||
|
@ -49,50 +43,3 @@ impl DefId {
|
|||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ReferenceDescriptor {
|
||||
pub range: TextRange,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DeclarationDescriptor<'a> {
|
||||
pat: ast::BindPat<'a>,
|
||||
pub range: TextRange,
|
||||
}
|
||||
|
||||
impl<'a> DeclarationDescriptor<'a> {
|
||||
pub fn new(pat: ast::BindPat) -> DeclarationDescriptor {
|
||||
let range = pat.syntax().range();
|
||||
|
||||
DeclarationDescriptor { pat, range }
|
||||
}
|
||||
|
||||
pub fn find_all_refs(&self) -> Vec<ReferenceDescriptor> {
|
||||
let name_ptr = LocalSyntaxPtr::new(self.pat.syntax());
|
||||
|
||||
let fn_def = match self.pat.syntax().ancestors().find_map(ast::FnDef::cast) {
|
||||
Some(def) => def,
|
||||
None => return Default::default(),
|
||||
};
|
||||
|
||||
let fn_scopes = FnScopes::new(fn_def);
|
||||
|
||||
let refs: Vec<_> = fn_def
|
||||
.syntax()
|
||||
.descendants()
|
||||
.filter_map(ast::NameRef::cast)
|
||||
.filter(|name_ref| match fn_scopes.resolve_local_name(*name_ref) {
|
||||
None => false,
|
||||
Some(entry) => entry.ptr() == name_ptr,
|
||||
})
|
||||
.map(|name_ref| ReferenceDescriptor {
|
||||
name: name_ref.syntax().text().to_string(),
|
||||
range: name_ref.syntax().range(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
refs
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::{
|
|||
use ra_editor::{self, find_node_at_offset, FileSymbol, LineIndex, LocalEdit};
|
||||
use ra_syntax::{
|
||||
ast::{self, ArgListOwner, Expr, NameOwner},
|
||||
AstNode, SourceFileNode, SmolStr,
|
||||
AstNode, SourceFileNode,
|
||||
SyntaxKind::*,
|
||||
SyntaxNodeRef, TextRange, TextUnit,
|
||||
};
|
||||
|
@ -22,7 +22,6 @@ use crate::{
|
|||
hir::{
|
||||
FunctionDescriptor, FnSignatureInfo, ModuleDescriptor,
|
||||
Problem,
|
||||
DeclarationDescriptor,
|
||||
},
|
||||
input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE},
|
||||
symbol_index::SymbolIndex,
|
||||
|
@ -273,24 +272,27 @@ impl AnalysisImpl {
|
|||
let file = self.db.file_syntax(position.file_id);
|
||||
let syntax = file.syntax();
|
||||
if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) {
|
||||
// First try to resolve the symbol locally
|
||||
return if let Some((name, range)) =
|
||||
resolve_local_name(&self.db, position.file_id, name_ref)
|
||||
if let Some(fn_descr) =
|
||||
FunctionDescriptor::guess_for_name_ref(&*self.db, position.file_id, name_ref)
|
||||
{
|
||||
let mut vec = vec![];
|
||||
vec.push((
|
||||
position.file_id,
|
||||
FileSymbol {
|
||||
name,
|
||||
node_range: range,
|
||||
kind: NAME,
|
||||
},
|
||||
));
|
||||
Ok(vec)
|
||||
} else {
|
||||
// If that fails try the index based approach.
|
||||
self.index_resolve(name_ref)
|
||||
};
|
||||
let scope = fn_descr.scope(&*self.db);
|
||||
// First try to resolve the symbol locally
|
||||
return if let Some(entry) = scope.resolve_local_name(name_ref) {
|
||||
let mut vec = vec![];
|
||||
vec.push((
|
||||
position.file_id,
|
||||
FileSymbol {
|
||||
name: entry.name().clone(),
|
||||
node_range: entry.ptr().range(),
|
||||
kind: NAME,
|
||||
},
|
||||
));
|
||||
Ok(vec)
|
||||
} else {
|
||||
// If that fails try the index based approach.
|
||||
self.index_resolve(name_ref)
|
||||
};
|
||||
}
|
||||
}
|
||||
if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) {
|
||||
if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
|
||||
|
@ -320,31 +322,41 @@ impl AnalysisImpl {
|
|||
|
||||
pub fn find_all_refs(&self, position: FilePosition) -> Vec<(FileId, TextRange)> {
|
||||
let file = self.db.file_syntax(position.file_id);
|
||||
let syntax = file.syntax();
|
||||
|
||||
// Find the binding associated with the offset
|
||||
let maybe_binding =
|
||||
find_node_at_offset::<ast::BindPat>(syntax, position.offset).or_else(|| {
|
||||
let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?;
|
||||
let resolved = resolve_local_name(&self.db, position.file_id, name_ref)?;
|
||||
find_node_at_offset::<ast::BindPat>(syntax, resolved.1.end())
|
||||
});
|
||||
|
||||
let binding = match maybe_binding {
|
||||
let (binding, descr) = match find_binding(&self.db, &file, position) {
|
||||
None => return Vec::new(),
|
||||
Some(it) => it,
|
||||
};
|
||||
|
||||
let decl = DeclarationDescriptor::new(binding);
|
||||
|
||||
let mut ret = vec![(position.file_id, decl.range)];
|
||||
let mut ret = vec![(position.file_id, binding.syntax().range())];
|
||||
ret.extend(
|
||||
decl.find_all_refs()
|
||||
descr
|
||||
.scope(&*self.db)
|
||||
.find_all_refs(binding)
|
||||
.into_iter()
|
||||
.map(|ref_desc| (position.file_id, ref_desc.range)),
|
||||
);
|
||||
|
||||
ret
|
||||
return ret;
|
||||
|
||||
fn find_binding<'a>(
|
||||
db: &db::RootDatabase,
|
||||
source_file: &'a SourceFileNode,
|
||||
position: FilePosition,
|
||||
) -> Option<(ast::BindPat<'a>, FunctionDescriptor)> {
|
||||
let syntax = source_file.syntax();
|
||||
if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) {
|
||||
let descr = FunctionDescriptor::guess_for_bind_pat(db, position.file_id, binding)?;
|
||||
return Some((binding, descr));
|
||||
};
|
||||
let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?;
|
||||
let descr = FunctionDescriptor::guess_for_name_ref(db, position.file_id, name_ref)?;
|
||||
let scope = descr.scope(db);
|
||||
let resolved = scope.resolve_local_name(name_ref)?;
|
||||
let resolved = resolved.ptr().resolve(source_file);
|
||||
let binding = find_node_at_offset::<ast::BindPat>(syntax, resolved.range().end())?;
|
||||
Some((binding, descr))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn doc_comment_for(
|
||||
|
@ -582,16 +594,3 @@ impl<'a> FnCallNode<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_local_name(
|
||||
db: &db::RootDatabase,
|
||||
file_id: FileId,
|
||||
name_ref: ast::NameRef,
|
||||
) -> Option<(SmolStr, TextRange)> {
|
||||
let fn_def = name_ref.syntax().ancestors().find_map(ast::FnDef::cast)?;
|
||||
let function = FunctionDescriptor::guess_from_source(db, file_id, fn_def);
|
||||
let scopes = function.scope(db);
|
||||
let scope_entry = scopes.resolve_local_name(name_ref)?;
|
||||
let syntax = db.resolve_syntax_ptr(scope_entry.ptr().into_global(file_id));
|
||||
Some((scope_entry.name().clone(), syntax.range()))
|
||||
}
|
||||
|
|
|
@ -56,11 +56,8 @@ impl LocalSyntaxPtr {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_global(self, file_id: FileId) -> SyntaxPtr {
|
||||
SyntaxPtr {
|
||||
file_id,
|
||||
local: self,
|
||||
}
|
||||
pub(crate) fn range(self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,10 +10,10 @@ use test_utils::assert_eq_dbg;
|
|||
|
||||
use ra_analysis::{
|
||||
mock_analysis::{analysis_and_position, single_file, single_file_with_position, MockAnalysis},
|
||||
AnalysisChange, CrateGraph, FileId, FnDescriptor,
|
||||
AnalysisChange, CrateGraph, FileId, FnSignatureInfo,
|
||||
};
|
||||
|
||||
fn get_signature(text: &str) -> (FnDescriptor, Option<usize>) {
|
||||
fn get_signature(text: &str) -> (FnSignatureInfo, Option<usize>) {
|
||||
let (analysis, position) = single_file_with_position(text);
|
||||
analysis.resolve_callable(position).unwrap().unwrap()
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue