Merge pull request #3678 from edwin0cheng/refactor-rename

Fix rename argument in macro call
This commit is contained in:
Aleksey Kladov 2020-03-23 14:06:40 +01:00 committed by GitHub
commit a2f7ca27c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 112 additions and 26 deletions

View File

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

View File

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

View File

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

View File

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