move resolve_local to Scopes

This commit is contained in:
Aleksey Kladov 2018-11-28 01:11:29 +03:00
parent 7207eef716
commit 16f67ee384
6 changed files with 105 additions and 109 deletions

View file

@ -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)
}

View file

@ -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;

View file

@ -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
}
}

View file

@ -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()))
}

View file

@ -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
}
}

View file

@ -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()
}