mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Use mutable syntax trees in merge_imports
, split_imports
This commit is contained in:
parent
4c20d6879f
commit
601413df8f
7 changed files with 144 additions and 113 deletions
|
@ -80,7 +80,7 @@ use std::fmt$0::{Display, Debug};
|
||||||
use std::fmt::{Display, Debug};
|
use std::fmt::{Display, Debug};
|
||||||
",
|
",
|
||||||
r"
|
r"
|
||||||
use std::fmt::{Debug, Display};
|
use std::fmt::{Display, Debug};
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ use std::fmt::Debug;
|
||||||
use std::fmt$0::Display;
|
use std::fmt$0::Display;
|
||||||
",
|
",
|
||||||
r"
|
r"
|
||||||
use std::fmt::{Debug, Display};
|
use std::fmt::{Display, Debug};
|
||||||
",
|
",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,7 @@ use std::fmt::{self, Display};
|
||||||
use std::{fmt, $0fmt::Display};
|
use std::{fmt, $0fmt::Display};
|
||||||
",
|
",
|
||||||
r"
|
r"
|
||||||
use std::{fmt::{self, Display}};
|
use std::{fmt::{Display, self}};
|
||||||
",
|
",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -247,7 +247,7 @@ use std::{fmt::{Debug, Display}};
|
||||||
use std::{fmt::Debug, fmt$0::Display};
|
use std::{fmt::Debug, fmt$0::Display};
|
||||||
",
|
",
|
||||||
r"
|
r"
|
||||||
use std::{fmt::{Debug, Display}};
|
use std::{fmt::{Display, Debug}};
|
||||||
",
|
",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -341,7 +341,9 @@ use foo::$0{
|
||||||
};
|
};
|
||||||
",
|
",
|
||||||
r"
|
r"
|
||||||
use foo::{FooBar, bar::baz};
|
use foo::{
|
||||||
|
FooBar, bar::baz,
|
||||||
|
};
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -299,7 +299,7 @@ fn main() {
|
||||||
",
|
",
|
||||||
r"
|
r"
|
||||||
mod std { pub mod fmt { pub trait Display {} } }
|
mod std { pub mod fmt { pub trait Display {} } }
|
||||||
use std::fmt::{self, Display};
|
use std::fmt::{Display, self};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
fmt;
|
fmt;
|
||||||
|
|
|
@ -19,14 +19,20 @@ pub(crate) fn split_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
|
||||||
|
|
||||||
let use_tree = path.top_path().syntax().ancestors().find_map(ast::UseTree::cast)?;
|
let use_tree = path.top_path().syntax().ancestors().find_map(ast::UseTree::cast)?;
|
||||||
|
|
||||||
let new_tree = use_tree.split_prefix(&path);
|
let has_errors = use_tree
|
||||||
if new_tree == use_tree {
|
.syntax()
|
||||||
|
.descendants_with_tokens()
|
||||||
|
.any(|it| it.kind() == syntax::SyntaxKind::ERROR);
|
||||||
|
let last_segment = use_tree.path().and_then(|it| it.segment());
|
||||||
|
if has_errors || last_segment.is_none() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let target = colon_colon.text_range();
|
let target = colon_colon.text_range();
|
||||||
acc.add(AssistId("split_import", AssistKind::RefactorRewrite), "Split import", target, |edit| {
|
acc.add(AssistId("split_import", AssistKind::RefactorRewrite), "Split import", target, |edit| {
|
||||||
edit.replace_ast(use_tree, new_tree);
|
let use_tree = edit.make_mut(use_tree.clone());
|
||||||
|
let path = edit.make_mut(path);
|
||||||
|
use_tree.split_prefix(&path);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -463,7 +463,7 @@ fn merge_groups_full() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn merge_groups_long_full() {
|
fn merge_groups_long_full() {
|
||||||
check_crate("std::foo::bar::Baz", r"use std::foo::bar::Qux;", r"use std::foo::bar::{Baz, Qux};")
|
check_crate("std::foo::bar::Baz", r"use std::foo::bar::Qux;", r"use std::foo::bar::{Qux, Baz};")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -471,7 +471,7 @@ fn merge_groups_long_last() {
|
||||||
check_module(
|
check_module(
|
||||||
"std::foo::bar::Baz",
|
"std::foo::bar::Baz",
|
||||||
r"use std::foo::bar::Qux;",
|
r"use std::foo::bar::Qux;",
|
||||||
r"use std::foo::bar::{Baz, Qux};",
|
r"use std::foo::bar::{Qux, Baz};",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,7 +480,7 @@ fn merge_groups_long_full_list() {
|
||||||
check_crate(
|
check_crate(
|
||||||
"std::foo::bar::Baz",
|
"std::foo::bar::Baz",
|
||||||
r"use std::foo::bar::{Qux, Quux};",
|
r"use std::foo::bar::{Qux, Quux};",
|
||||||
r"use std::foo::bar::{Baz, Quux, Qux};",
|
r"use std::foo::bar::{Qux, Quux, Baz};",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -489,7 +489,7 @@ fn merge_groups_long_last_list() {
|
||||||
check_module(
|
check_module(
|
||||||
"std::foo::bar::Baz",
|
"std::foo::bar::Baz",
|
||||||
r"use std::foo::bar::{Qux, Quux};",
|
r"use std::foo::bar::{Qux, Quux};",
|
||||||
r"use std::foo::bar::{Baz, Quux, Qux};",
|
r"use std::foo::bar::{Qux, Quux, Baz};",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,7 +498,7 @@ fn merge_groups_long_full_nested() {
|
||||||
check_crate(
|
check_crate(
|
||||||
"std::foo::bar::Baz",
|
"std::foo::bar::Baz",
|
||||||
r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
|
r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
|
||||||
r"use std::foo::bar::{Baz, Qux, quux::{Fez, Fizz}};",
|
r"use std::foo::bar::{Qux, quux::{Fez, Fizz}, Baz};",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,7 +517,7 @@ fn merge_groups_full_nested_deep() {
|
||||||
check_crate(
|
check_crate(
|
||||||
"std::foo::bar::quux::Baz",
|
"std::foo::bar::quux::Baz",
|
||||||
r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
|
r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
|
||||||
r"use std::foo::bar::{Qux, quux::{Baz, Fez, Fizz}};",
|
r"use std::foo::bar::{Qux, quux::{Fez, Fizz, Baz}};",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -526,7 +526,7 @@ fn merge_groups_full_nested_long() {
|
||||||
check_crate(
|
check_crate(
|
||||||
"std::foo::bar::Baz",
|
"std::foo::bar::Baz",
|
||||||
r"use std::{foo::bar::Qux};",
|
r"use std::{foo::bar::Qux};",
|
||||||
r"use std::{foo::bar::{Baz, Qux}};",
|
r"use std::{foo::bar::{Qux, Baz}};",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,7 +535,7 @@ fn merge_groups_last_nested_long() {
|
||||||
check_crate(
|
check_crate(
|
||||||
"std::foo::bar::Baz",
|
"std::foo::bar::Baz",
|
||||||
r"use std::{foo::bar::Qux};",
|
r"use std::{foo::bar::Qux};",
|
||||||
r"use std::{foo::bar::{Baz, Qux}};",
|
r"use std::{foo::bar::{Qux, Baz}};",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -600,7 +600,7 @@ fn merge_mod_into_glob() {
|
||||||
check_with_config(
|
check_with_config(
|
||||||
"token::TokenKind",
|
"token::TokenKind",
|
||||||
r"use token::TokenKind::*;",
|
r"use token::TokenKind::*;",
|
||||||
r"use token::TokenKind::{*, self};",
|
r"use token::TokenKind::{self, *};",
|
||||||
&InsertUseConfig {
|
&InsertUseConfig {
|
||||||
granularity: ImportGranularity::Crate,
|
granularity: ImportGranularity::Crate,
|
||||||
enforce_granularity: true,
|
enforce_granularity: true,
|
||||||
|
@ -618,7 +618,7 @@ fn merge_self_glob() {
|
||||||
check_with_config(
|
check_with_config(
|
||||||
"self",
|
"self",
|
||||||
r"use self::*;",
|
r"use self::*;",
|
||||||
r"use self::{*, self};",
|
r"use self::{self, *};",
|
||||||
&InsertUseConfig {
|
&InsertUseConfig {
|
||||||
granularity: ImportGranularity::Crate,
|
granularity: ImportGranularity::Crate,
|
||||||
enforce_granularity: true,
|
enforce_granularity: true,
|
||||||
|
@ -637,7 +637,7 @@ fn merge_glob() {
|
||||||
r"
|
r"
|
||||||
use syntax::{SyntaxKind::*};",
|
use syntax::{SyntaxKind::*};",
|
||||||
r"
|
r"
|
||||||
use syntax::{SyntaxKind::{*, self}};",
|
use syntax::{SyntaxKind::{self, *}};",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,10 +44,10 @@ pub fn try_merge_imports(
|
||||||
}
|
}
|
||||||
|
|
||||||
let lhs = lhs.clone_subtree().clone_for_update();
|
let lhs = lhs.clone_subtree().clone_for_update();
|
||||||
|
let rhs = rhs.clone_subtree().clone_for_update();
|
||||||
let lhs_tree = lhs.use_tree()?;
|
let lhs_tree = lhs.use_tree()?;
|
||||||
let rhs_tree = rhs.use_tree()?;
|
let rhs_tree = rhs.use_tree()?;
|
||||||
let merged = try_merge_trees(&lhs_tree, &rhs_tree, merge_behavior)?;
|
try_merge_trees_mut(&lhs_tree, &rhs_tree, merge_behavior)?;
|
||||||
ted::replace(lhs_tree.syntax(), merged.syntax());
|
|
||||||
Some(lhs)
|
Some(lhs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,57 +56,49 @@ pub fn try_merge_trees(
|
||||||
rhs: &ast::UseTree,
|
rhs: &ast::UseTree,
|
||||||
merge: MergeBehavior,
|
merge: MergeBehavior,
|
||||||
) -> Option<ast::UseTree> {
|
) -> Option<ast::UseTree> {
|
||||||
|
let lhs = lhs.clone_subtree().clone_for_update();
|
||||||
|
let rhs = rhs.clone_subtree().clone_for_update();
|
||||||
|
try_merge_trees_mut(&lhs, &rhs, merge)?;
|
||||||
|
Some(lhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_merge_trees_mut(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior) -> Option<()> {
|
||||||
let lhs_path = lhs.path()?;
|
let lhs_path = lhs.path()?;
|
||||||
let rhs_path = rhs.path()?;
|
let rhs_path = rhs.path()?;
|
||||||
|
|
||||||
let (lhs_prefix, rhs_prefix) = common_prefix(&lhs_path, &rhs_path)?;
|
let (lhs_prefix, rhs_prefix) = common_prefix(&lhs_path, &rhs_path)?;
|
||||||
let (lhs, rhs) = if lhs.is_simple_path()
|
if !(lhs.is_simple_path()
|
||||||
&& rhs.is_simple_path()
|
&& rhs.is_simple_path()
|
||||||
&& lhs_path == lhs_prefix
|
&& lhs_path == lhs_prefix
|
||||||
&& rhs_path == rhs_prefix
|
&& rhs_path == rhs_prefix)
|
||||||
{
|
{
|
||||||
(lhs.clone(), rhs.clone())
|
lhs.split_prefix(&lhs_prefix);
|
||||||
} else {
|
rhs.split_prefix(&rhs_prefix);
|
||||||
(lhs.split_prefix(&lhs_prefix), rhs.split_prefix(&rhs_prefix))
|
}
|
||||||
};
|
recursive_merge(&lhs, &rhs, merge)
|
||||||
recursive_merge(&lhs, &rhs, merge).map(|it| it.clone_for_update())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recursively "zips" together lhs and rhs.
|
/// Recursively merges rhs to lhs
|
||||||
fn recursive_merge(
|
#[must_use]
|
||||||
lhs: &ast::UseTree,
|
fn recursive_merge(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior) -> Option<()> {
|
||||||
rhs: &ast::UseTree,
|
let mut use_trees: Vec<ast::UseTree> = lhs
|
||||||
merge: MergeBehavior,
|
|
||||||
) -> Option<ast::UseTree> {
|
|
||||||
let mut use_trees = lhs
|
|
||||||
.use_tree_list()
|
.use_tree_list()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|list| list.use_trees())
|
.flat_map(|list| list.use_trees())
|
||||||
// We use Option here to early return from this function(this is not the
|
// We use Option here to early return from this function(this is not the
|
||||||
// same as a `filter` op).
|
// same as a `filter` op).
|
||||||
.map(|tree| match merge.is_tree_allowed(&tree) {
|
.map(|tree| merge.is_tree_allowed(&tree).then(|| tree))
|
||||||
true => Some(tree),
|
.collect::<Option<_>>()?;
|
||||||
false => None,
|
|
||||||
})
|
|
||||||
.collect::<Option<Vec<_>>>()?;
|
|
||||||
use_trees.sort_unstable_by(|a, b| path_cmp_for_sort(a.path(), b.path()));
|
use_trees.sort_unstable_by(|a, b| path_cmp_for_sort(a.path(), b.path()));
|
||||||
for rhs_t in rhs.use_tree_list().into_iter().flat_map(|list| list.use_trees()) {
|
for rhs_t in rhs.use_tree_list().into_iter().flat_map(|list| list.use_trees()) {
|
||||||
if !merge.is_tree_allowed(&rhs_t) {
|
if !merge.is_tree_allowed(&rhs_t) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let rhs_path = rhs_t.path();
|
let rhs_path = rhs_t.path();
|
||||||
match use_trees.binary_search_by(|lhs_t| {
|
|
||||||
let (lhs_t, rhs_t) = match lhs_t
|
|
||||||
.path()
|
|
||||||
.zip(rhs_path.clone())
|
|
||||||
.and_then(|(lhs, rhs)| common_prefix(&lhs, &rhs))
|
|
||||||
{
|
|
||||||
Some((lhs_p, rhs_p)) => (lhs_t.split_prefix(&lhs_p), rhs_t.split_prefix(&rhs_p)),
|
|
||||||
None => (lhs_t.clone(), rhs_t.clone()),
|
|
||||||
};
|
|
||||||
|
|
||||||
path_cmp_bin_search(lhs_t.path(), rhs_t.path())
|
match use_trees
|
||||||
}) {
|
.binary_search_by(|lhs_t| path_cmp_bin_search(lhs_t.path(), rhs_path.as_ref()))
|
||||||
|
{
|
||||||
Ok(idx) => {
|
Ok(idx) => {
|
||||||
let lhs_t = &mut use_trees[idx];
|
let lhs_t = &mut use_trees[idx];
|
||||||
let lhs_path = lhs_t.path()?;
|
let lhs_path = lhs_t.path()?;
|
||||||
|
@ -128,6 +120,7 @@ fn recursive_merge(
|
||||||
match (tree_contains_self(lhs_t), tree_contains_self(&rhs_t)) {
|
match (tree_contains_self(lhs_t), tree_contains_self(&rhs_t)) {
|
||||||
(true, false) => continue,
|
(true, false) => continue,
|
||||||
(false, true) => {
|
(false, true) => {
|
||||||
|
ted::replace(lhs_t.syntax(), rhs_t.syntax());
|
||||||
*lhs_t = rhs_t;
|
*lhs_t = rhs_t;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -142,25 +135,27 @@ fn recursive_merge(
|
||||||
if lhs_t.star_token().is_some() || rhs_t.star_token().is_some() {
|
if lhs_t.star_token().is_some() || rhs_t.star_token().is_some() {
|
||||||
if tree_is_self(lhs_t) || tree_is_self(&rhs_t) {
|
if tree_is_self(lhs_t) || tree_is_self(&rhs_t) {
|
||||||
cov_mark::hit!(merge_self_glob);
|
cov_mark::hit!(merge_self_glob);
|
||||||
*lhs_t = make::use_tree(
|
let self_tree = make::use_tree(
|
||||||
make::path_unqualified(make::path_segment_self()),
|
make::path_unqualified(make::path_segment_self()),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
false,
|
false,
|
||||||
);
|
)
|
||||||
use_trees.insert(idx, make::use_tree_glob());
|
.clone_for_update();
|
||||||
|
ted::replace(lhs_t.syntax(), self_tree.syntax());
|
||||||
|
*lhs_t = self_tree;
|
||||||
|
let glob = make::use_tree_glob().clone_for_update();
|
||||||
|
use_trees.insert(idx, glob.clone());
|
||||||
|
lhs.get_or_create_use_tree_list().add_use_tree(glob);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else if lhs_t.use_tree_list().is_none() && rhs_t.use_tree_list().is_none() {
|
} else if lhs_t.use_tree_list().is_none() && rhs_t.use_tree_list().is_none() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let lhs = lhs_t.split_prefix(&lhs_prefix);
|
lhs_t.split_prefix(&lhs_prefix);
|
||||||
let rhs = rhs_t.split_prefix(&rhs_prefix);
|
rhs_t.split_prefix(&rhs_prefix);
|
||||||
match recursive_merge(&lhs, &rhs, merge) {
|
recursive_merge(&lhs_t, &rhs_t, merge)?;
|
||||||
Some(use_tree) => use_trees[idx] = use_tree,
|
|
||||||
None => return None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(_)
|
Err(_)
|
||||||
if merge == MergeBehavior::Module
|
if merge == MergeBehavior::Module
|
||||||
|
@ -170,16 +165,12 @@ fn recursive_merge(
|
||||||
return None
|
return None
|
||||||
}
|
}
|
||||||
Err(idx) => {
|
Err(idx) => {
|
||||||
use_trees.insert(idx, rhs_t);
|
use_trees.insert(idx, rhs_t.clone());
|
||||||
|
lhs.get_or_create_use_tree_list().add_use_tree(rhs_t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some(())
|
||||||
let lhs = lhs.clone_subtree().clone_for_update();
|
|
||||||
if let Some(old) = lhs.use_tree_list() {
|
|
||||||
ted::replace(old.syntax(), make::use_tree_list(use_trees).syntax().clone_for_update());
|
|
||||||
}
|
|
||||||
ast::UseTree::cast(lhs.syntax().clone_subtree())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Traverses both paths until they differ, returning the common prefix of both.
|
/// Traverses both paths until they differ, returning the common prefix of both.
|
||||||
|
@ -224,11 +215,9 @@ fn path_cmp_for_sort(a: Option<ast::Path>, b: Option<ast::Path>) -> Ordering {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Path comparison func for binary searching for merging.
|
/// Path comparison func for binary searching for merging.
|
||||||
fn path_cmp_bin_search(lhs: Option<ast::Path>, rhs: Option<ast::Path>) -> Ordering {
|
fn path_cmp_bin_search(lhs: Option<ast::Path>, rhs: Option<&ast::Path>) -> Ordering {
|
||||||
match (
|
match (lhs.as_ref().and_then(ast::Path::first_segment), rhs.and_then(ast::Path::first_segment))
|
||||||
lhs.as_ref().and_then(ast::Path::first_segment),
|
{
|
||||||
rhs.as_ref().and_then(ast::Path::first_segment),
|
|
||||||
) {
|
|
||||||
(None, None) => Ordering::Equal,
|
(None, None) => Ordering::Equal,
|
||||||
(None, Some(_)) => Ordering::Less,
|
(None, Some(_)) => Ordering::Less,
|
||||||
(Some(_), None) => Ordering::Greater,
|
(Some(_), None) => Ordering::Greater,
|
||||||
|
|
|
@ -4,48 +4,10 @@
|
||||||
use std::{fmt, iter, ops};
|
use std::{fmt, iter, ops};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
algo,
|
|
||||||
ast::{self, make, AstNode},
|
ast::{self, make, AstNode},
|
||||||
ted, AstToken, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken,
|
ted, AstToken, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl ast::UseTree {
|
|
||||||
/// Splits off the given prefix, making it the path component of the use tree, appending the rest of the path to all UseTreeList items.
|
|
||||||
#[must_use]
|
|
||||||
pub fn split_prefix(&self, prefix: &ast::Path) -> ast::UseTree {
|
|
||||||
let suffix = if self.path().as_ref() == Some(prefix) && self.use_tree_list().is_none() {
|
|
||||||
make::path_unqualified(make::path_segment_self())
|
|
||||||
} else {
|
|
||||||
match split_path_prefix(prefix) {
|
|
||||||
Some(it) => it,
|
|
||||||
None => return self.clone(),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let use_tree = make::use_tree(
|
|
||||||
suffix,
|
|
||||||
self.use_tree_list(),
|
|
||||||
self.rename(),
|
|
||||||
self.star_token().is_some(),
|
|
||||||
);
|
|
||||||
let nested = make::use_tree_list(iter::once(use_tree));
|
|
||||||
return make::use_tree(prefix.clone(), Some(nested), None, false);
|
|
||||||
|
|
||||||
fn split_path_prefix(prefix: &ast::Path) -> Option<ast::Path> {
|
|
||||||
let parent = prefix.parent_path()?;
|
|
||||||
let segment = parent.segment()?;
|
|
||||||
if algo::has_errors(segment.syntax()) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let mut res = make::path_unqualified(segment);
|
|
||||||
for p in iter::successors(parent.parent_path(), |it| it.parent_path()) {
|
|
||||||
res = make::path_qualified(res, p.segment()?);
|
|
||||||
}
|
|
||||||
Some(res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct IndentLevel(pub u8);
|
pub struct IndentLevel(pub u8);
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
//! Structural editing for ast.
|
//! Structural editing for ast.
|
||||||
|
|
||||||
use std::iter::empty;
|
use std::iter::{empty, successors};
|
||||||
|
|
||||||
use parser::{SyntaxKind, T};
|
use parser::{SyntaxKind, T};
|
||||||
use rowan::SyntaxElement;
|
use rowan::SyntaxElement;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
algo::neighbor,
|
algo::{self, neighbor},
|
||||||
ast::{self, edit::IndentLevel, make, HasGenericParams},
|
ast::{self, edit::IndentLevel, make, HasGenericParams},
|
||||||
ted::{self, Position},
|
ted::{self, Position},
|
||||||
AstNode, AstToken, Direction,
|
AstNode, AstToken, Direction,
|
||||||
|
@ -282,6 +282,78 @@ impl ast::UseTree {
|
||||||
}
|
}
|
||||||
ted::remove(self.syntax());
|
ted::remove(self.syntax());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_or_create_use_tree_list(&self) -> ast::UseTreeList {
|
||||||
|
match self.use_tree_list() {
|
||||||
|
Some(it) => it,
|
||||||
|
None => {
|
||||||
|
let position = Position::last_child_of(self.syntax());
|
||||||
|
let use_tree_list = make::use_tree_list(empty()).clone_for_update();
|
||||||
|
let mut elements = Vec::with_capacity(2);
|
||||||
|
if self.coloncolon_token().is_none() {
|
||||||
|
elements.push(make::token(T![::]).into());
|
||||||
|
}
|
||||||
|
elements.push(use_tree_list.syntax().clone().into());
|
||||||
|
ted::insert_all_raw(position, elements);
|
||||||
|
use_tree_list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Splits off the given prefix, making it the path component of the use tree,
|
||||||
|
/// appending the rest of the path to all UseTreeList items.
|
||||||
|
pub fn split_prefix(&self, prefix: &ast::Path) {
|
||||||
|
debug_assert_eq!(self.path(), Some(prefix.top_path()));
|
||||||
|
let path = self.path().unwrap();
|
||||||
|
if &path == prefix && self.use_tree_list().is_none() {
|
||||||
|
let self_suffix = make::path_unqualified(make::path_segment_self()).clone_for_update();
|
||||||
|
ted::replace(path.syntax(), self_suffix.syntax());
|
||||||
|
} else if split_path_prefix(prefix).is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let subtree = self.clone_subtree().clone_for_update();
|
||||||
|
ted::remove_all_iter(self.syntax().children_with_tokens());
|
||||||
|
ted::insert(Position::first_child_of(self.syntax()), prefix.syntax());
|
||||||
|
self.get_or_create_use_tree_list().add_use_tree(subtree);
|
||||||
|
|
||||||
|
fn split_path_prefix(prefix: &ast::Path) -> Option<()> {
|
||||||
|
let parent = prefix.parent_path()?;
|
||||||
|
let segment = parent.segment()?;
|
||||||
|
if algo::has_errors(segment.syntax()) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
for p in successors(parent.parent_path(), |it| it.parent_path()) {
|
||||||
|
p.segment()?;
|
||||||
|
}
|
||||||
|
prefix.parent_path().and_then(|p| p.coloncolon_token()).map(ted::remove);
|
||||||
|
ted::remove(prefix.syntax());
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ast::UseTreeList {
|
||||||
|
pub fn add_use_tree(&self, use_tree: ast::UseTree) {
|
||||||
|
let (position, elements) = match self.use_trees().last() {
|
||||||
|
Some(last_tree) => (
|
||||||
|
Position::after(last_tree.syntax()),
|
||||||
|
vec![
|
||||||
|
make::token(T![,]).into(),
|
||||||
|
make::tokens::single_space().into(),
|
||||||
|
use_tree.syntax.into(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
None => {
|
||||||
|
let position = match self.l_curly_token() {
|
||||||
|
Some(l_curly) => Position::after(l_curly),
|
||||||
|
None => Position::last_child_of(self.syntax()),
|
||||||
|
};
|
||||||
|
(position, vec![use_tree.syntax.into()])
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ted::insert_all_raw(position, elements);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ast::Use {
|
impl ast::Use {
|
||||||
|
|
Loading…
Reference in a new issue