mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-28 10:39:45 +00:00
Migrate PathTransform to SyntaxEditor
Signed-off-by: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com>
This commit is contained in:
parent
4866c4c2eb
commit
46e86c6aa2
8 changed files with 168 additions and 86 deletions
|
|
@ -12,7 +12,7 @@ use span::Edition;
|
|||
use syntax::{
|
||||
NodeOrToken, SyntaxNode,
|
||||
ast::{self, AstNode, HasGenericArgs, make},
|
||||
ted,
|
||||
syntax_editor::{self, SyntaxEditor},
|
||||
};
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
|
|
@ -129,15 +129,18 @@ impl<'a> PathTransform<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn apply(&self, syntax: &SyntaxNode) {
|
||||
#[must_use]
|
||||
pub fn apply(&self, syntax: &SyntaxNode) -> SyntaxNode {
|
||||
self.build_ctx().apply(syntax)
|
||||
}
|
||||
|
||||
pub fn apply_all<'b>(&self, nodes: impl IntoIterator<Item = &'b SyntaxNode>) {
|
||||
#[must_use]
|
||||
pub fn apply_all<'b>(
|
||||
&self,
|
||||
nodes: impl IntoIterator<Item = &'b SyntaxNode>,
|
||||
) -> Vec<SyntaxNode> {
|
||||
let ctx = self.build_ctx();
|
||||
for node in nodes {
|
||||
ctx.apply(node);
|
||||
}
|
||||
nodes.into_iter().map(|node| ctx.apply(&node.clone())).collect()
|
||||
}
|
||||
|
||||
fn prettify_target_node(&self, node: SyntaxNode) -> SyntaxNode {
|
||||
|
|
@ -237,7 +240,7 @@ impl<'a> PathTransform<'a> {
|
|||
Some((k.name(db).display(db, target_edition).to_string(), v.lifetime()?))
|
||||
})
|
||||
.collect();
|
||||
let ctx = Ctx {
|
||||
let mut ctx = Ctx {
|
||||
type_substs,
|
||||
const_substs,
|
||||
lifetime_substs,
|
||||
|
|
@ -273,42 +276,75 @@ fn preorder_rev(item: &SyntaxNode) -> impl Iterator<Item = SyntaxNode> {
|
|||
}
|
||||
|
||||
impl Ctx<'_> {
|
||||
fn apply(&self, item: &SyntaxNode) {
|
||||
fn apply(&self, item: &SyntaxNode) -> SyntaxNode {
|
||||
// `transform_path` may update a node's parent and that would break the
|
||||
// tree traversal. Thus all paths in the tree are collected into a vec
|
||||
// so that such operation is safe.
|
||||
let paths = preorder_rev(item).filter_map(ast::Path::cast).collect::<Vec<_>>();
|
||||
for path in paths {
|
||||
self.transform_path(path);
|
||||
}
|
||||
|
||||
preorder_rev(item).filter_map(ast::Lifetime::cast).for_each(|lifetime| {
|
||||
let item = self.transform_path(item).clone_subtree();
|
||||
let mut editor = SyntaxEditor::new(item.clone());
|
||||
preorder_rev(&item).filter_map(ast::Lifetime::cast).for_each(|lifetime| {
|
||||
if let Some(subst) = self.lifetime_substs.get(&lifetime.syntax().text().to_string()) {
|
||||
ted::replace(lifetime.syntax(), subst.clone_subtree().clone_for_update().syntax());
|
||||
editor
|
||||
.replace(lifetime.syntax(), subst.clone_subtree().clone_for_update().syntax());
|
||||
}
|
||||
});
|
||||
|
||||
editor.finish().new_root().clone()
|
||||
}
|
||||
|
||||
fn transform_default_values(&self, defaulted_params: Vec<DefaultedParam>) {
|
||||
fn transform_default_values(&mut self, defaulted_params: Vec<DefaultedParam>) {
|
||||
// By now the default values are simply copied from where they are declared
|
||||
// and should be transformed. As any value is allowed to refer to previous
|
||||
// generic (both type and const) parameters, they should be all iterated left-to-right.
|
||||
for param in defaulted_params {
|
||||
let value = match param {
|
||||
Either::Left(k) => self.type_substs.get(&k).unwrap().syntax(),
|
||||
Either::Right(k) => self.const_substs.get(&k).unwrap(),
|
||||
let value = match ¶m {
|
||||
Either::Left(k) => self.type_substs.get(k).unwrap().syntax(),
|
||||
Either::Right(k) => self.const_substs.get(k).unwrap(),
|
||||
};
|
||||
// `transform_path` may update a node's parent and that would break the
|
||||
// tree traversal. Thus all paths in the tree are collected into a vec
|
||||
// so that such operation is safe.
|
||||
let paths = preorder_rev(value).filter_map(ast::Path::cast).collect::<Vec<_>>();
|
||||
for path in paths {
|
||||
self.transform_path(path);
|
||||
let new_value = self.transform_path(value);
|
||||
match param {
|
||||
Either::Left(k) => {
|
||||
self.type_substs.insert(k, ast::Type::cast(new_value.clone()).unwrap());
|
||||
}
|
||||
Either::Right(k) => {
|
||||
self.const_substs.insert(k, new_value.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn transform_path(&self, path: ast::Path) -> Option<()> {
|
||||
fn transform_path(&self, path: &SyntaxNode) -> SyntaxNode {
|
||||
fn find_child_paths(root_path: &SyntaxNode) -> Vec<ast::Path> {
|
||||
let mut result = Vec::new();
|
||||
for child in root_path.children() {
|
||||
if let Some(child_path) = ast::Path::cast(child.clone()) {
|
||||
result.push(child_path);
|
||||
} else {
|
||||
result.extend(find_child_paths(&child));
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
let root_path = path.clone_subtree();
|
||||
let result = find_child_paths(&root_path);
|
||||
let mut editor = SyntaxEditor::new(root_path.clone());
|
||||
for sub_path in result {
|
||||
let new = self.transform_path(sub_path.syntax());
|
||||
editor.replace(sub_path.syntax(), new);
|
||||
}
|
||||
let update_sub_item = editor.finish().new_root().clone().clone_subtree();
|
||||
let item = find_child_paths(&update_sub_item);
|
||||
let mut editor = SyntaxEditor::new(update_sub_item);
|
||||
for sub_path in item {
|
||||
self.transform_path_(&mut editor, &sub_path);
|
||||
}
|
||||
editor.finish().new_root().clone()
|
||||
}
|
||||
|
||||
fn transform_path_(&self, editor: &mut SyntaxEditor, path: &ast::Path) -> Option<()> {
|
||||
if path.qualifier().is_some() {
|
||||
return None;
|
||||
}
|
||||
|
|
@ -320,8 +356,7 @@ impl Ctx<'_> {
|
|||
// don't try to qualify sole `self` either, they are usually locals, but are returned as modules due to namespace clashing
|
||||
return None;
|
||||
}
|
||||
|
||||
let resolution = self.source_scope.speculative_resolve(&path)?;
|
||||
let resolution = self.source_scope.speculative_resolve(path)?;
|
||||
|
||||
match resolution {
|
||||
hir::PathResolution::TypeParam(tp) => {
|
||||
|
|
@ -361,12 +396,12 @@ impl Ctx<'_> {
|
|||
|
||||
let segment = make::path_segment_ty(subst.clone(), trait_ref);
|
||||
let qualified = make::path_from_segments(std::iter::once(segment), false);
|
||||
ted::replace(path.syntax(), qualified.clone_for_update().syntax());
|
||||
editor.replace(path.syntax(), qualified.clone_for_update().syntax());
|
||||
} else if let Some(path_ty) = ast::PathType::cast(parent) {
|
||||
let old = path_ty.syntax();
|
||||
|
||||
if old.parent().is_some() {
|
||||
ted::replace(old, subst.clone_subtree().clone_for_update().syntax());
|
||||
editor.replace(old, subst.clone_subtree().clone_for_update().syntax());
|
||||
} else {
|
||||
// Some `path_ty` has no parent, especially ones made for default value
|
||||
// of type parameters.
|
||||
|
|
@ -378,13 +413,13 @@ impl Ctx<'_> {
|
|||
}
|
||||
let start = path_ty.syntax().first_child().map(NodeOrToken::Node)?;
|
||||
let end = path_ty.syntax().last_child().map(NodeOrToken::Node)?;
|
||||
ted::replace_all(
|
||||
editor.replace_all(
|
||||
start..=end,
|
||||
new.syntax().children().map(NodeOrToken::Node).collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
ted::replace(
|
||||
editor.replace(
|
||||
path.syntax(),
|
||||
subst.clone_subtree().clone_for_update().syntax(),
|
||||
);
|
||||
|
|
@ -410,17 +445,28 @@ impl Ctx<'_> {
|
|||
};
|
||||
let found_path = self.target_module.find_path(self.source_scope.db, def, cfg)?;
|
||||
let res = mod_path_to_ast(&found_path, self.target_edition).clone_for_update();
|
||||
let mut res_editor = SyntaxEditor::new(res.syntax().clone_subtree());
|
||||
if let Some(args) = path.segment().and_then(|it| it.generic_arg_list()) {
|
||||
if let Some(segment) = res.segment() {
|
||||
let old = segment.get_or_create_generic_arg_list();
|
||||
ted::replace(old.syntax(), args.clone_subtree().syntax().clone_for_update())
|
||||
if let Some(old) = segment.generic_arg_list() {
|
||||
res_editor.replace(
|
||||
old.syntax(),
|
||||
args.clone_subtree().syntax().clone_for_update(),
|
||||
)
|
||||
} else {
|
||||
res_editor.insert(
|
||||
syntax_editor::Position::last_child_of(segment.syntax()),
|
||||
args.clone_subtree().syntax().clone_for_update(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
ted::replace(path.syntax(), res.syntax())
|
||||
let res = res_editor.finish().new_root().clone();
|
||||
editor.replace(path.syntax().clone(), res);
|
||||
}
|
||||
hir::PathResolution::ConstParam(cp) => {
|
||||
if let Some(subst) = self.const_substs.get(&cp) {
|
||||
ted::replace(path.syntax(), subst.clone_subtree().clone_for_update());
|
||||
editor.replace(path.syntax(), subst.clone_subtree().clone_for_update());
|
||||
}
|
||||
}
|
||||
hir::PathResolution::SelfType(imp) => {
|
||||
|
|
@ -457,13 +503,13 @@ impl Ctx<'_> {
|
|||
mod_path_to_ast(&found_path, self.target_edition).qualifier()
|
||||
{
|
||||
let res = make::path_concat(qual, path_ty.path()?).clone_for_update();
|
||||
ted::replace(path.syntax(), res.syntax());
|
||||
editor.replace(path.syntax(), res.syntax());
|
||||
return Some(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ted::replace(path.syntax(), ast_ty.syntax());
|
||||
editor.replace(path.syntax(), ast_ty.syntax());
|
||||
}
|
||||
hir::PathResolution::Local(_)
|
||||
| hir::PathResolution::Def(_)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue