aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-04-20 15:34:01 +0100
committerAleksey Kladov <[email protected]>2020-04-20 15:34:01 +0100
commit8a04372fec5f26a0650395a1e420fea062b3a7ab (patch)
treeede61469d8f4e180f0cfa7cbe00d889737d45551 /crates
parent90f837829d4f2c1054751de2de695ba1c0b8ae5c (diff)
Fix panic in split_imports assist
The fix is admittedly quit literally just papering over. Long-term, I see two more principled approaches: * we switch to a fully tree-based impl, without parse . to_string step; with this approach, there shouldn't be any panics. The results might be nonsensical, but so was the original input. * we preserve the invariant that re-parsing constructed node is an identity, and make all the `make_xxx` method return an `Option`. closes #4044
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/src/handlers/split_import.rs7
-rw-r--r--crates/ra_syntax/src/algo.rs8
-rw-r--r--crates/ra_syntax/src/ast/edit.rs6
3 files changed, 17 insertions, 4 deletions
diff --git a/crates/ra_assists/src/handlers/split_import.rs b/crates/ra_assists/src/handlers/split_import.rs
index d9244f22d..f25826796 100644
--- a/crates/ra_assists/src/handlers/split_import.rs
+++ b/crates/ra_assists/src/handlers/split_import.rs
@@ -37,7 +37,7 @@ pub(crate) fn split_import(ctx: AssistCtx) -> Option<Assist> {
37 37
38#[cfg(test)] 38#[cfg(test)]
39mod tests { 39mod tests {
40 use crate::helpers::{check_assist, check_assist_target}; 40 use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target};
41 41
42 use super::*; 42 use super::*;
43 43
@@ -63,4 +63,9 @@ mod tests {
63 fn split_import_target() { 63 fn split_import_target() {
64 check_assist_target(split_import, "use crate::<|>db::{RootDatabase, FileSymbol}", "::"); 64 check_assist_target(split_import, "use crate::<|>db::{RootDatabase, FileSymbol}", "::");
65 } 65 }
66
67 #[test]
68 fn issue4044() {
69 check_assist_not_applicable(split_import, "use crate::<|>:::self;")
70 }
66} 71}
diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs
index ea41bf85d..06df8495c 100644
--- a/crates/ra_syntax/src/algo.rs
+++ b/crates/ra_syntax/src/algo.rs
@@ -10,8 +10,8 @@ use ra_text_edit::TextEditBuilder;
10use rustc_hash::FxHashMap; 10use rustc_hash::FxHashMap;
11 11
12use crate::{ 12use crate::{
13 AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxNodePtr, SyntaxToken, 13 AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxNodePtr,
14 TextRange, TextUnit, 14 SyntaxToken, TextRange, TextUnit,
15}; 15};
16 16
17/// Returns ancestors of the node at the offset, sorted by length. This should 17/// Returns ancestors of the node at the offset, sorted by length. This should
@@ -90,6 +90,10 @@ pub fn neighbor<T: AstNode>(me: &T, direction: Direction) -> Option<T> {
90 me.syntax().siblings(direction).skip(1).find_map(T::cast) 90 me.syntax().siblings(direction).skip(1).find_map(T::cast)
91} 91}
92 92
93pub fn has_errors(node: &SyntaxNode) -> bool {
94 node.children().any(|it| it.kind() == SyntaxKind::ERROR)
95}
96
93#[derive(Debug, PartialEq, Eq, Clone, Copy)] 97#[derive(Debug, PartialEq, Eq, Clone, Copy)]
94pub enum InsertPosition<T> { 98pub enum InsertPosition<T> {
95 First, 99 First,
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs
index 9e5411ee5..26e4576ff 100644
--- a/crates/ra_syntax/src/ast/edit.rs
+++ b/crates/ra_syntax/src/ast/edit.rs
@@ -307,7 +307,11 @@ impl ast::UseTree {
307 307
308 fn split_path_prefix(prefix: &ast::Path) -> Option<ast::Path> { 308 fn split_path_prefix(prefix: &ast::Path) -> Option<ast::Path> {
309 let parent = prefix.parent_path()?; 309 let parent = prefix.parent_path()?;
310 let mut res = make::path_unqualified(parent.segment()?); 310 let segment = parent.segment()?;
311 if algo::has_errors(segment.syntax()) {
312 return None;
313 }
314 let mut res = make::path_unqualified(segment);
311 for p in iter::successors(parent.parent_path(), |it| it.parent_path()) { 315 for p in iter::successors(parent.parent_path(), |it| it.parent_path()) {
312 res = make::path_qualified(res, p.segment()?); 316 res = make::path_qualified(res, p.segment()?);
313 } 317 }