mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-13 18:37:33 +00:00
move resolve_local to Scopes
This commit is contained in:
parent
7207eef716
commit
16f67ee384
@ -6,8 +6,8 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
|
TextRange, TextUnit, SyntaxNodeRef,
|
||||||
ast::{self, AstNode, DocCommentsOwner, NameOwner},
|
ast::{self, AstNode, DocCommentsOwner, NameOwner},
|
||||||
TextRange, TextUnit,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -39,6 +39,32 @@ impl FunctionDescriptor {
|
|||||||
FunctionDescriptor { fn_id }
|
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> {
|
pub(crate) fn scope(&self, db: &impl HirDatabase) -> Arc<FnScopes> {
|
||||||
db.fn_scopes(self.fn_id)
|
db.fn_scopes(self.fn_id)
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
|
AstNode, SmolStr, SyntaxNodeRef, TextRange,
|
||||||
algo::generate,
|
algo::generate,
|
||||||
ast::{self, ArgListOwner, LoopBodyOwner, NameOwner},
|
ast::{self, ArgListOwner, LoopBodyOwner, NameOwner},
|
||||||
AstNode, SmolStr, SyntaxNodeRef,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -70,6 +70,27 @@ impl FnScopes {
|
|||||||
.nth(0);
|
.nth(0);
|
||||||
ret
|
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 {
|
fn root_scope(&mut self) -> ScopeId {
|
||||||
self.scopes.alloc(ScopeData {
|
self.scopes.alloc(ScopeData {
|
||||||
parent: None,
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use ra_editor::find_node_at_offset;
|
use ra_editor::find_node_at_offset;
|
||||||
|
@ -11,15 +11,9 @@ mod function;
|
|||||||
mod module;
|
mod module;
|
||||||
mod path;
|
mod path;
|
||||||
|
|
||||||
use ra_syntax::{
|
|
||||||
ast::{self, AstNode},
|
|
||||||
TextRange,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
hir::db::HirDatabase,
|
hir::db::HirDatabase,
|
||||||
loc2id::{DefId, DefLoc},
|
loc2id::{DefId, DefLoc},
|
||||||
syntax_ptr::LocalSyntaxPtr,
|
|
||||||
Cancelable,
|
Cancelable,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -49,50 +43,3 @@ impl DefId {
|
|||||||
Ok(res)
|
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_editor::{self, find_node_at_offset, FileSymbol, LineIndex, LocalEdit};
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
ast::{self, ArgListOwner, Expr, NameOwner},
|
ast::{self, ArgListOwner, Expr, NameOwner},
|
||||||
AstNode, SourceFileNode, SmolStr,
|
AstNode, SourceFileNode,
|
||||||
SyntaxKind::*,
|
SyntaxKind::*,
|
||||||
SyntaxNodeRef, TextRange, TextUnit,
|
SyntaxNodeRef, TextRange, TextUnit,
|
||||||
};
|
};
|
||||||
@ -22,7 +22,6 @@ use crate::{
|
|||||||
hir::{
|
hir::{
|
||||||
FunctionDescriptor, FnSignatureInfo, ModuleDescriptor,
|
FunctionDescriptor, FnSignatureInfo, ModuleDescriptor,
|
||||||
Problem,
|
Problem,
|
||||||
DeclarationDescriptor,
|
|
||||||
},
|
},
|
||||||
input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE},
|
input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE},
|
||||||
symbol_index::SymbolIndex,
|
symbol_index::SymbolIndex,
|
||||||
@ -273,24 +272,27 @@ impl AnalysisImpl {
|
|||||||
let file = self.db.file_syntax(position.file_id);
|
let file = self.db.file_syntax(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) {
|
||||||
// First try to resolve the symbol locally
|
if let Some(fn_descr) =
|
||||||
return if let Some((name, range)) =
|
FunctionDescriptor::guess_for_name_ref(&*self.db, position.file_id, name_ref)
|
||||||
resolve_local_name(&self.db, position.file_id, name_ref)
|
|
||||||
{
|
{
|
||||||
let mut vec = vec![];
|
let scope = fn_descr.scope(&*self.db);
|
||||||
vec.push((
|
// First try to resolve the symbol locally
|
||||||
position.file_id,
|
return if let Some(entry) = scope.resolve_local_name(name_ref) {
|
||||||
FileSymbol {
|
let mut vec = vec![];
|
||||||
name,
|
vec.push((
|
||||||
node_range: range,
|
position.file_id,
|
||||||
kind: NAME,
|
FileSymbol {
|
||||||
},
|
name: entry.name().clone(),
|
||||||
));
|
node_range: entry.ptr().range(),
|
||||||
Ok(vec)
|
kind: NAME,
|
||||||
} else {
|
},
|
||||||
// If that fails try the index based approach.
|
));
|
||||||
self.index_resolve(name_ref)
|
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(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) {
|
||||||
if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
|
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)> {
|
pub fn find_all_refs(&self, position: FilePosition) -> Vec<(FileId, TextRange)> {
|
||||||
let file = self.db.file_syntax(position.file_id);
|
let file = self.db.file_syntax(position.file_id);
|
||||||
let syntax = file.syntax();
|
|
||||||
|
|
||||||
// Find the binding associated with the offset
|
// Find the binding associated with the offset
|
||||||
let maybe_binding =
|
let (binding, descr) = match find_binding(&self.db, &file, position) {
|
||||||
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 {
|
|
||||||
None => return Vec::new(),
|
None => return Vec::new(),
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
};
|
};
|
||||||
|
|
||||||
let decl = DeclarationDescriptor::new(binding);
|
let mut ret = vec![(position.file_id, binding.syntax().range())];
|
||||||
|
|
||||||
let mut ret = vec![(position.file_id, decl.range)];
|
|
||||||
ret.extend(
|
ret.extend(
|
||||||
decl.find_all_refs()
|
descr
|
||||||
|
.scope(&*self.db)
|
||||||
|
.find_all_refs(binding)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|ref_desc| (position.file_id, ref_desc.range)),
|
.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(
|
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 {
|
pub(crate) fn range(self) -> TextRange {
|
||||||
SyntaxPtr {
|
self.range
|
||||||
file_id,
|
|
||||||
local: self,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,10 +10,10 @@ use test_utils::assert_eq_dbg;
|
|||||||
|
|
||||||
use ra_analysis::{
|
use ra_analysis::{
|
||||||
mock_analysis::{analysis_and_position, single_file, single_file_with_position, MockAnalysis},
|
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);
|
let (analysis, position) = single_file_with_position(text);
|
||||||
analysis.resolve_callable(position).unwrap().unwrap()
|
analysis.resolve_callable(position).unwrap().unwrap()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user