Skip to content

Enhance renaming to include identifiers that are generated from the original symbol #19825

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions crates/hir/src/semantics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,20 @@ impl<DB: HirDatabase> Semantics<'_, DB> {
self.imp.descend_node_at_offset(node, offset).filter_map(|mut it| it.find_map(N::cast))
}

/// Find an AstNode by offset inside SyntaxNode, if it is inside
/// an attribute macro call, descend it and find again. Do not
/// care if the found name doesn't match the original name.
// FIXME: Rethink this API
pub fn find_nodes_at_offset_with_descend_any_name<'slf, N: AstNode + 'slf>(
&'slf self,
node: &SyntaxNode,
offset: TextSize,
) -> impl Iterator<Item = N> + 'slf {
self.imp
.descend_node_at_offset_any_name(node, offset)
.filter_map(|mut it| it.find_map(N::cast))
}

pub fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<Struct> {
self.imp.resolve_range_pat(range_pat).map(Struct::from)
}
Expand Down Expand Up @@ -972,6 +986,29 @@ impl<'db> SemanticsImpl<'db> {
r
}

/// Descends the token into expansions, returning the tokens that matches the input
/// token's [`SyntaxKind`].
pub fn descend_into_macros_exact_any_name(
&self,
token: SyntaxToken,
) -> SmallVec<[SyntaxToken; 1]> {
let mut r = smallvec![];
let kind = token.kind();

self.descend_into_macros_cb(token.clone(), |InFile { value, file_id: _ }, ctx| {
let mapped_kind = value.kind();
let any_ident_match = || kind.is_any_identifier() && value.kind().is_any_identifier();
let matches = (kind == mapped_kind || any_ident_match()) && !ctx.is_opaque(self.db);
if matches {
r.push(value);
}
});
if r.is_empty() {
r.push(token);
}
r
}

/// Descends the token into expansions, returning the first token that matches the input
/// token's [`SyntaxKind`] and text.
pub fn descend_into_macros_single_exact(&self, token: SyntaxToken) -> SyntaxToken {
Expand Down Expand Up @@ -1252,6 +1289,29 @@ impl<'db> SemanticsImpl<'db> {
})
}

// Note this return type is deliberate as [`find_nodes_at_offset_with_descend`] wants to stop
// traversing the inner iterator when it finds a node.
// The outer iterator is over the tokens descendants
// The inner iterator is the ancestors of a descendant
fn descend_node_at_offset_any_name(
&self,
node: &SyntaxNode,
offset: TextSize,
) -> impl Iterator<Item = impl Iterator<Item = SyntaxNode> + '_> + '_ {
node.token_at_offset(offset)
.map(move |token| self.descend_into_macros_exact_any_name(token))
.map(|descendants| {
descendants.into_iter().map(move |it| self.token_ancestors_with_macros(it))
})
// re-order the tokens from token_at_offset by returning the ancestors with the smaller first nodes first
// See algo::ancestors_at_offset, which uses the same approach
.kmerge_by(|left, right| {
left.clone()
.map(|node| node.text_range().len())
.lt(right.clone().map(|node| node.text_range().len()))
})
}

/// Attempts to map the node out of macro expanded files returning the original file range.
/// If upmapping is not possible, this will fall back to the range of the macro call of the
/// macro file the node resides in.
Expand Down
3 changes: 2 additions & 1 deletion crates/ide-assists/src/handlers/remove_underscore.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use ide_db::{
assists::AssistId,
defs::{Definition, NameClass, NameRefClass},
rename::RenameDefinition,
};
use syntax::{AstNode, ast};

Expand Down Expand Up @@ -61,7 +62,7 @@ pub(crate) fn remove_underscore(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
"Remove underscore from a used variable",
text_range,
|builder| {
let changes = def.rename(&ctx.sema, new_name).unwrap();
let changes = def.rename(&ctx.sema, new_name, RenameDefinition::Yes).unwrap();
builder.source_change = changes;
},
)
Expand Down
21 changes: 17 additions & 4 deletions crates/ide-db/src/rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ impl Definition {
&self,
sema: &Semantics<'_, RootDatabase>,
new_name: &str,
rename_definition: RenameDefinition,
) -> Result<SourceChange> {
// We append `r#` if needed.
let new_name = new_name.trim_start_matches("r#");
Expand Down Expand Up @@ -103,8 +104,10 @@ impl Definition {
bail!("Cannot rename a builtin attr.")
}
Definition::SelfType(_) => bail!("Cannot rename `Self`"),
Definition::Macro(mac) => rename_reference(sema, Definition::Macro(mac), new_name),
def => rename_reference(sema, def, new_name),
Definition::Macro(mac) => {
rename_reference(sema, Definition::Macro(mac), new_name, RenameDefinition::Yes)
}
def => rename_reference(sema, def, new_name, rename_definition),
}
}

Expand Down Expand Up @@ -328,6 +331,7 @@ fn rename_reference(
sema: &Semantics<'_, RootDatabase>,
def: Definition,
new_name: &str,
rename_definition: RenameDefinition,
) -> Result<SourceChange> {
let ident_kind = IdentifierKind::classify(new_name)?;

Expand Down Expand Up @@ -369,11 +373,20 @@ fn rename_reference(

// This needs to come after the references edits, because we change the annotation of existing edits
// if a conflict is detected.
let (file_id, edit) = source_edit_from_def(sema, def, new_name, &mut source_change)?;
source_change.insert_source_edit(file_id, edit);
if rename_definition == RenameDefinition::Yes {
let (file_id, edit) = source_edit_from_def(sema, def, new_name, &mut source_change)?;

source_change.insert_source_edit(file_id, edit);
}
Ok(source_change)
}

#[derive(Copy, Clone, PartialEq)]
pub enum RenameDefinition {
Yes,
No,
}

pub fn source_edit_from_references(
references: &[FileReference],
def: Definition,
Expand Down
4 changes: 2 additions & 2 deletions crates/ide-diagnostics/src/handlers/incorrect_case.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use hir::{CaseType, InFile, db::ExpandDatabase};
use ide_db::{assists::Assist, defs::NameClass};
use ide_db::{assists::Assist, defs::NameClass, rename::RenameDefinition};
use syntax::AstNode;

use crate::{
Expand Down Expand Up @@ -44,7 +44,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option<Vec<Ass
let label = format!("Rename to {}", d.suggested_text);
let mut res = unresolved_fix("change_case", &label, frange.range);
if ctx.resolve.should_resolve(&res.id) {
let source_change = def.rename(&ctx.sema, &d.suggested_text);
let source_change = def.rename(&ctx.sema, &d.suggested_text, RenameDefinition::Yes);
res.source_change = Some(source_change.ok().unwrap_or_default());
}

Expand Down
Loading
Loading