mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-11-03 05:13:35 +00:00
Merge pull request #19079 from ChayimFriedman2/rename-conflict
feat: Warn the user when a rename will change the meaning of the program
This commit is contained in:
commit
cf255a61d5
12 changed files with 509 additions and 59 deletions
|
|
@ -12,8 +12,8 @@ use std::{
|
|||
|
||||
use either::Either;
|
||||
use hir_def::{
|
||||
expr_store::ExprOrPatSource,
|
||||
hir::{Expr, ExprOrPatId},
|
||||
expr_store::{Body, ExprOrPatSource},
|
||||
hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat},
|
||||
lower::LowerCtx,
|
||||
nameres::{MacroSubNs, ModuleOrigin},
|
||||
path::ModPath,
|
||||
|
|
@ -629,6 +629,31 @@ impl<'db> SemanticsImpl<'db> {
|
|||
)
|
||||
}
|
||||
|
||||
/// Checks if renaming `renamed` to `new_name` may introduce conflicts with other locals,
|
||||
/// and returns the conflicting locals.
|
||||
pub fn rename_conflicts(&self, to_be_renamed: &Local, new_name: &str) -> Vec<Local> {
|
||||
let body = self.db.body(to_be_renamed.parent);
|
||||
let resolver = to_be_renamed.parent.resolver(self.db.upcast());
|
||||
let starting_expr =
|
||||
body.binding_owners.get(&to_be_renamed.binding_id).copied().unwrap_or(body.body_expr);
|
||||
let mut visitor = RenameConflictsVisitor {
|
||||
body: &body,
|
||||
conflicts: FxHashSet::default(),
|
||||
db: self.db,
|
||||
new_name: Symbol::intern(new_name),
|
||||
old_name: to_be_renamed.name(self.db).symbol().clone(),
|
||||
owner: to_be_renamed.parent,
|
||||
to_be_renamed: to_be_renamed.binding_id,
|
||||
resolver,
|
||||
};
|
||||
visitor.rename_conflicts(starting_expr);
|
||||
visitor
|
||||
.conflicts
|
||||
.into_iter()
|
||||
.map(|binding_id| Local { parent: to_be_renamed.parent, binding_id })
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Retrieves all the formatting parts of the format_args! (or `asm!`) template string.
|
||||
pub fn as_format_args_parts(
|
||||
&self,
|
||||
|
|
@ -2094,3 +2119,69 @@ impl ops::Deref for VisibleTraits {
|
|||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
struct RenameConflictsVisitor<'a> {
|
||||
db: &'a dyn HirDatabase,
|
||||
owner: DefWithBodyId,
|
||||
resolver: Resolver,
|
||||
body: &'a Body,
|
||||
to_be_renamed: BindingId,
|
||||
new_name: Symbol,
|
||||
old_name: Symbol,
|
||||
conflicts: FxHashSet<BindingId>,
|
||||
}
|
||||
|
||||
impl RenameConflictsVisitor<'_> {
|
||||
fn resolve_path(&mut self, node: ExprOrPatId, path: &Path) {
|
||||
if let Path::BarePath(path) = path {
|
||||
if let Some(name) = path.as_ident() {
|
||||
if *name.symbol() == self.new_name {
|
||||
if let Some(conflicting) = self.resolver.rename_will_conflict_with_renamed(
|
||||
self.db.upcast(),
|
||||
name,
|
||||
path,
|
||||
self.body.expr_or_pat_path_hygiene(node),
|
||||
self.to_be_renamed,
|
||||
) {
|
||||
self.conflicts.insert(conflicting);
|
||||
}
|
||||
} else if *name.symbol() == self.old_name {
|
||||
if let Some(conflicting) =
|
||||
self.resolver.rename_will_conflict_with_another_variable(
|
||||
self.db.upcast(),
|
||||
name,
|
||||
path,
|
||||
self.body.expr_or_pat_path_hygiene(node),
|
||||
&self.new_name,
|
||||
self.to_be_renamed,
|
||||
)
|
||||
{
|
||||
self.conflicts.insert(conflicting);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn rename_conflicts(&mut self, expr: ExprId) {
|
||||
match &self.body[expr] {
|
||||
Expr::Path(path) => {
|
||||
let guard = self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr);
|
||||
self.resolve_path(expr.into(), path);
|
||||
self.resolver.reset_to_guard(guard);
|
||||
}
|
||||
&Expr::Assignment { target, .. } => {
|
||||
let guard = self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr);
|
||||
self.body.walk_pats(target, &mut |pat| {
|
||||
if let Pat::Path(path) = &self.body[pat] {
|
||||
self.resolve_path(pat.into(), path);
|
||||
}
|
||||
});
|
||||
self.resolver.reset_to_guard(guard);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.body.walk_child_exprs(expr, |expr| self.rename_conflicts(expr));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue