mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-11-13 17:35:21 +00:00
Merge pull request #20387 from ChayimFriedman2/rename-macro
Some checks are pending
metrics / build_metrics (push) Waiting to run
metrics / other_metrics (diesel-1.4.8) (push) Blocked by required conditions
metrics / other_metrics (hyper-0.14.18) (push) Blocked by required conditions
metrics / other_metrics (ripgrep-13.0.0) (push) Blocked by required conditions
metrics / other_metrics (self) (push) Blocked by required conditions
metrics / other_metrics (webrender-2022) (push) Blocked by required conditions
metrics / generate_final_metrics (push) Blocked by required conditions
rustdoc / rustdoc (push) Waiting to run
Some checks are pending
metrics / build_metrics (push) Waiting to run
metrics / other_metrics (diesel-1.4.8) (push) Blocked by required conditions
metrics / other_metrics (hyper-0.14.18) (push) Blocked by required conditions
metrics / other_metrics (ripgrep-13.0.0) (push) Blocked by required conditions
metrics / other_metrics (self) (push) Blocked by required conditions
metrics / other_metrics (webrender-2022) (push) Blocked by required conditions
metrics / generate_final_metrics (push) Blocked by required conditions
rustdoc / rustdoc (push) Waiting to run
fix: Do not remove the original token when descending into derives
This commit is contained in:
commit
8241ec6b02
2 changed files with 78 additions and 60 deletions
|
|
@ -1241,29 +1241,27 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
adt,
|
adt,
|
||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
let mut res = None;
|
|
||||||
for (_, derive_attr, derives) in derives {
|
for (_, derive_attr, derives) in derives {
|
||||||
// as there may be multiple derives registering the same helper
|
// as there may be multiple derives registering the same helper
|
||||||
// name, we gotta make sure to call this for all of them!
|
// name, we gotta make sure to call this for all of them!
|
||||||
// FIXME: We need to call `f` for all of them as well though!
|
// FIXME: We need to call `f` for all of them as well though!
|
||||||
res = res.or(process_expansion_for_token(
|
process_expansion_for_token(ctx, &mut stack, derive_attr);
|
||||||
ctx,
|
|
||||||
&mut stack,
|
|
||||||
derive_attr,
|
|
||||||
));
|
|
||||||
for derive in derives.into_iter().flatten() {
|
for derive in derives.into_iter().flatten() {
|
||||||
res = res
|
process_expansion_for_token(ctx, &mut stack, derive);
|
||||||
.or(process_expansion_for_token(ctx, &mut stack, derive));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// remove all tokens that are within the derives expansion
|
// remove all tokens that are within the derives expansion
|
||||||
filter_duplicates(tokens, adt.syntax().text_range());
|
filter_duplicates(tokens, adt.syntax().text_range());
|
||||||
Some(res)
|
Some(())
|
||||||
});
|
});
|
||||||
// if we found derives, we can early exit. There is no way we can be in any
|
// if we found derives, we can early exit. There is no way we can be in any
|
||||||
// macro call at this point given we are not in a token tree
|
// macro call at this point given we are not in a token tree
|
||||||
if let Some(res) = res {
|
if let Some(()) = res {
|
||||||
return res;
|
// Note: derives do not remap the original token. Furthermore, we want
|
||||||
|
// the original token to be before the derives in the list, because if they
|
||||||
|
// upmap to the same token and we deduplicate them (e.g. in rename), we
|
||||||
|
// want the original token to remain, not the derive.
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Then check for token trees, that means we are either in a function-like macro or
|
// Then check for token trees, that means we are either in a function-like macro or
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,27 @@ pub use ide_db::rename::RenameError;
|
||||||
|
|
||||||
type RenameResult<T> = Result<T, RenameError>;
|
type RenameResult<T> = Result<T, RenameError>;
|
||||||
|
|
||||||
|
/// This is similar to `collect::<Result<Vec<_>, _>>`, but unlike it, it succeeds if there is *any* `Ok` item.
|
||||||
|
fn ok_if_any<T, E>(iter: impl Iterator<Item = Result<T, E>>) -> Result<Vec<T>, E> {
|
||||||
|
let mut err = None;
|
||||||
|
let oks = iter
|
||||||
|
.filter_map(|item| match item {
|
||||||
|
Ok(it) => Some(it),
|
||||||
|
Err(it) => {
|
||||||
|
err = Some(it);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
if !oks.is_empty() {
|
||||||
|
Ok(oks)
|
||||||
|
} else if let Some(err) = err {
|
||||||
|
Err(err)
|
||||||
|
} else {
|
||||||
|
Ok(Vec::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Prepares a rename. The sole job of this function is to return the TextRange of the thing that is
|
/// Prepares a rename. The sole job of this function is to return the TextRange of the thing that is
|
||||||
/// being targeted for a rename.
|
/// being targeted for a rename.
|
||||||
pub(crate) fn prepare_rename(
|
pub(crate) fn prepare_rename(
|
||||||
|
|
@ -95,7 +116,8 @@ pub(crate) fn rename(
|
||||||
alias_fallback(syntax, position, &new_name.display(db, edition).to_string());
|
alias_fallback(syntax, position, &new_name.display(db, edition).to_string());
|
||||||
|
|
||||||
let ops: RenameResult<Vec<SourceChange>> = match alias_fallback {
|
let ops: RenameResult<Vec<SourceChange>> = match alias_fallback {
|
||||||
Some(_) => defs
|
Some(_) => ok_if_any(
|
||||||
|
defs
|
||||||
// FIXME: This can use the `ide_db::rename_reference` (or def.rename) method once we can
|
// FIXME: This can use the `ide_db::rename_reference` (or def.rename) method once we can
|
||||||
// properly find "direct" usages/references.
|
// properly find "direct" usages/references.
|
||||||
.map(|(.., def, new_name, _)| {
|
.map(|(.., def, new_name, _)| {
|
||||||
|
|
@ -130,10 +152,9 @@ pub(crate) fn rename(
|
||||||
}));
|
}));
|
||||||
|
|
||||||
Ok(source_change)
|
Ok(source_change)
|
||||||
})
|
}),
|
||||||
.collect(),
|
),
|
||||||
None => defs
|
None => ok_if_any(defs.map(|(.., def, new_name, rename_def)| {
|
||||||
.map(|(.., def, new_name, rename_def)| {
|
|
||||||
if let Definition::Local(local) = def {
|
if let Definition::Local(local) = def {
|
||||||
if let Some(self_param) = local.as_self_param(sema.db) {
|
if let Some(self_param) = local.as_self_param(sema.db) {
|
||||||
cov_mark::hit!(rename_self_to_param);
|
cov_mark::hit!(rename_self_to_param);
|
||||||
|
|
@ -145,8 +166,7 @@ pub(crate) fn rename(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def.rename(&sema, new_name.as_str(), rename_def)
|
def.rename(&sema, new_name.as_str(), rename_def)
|
||||||
})
|
})),
|
||||||
.collect(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ops?.into_iter()
|
ops?.into_iter()
|
||||||
|
|
@ -320,7 +340,7 @@ fn find_definitions(
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let res: RenameResult<Vec<_>> = symbols.filter_map(Result::transpose).collect();
|
let res: RenameResult<Vec<_>> = ok_if_any(symbols.filter_map(Result::transpose));
|
||||||
match res {
|
match res {
|
||||||
Ok(v) => {
|
Ok(v) => {
|
||||||
// remove duplicates, comparing `Definition`s
|
// remove duplicates, comparing `Definition`s
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue