Merge pull request #3678 from edwin0cheng/refactor-rename
Fix rename argument in macro call
This commit is contained in:
commit
a2f7ca27c0
@ -12,7 +12,8 @@
|
||||
use ra_db::{FileId, FileRange};
|
||||
use ra_prof::profile;
|
||||
use ra_syntax::{
|
||||
algo::skip_trivia_token, ast, AstNode, Direction, SyntaxNode, SyntaxToken, TextRange, TextUnit,
|
||||
algo::{find_node_at_offset, skip_trivia_token},
|
||||
ast, AstNode, Direction, SyntaxNode, SyntaxToken, TextRange, TextUnit,
|
||||
};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
@ -108,6 +109,17 @@ pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken {
|
||||
token.value
|
||||
}
|
||||
|
||||
pub fn descend_node_at_offset<N: ast::AstNode>(
|
||||
&self,
|
||||
node: &SyntaxNode,
|
||||
offset: TextUnit,
|
||||
) -> Option<N> {
|
||||
// Handle macro token cases
|
||||
node.token_at_offset(offset)
|
||||
.map(|token| self.descend_into_macros(token))
|
||||
.find_map(|it| self.ancestors_with_macros(it.parent()).find_map(N::cast))
|
||||
}
|
||||
|
||||
pub fn original_range(&self, node: &SyntaxNode) -> FileRange {
|
||||
let node = self.find_file(node.clone());
|
||||
original_range(self.db, node.as_ref())
|
||||
@ -129,6 +141,8 @@ pub fn ancestors_at_offset_with_macros(
|
||||
.kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len())
|
||||
}
|
||||
|
||||
/// Find a AstNode by offset inside SyntaxNode, if it is inside *Macrofile*,
|
||||
/// search up until it is of the target AstNode type
|
||||
pub fn find_node_at_offset_with_macros<N: AstNode>(
|
||||
&self,
|
||||
node: &SyntaxNode,
|
||||
@ -137,6 +151,19 @@ pub fn find_node_at_offset_with_macros<N: AstNode>(
|
||||
self.ancestors_at_offset_with_macros(node, offset).find_map(N::cast)
|
||||
}
|
||||
|
||||
/// Find a AstNode by offset inside SyntaxNode, if it is inside *MacroCall*,
|
||||
/// descend it and find again
|
||||
pub fn find_node_at_offset_with_descend<N: AstNode>(
|
||||
&self,
|
||||
node: &SyntaxNode,
|
||||
offset: TextUnit,
|
||||
) -> Option<N> {
|
||||
if let Some(it) = find_node_at_offset(&node, offset) {
|
||||
return Some(it);
|
||||
}
|
||||
self.descend_node_at_offset(&node, offset)
|
||||
}
|
||||
|
||||
pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> {
|
||||
self.analyze(expr.syntax()).type_of(self.db, &expr)
|
||||
}
|
||||
|
@ -94,12 +94,16 @@ pub(crate) fn find_all_refs(
|
||||
let sema = Semantics::new(db);
|
||||
let syntax = sema.parse(position.file_id).syntax().clone();
|
||||
|
||||
let (opt_name, search_kind) =
|
||||
if let Some(name) = get_struct_def_name_for_struct_literal_search(&syntax, position) {
|
||||
(Some(name), ReferenceKind::StructLiteral)
|
||||
} else {
|
||||
(find_node_at_offset::<ast::Name>(&syntax, position.offset), ReferenceKind::Other)
|
||||
};
|
||||
let (opt_name, search_kind) = if let Some(name) =
|
||||
get_struct_def_name_for_struct_literal_search(&sema, &syntax, position)
|
||||
{
|
||||
(Some(name), ReferenceKind::StructLiteral)
|
||||
} else {
|
||||
(
|
||||
sema.find_node_at_offset_with_descend::<ast::Name>(&syntax, position.offset),
|
||||
ReferenceKind::Other,
|
||||
)
|
||||
};
|
||||
|
||||
let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?;
|
||||
|
||||
@ -131,7 +135,8 @@ fn find_name(
|
||||
let range = name.syntax().text_range();
|
||||
return Some(RangeInfo::new(range, def));
|
||||
}
|
||||
let name_ref = find_node_at_offset::<ast::NameRef>(&syntax, position.offset)?;
|
||||
let name_ref =
|
||||
sema.find_node_at_offset_with_descend::<ast::NameRef>(&syntax, position.offset)?;
|
||||
let def = classify_name_ref(sema, &name_ref)?.definition();
|
||||
let range = name_ref.syntax().text_range();
|
||||
Some(RangeInfo::new(range, def))
|
||||
@ -157,6 +162,7 @@ fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Optio
|
||||
}
|
||||
|
||||
fn get_struct_def_name_for_struct_literal_search(
|
||||
sema: &Semantics<RootDatabase>,
|
||||
syntax: &SyntaxNode,
|
||||
position: FilePosition,
|
||||
) -> Option<ast::Name> {
|
||||
@ -164,10 +170,18 @@ fn get_struct_def_name_for_struct_literal_search(
|
||||
if right.kind() != SyntaxKind::L_CURLY && right.kind() != SyntaxKind::L_PAREN {
|
||||
return None;
|
||||
}
|
||||
if let Some(name) = find_node_at_offset::<ast::Name>(&syntax, left.text_range().start()) {
|
||||
if let Some(name) =
|
||||
sema.find_node_at_offset_with_descend::<ast::Name>(&syntax, left.text_range().start())
|
||||
{
|
||||
return name.syntax().ancestors().find_map(ast::StructDef::cast).and_then(|l| l.name());
|
||||
}
|
||||
if find_node_at_offset::<ast::TypeParamList>(&syntax, left.text_range().start()).is_some() {
|
||||
if sema
|
||||
.find_node_at_offset_with_descend::<ast::TypeParamList>(
|
||||
&syntax,
|
||||
left.text_range().start(),
|
||||
)
|
||||
.is_some()
|
||||
{
|
||||
return left.ancestors().find_map(ast::StructDef::cast).and_then(|l| l.name());
|
||||
}
|
||||
}
|
||||
|
@ -249,6 +249,63 @@ fn main() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rename_for_macro_args_rev() {
|
||||
test_rename(
|
||||
r#"
|
||||
macro_rules! foo {($i:ident) => {$i} }
|
||||
fn main() {
|
||||
let a = "test";
|
||||
foo!(a<|>);
|
||||
}"#,
|
||||
"b",
|
||||
r#"
|
||||
macro_rules! foo {($i:ident) => {$i} }
|
||||
fn main() {
|
||||
let b = "test";
|
||||
foo!(b);
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rename_for_macro_define_fn() {
|
||||
test_rename(
|
||||
r#"
|
||||
macro_rules! define_fn {($id:ident) => { fn $id{} }}
|
||||
define_fn!(foo);
|
||||
fn main() {
|
||||
fo<|>o();
|
||||
}"#,
|
||||
"bar",
|
||||
r#"
|
||||
macro_rules! define_fn {($id:ident) => { fn $id{} }}
|
||||
define_fn!(bar);
|
||||
fn main() {
|
||||
bar();
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rename_for_macro_define_fn_rev() {
|
||||
test_rename(
|
||||
r#"
|
||||
macro_rules! define_fn {($id:ident) => { fn $id{} }}
|
||||
define_fn!(fo<|>o);
|
||||
fn main() {
|
||||
foo();
|
||||
}"#,
|
||||
"bar",
|
||||
r#"
|
||||
macro_rules! define_fn {($id:ident) => { fn $id{} }}
|
||||
define_fn!(bar);
|
||||
fn main() {
|
||||
bar();
|
||||
}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rename_for_param_inside() {
|
||||
test_rename(
|
||||
|
@ -10,9 +10,7 @@
|
||||
use once_cell::unsync::Lazy;
|
||||
use ra_db::{FileId, FileRange, SourceDatabaseExt};
|
||||
use ra_prof::profile;
|
||||
use ra_syntax::{
|
||||
algo::find_node_at_offset, ast, match_ast, AstNode, TextRange, TextUnit, TokenAtOffset,
|
||||
};
|
||||
use ra_syntax::{ast, match_ast, AstNode, TextRange, TextUnit};
|
||||
use rustc_hash::FxHashMap;
|
||||
use test_utils::tested_by;
|
||||
|
||||
@ -219,21 +217,11 @@ pub fn find_usages(
|
||||
continue;
|
||||
}
|
||||
|
||||
let name_ref =
|
||||
if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(&tree, offset) {
|
||||
let name_ref: ast::NameRef =
|
||||
if let Some(name_ref) = sema.find_node_at_offset_with_descend(&tree, offset) {
|
||||
name_ref
|
||||
} else {
|
||||
// Handle macro token cases
|
||||
let token = match tree.token_at_offset(offset) {
|
||||
TokenAtOffset::None => continue,
|
||||
TokenAtOffset::Single(t) => t,
|
||||
TokenAtOffset::Between(_, t) => t,
|
||||
};
|
||||
let expanded = sema.descend_into_macros(token);
|
||||
match ast::NameRef::cast(expanded.parent()) {
|
||||
Some(name_ref) => name_ref,
|
||||
_ => continue,
|
||||
}
|
||||
continue;
|
||||
};
|
||||
|
||||
// FIXME: reuse sb
|
||||
|
Loading…
Reference in New Issue
Block a user