diff options
Diffstat (limited to 'crates/ide_assists')
10 files changed, 60 insertions, 71 deletions
diff --git a/crates/ide_assists/src/handlers/add_turbo_fish.rs b/crates/ide_assists/src/handlers/add_turbo_fish.rs index ee879c151..436767895 100644 --- a/crates/ide_assists/src/handlers/add_turbo_fish.rs +++ b/crates/ide_assists/src/handlers/add_turbo_fish.rs | |||
@@ -38,7 +38,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<( | |||
38 | cov_mark::hit!(add_turbo_fish_one_fish_is_enough); | 38 | cov_mark::hit!(add_turbo_fish_one_fish_is_enough); |
39 | return None; | 39 | return None; |
40 | } | 40 | } |
41 | let name_ref = ast::NameRef::cast(ident.parent())?; | 41 | let name_ref = ast::NameRef::cast(ident.parent()?)?; |
42 | let def = match NameRefClass::classify(&ctx.sema, &name_ref)? { | 42 | let def = match NameRefClass::classify(&ctx.sema, &name_ref)? { |
43 | NameRefClass::Definition(def) => def, | 43 | NameRefClass::Definition(def) => def, |
44 | NameRefClass::ExternCrate(_) | NameRefClass::FieldShorthand { .. } => return None, | 44 | NameRefClass::ExternCrate(_) | NameRefClass::FieldShorthand { .. } => return None, |
diff --git a/crates/ide_assists/src/handlers/change_visibility.rs b/crates/ide_assists/src/handlers/change_visibility.rs index ec99a5505..d7e39b2ae 100644 --- a/crates/ide_assists/src/handlers/change_visibility.rs +++ b/crates/ide_assists/src/handlers/change_visibility.rs | |||
@@ -41,7 +41,7 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
41 | }); | 41 | }); |
42 | 42 | ||
43 | let (offset, target) = if let Some(keyword) = item_keyword { | 43 | let (offset, target) = if let Some(keyword) = item_keyword { |
44 | let parent = keyword.parent(); | 44 | let parent = keyword.parent()?; |
45 | let def_kws = vec![CONST, STATIC, TYPE_ALIAS, FN, MODULE, STRUCT, ENUM, TRAIT]; | 45 | let def_kws = vec![CONST, STATIC, TYPE_ALIAS, FN, MODULE, STRUCT, ENUM, TRAIT]; |
46 | // Parent is not a definition, can't add visibility | 46 | // Parent is not a definition, can't add visibility |
47 | if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) { | 47 | if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) { |
diff --git a/crates/ide_assists/src/handlers/expand_glob_import.rs b/crates/ide_assists/src/handlers/expand_glob_import.rs index 5fe617ba4..5b540df5c 100644 --- a/crates/ide_assists/src/handlers/expand_glob_import.rs +++ b/crates/ide_assists/src/handlers/expand_glob_import.rs | |||
@@ -48,7 +48,7 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Opti | |||
48 | _ => return None, | 48 | _ => return None, |
49 | }; | 49 | }; |
50 | 50 | ||
51 | let current_scope = ctx.sema.scope(&star.parent()); | 51 | let current_scope = ctx.sema.scope(&star.parent()?); |
52 | let current_module = current_scope.module()?; | 52 | let current_module = current_scope.module()?; |
53 | 53 | ||
54 | let refs_in_target = find_refs_in_mod(ctx, target_module, Some(current_module))?; | 54 | let refs_in_target = find_refs_in_mod(ctx, target_module, Some(current_module))?; |
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs index dd4501709..5fdc8bf38 100644 --- a/crates/ide_assists/src/handlers/extract_function.rs +++ b/crates/ide_assists/src/handlers/extract_function.rs | |||
@@ -16,7 +16,6 @@ use syntax::{ | |||
16 | edit::{AstNodeEdit, IndentLevel}, | 16 | edit::{AstNodeEdit, IndentLevel}, |
17 | AstNode, | 17 | AstNode, |
18 | }, | 18 | }, |
19 | SyntaxElement, | ||
20 | SyntaxKind::{self, BLOCK_EXPR, BREAK_EXPR, COMMENT, PATH_EXPR, RETURN_EXPR}, | 19 | SyntaxKind::{self, BLOCK_EXPR, BREAK_EXPR, COMMENT, PATH_EXPR, RETURN_EXPR}, |
21 | SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T, | 20 | SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T, |
22 | }; | 21 | }; |
@@ -62,7 +61,10 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
62 | return None; | 61 | return None; |
63 | } | 62 | } |
64 | 63 | ||
65 | let node = element_to_node(node); | 64 | let node = match node { |
65 | syntax::NodeOrToken::Node(n) => n, | ||
66 | syntax::NodeOrToken::Token(t) => t.parent()?, | ||
67 | }; | ||
66 | 68 | ||
67 | let body = extraction_target(&node, ctx.frange.range)?; | 69 | let body = extraction_target(&node, ctx.frange.range)?; |
68 | 70 | ||
@@ -560,14 +562,6 @@ impl HasTokenAtOffset for FunctionBody { | |||
560 | } | 562 | } |
561 | } | 563 | } |
562 | 564 | ||
563 | /// node or token's parent | ||
564 | fn element_to_node(node: SyntaxElement) -> SyntaxNode { | ||
565 | match node { | ||
566 | syntax::NodeOrToken::Node(n) => n, | ||
567 | syntax::NodeOrToken::Token(t) => t.parent(), | ||
568 | } | ||
569 | } | ||
570 | |||
571 | /// Try to guess what user wants to extract | 565 | /// Try to guess what user wants to extract |
572 | /// | 566 | /// |
573 | /// We have basically have two cases: | 567 | /// We have basically have two cases: |
@@ -1246,7 +1240,7 @@ fn make_body( | |||
1246 | }) | 1240 | }) |
1247 | } | 1241 | } |
1248 | FlowHandler::If { .. } => { | 1242 | FlowHandler::If { .. } => { |
1249 | let lit_false = ast::Literal::cast(make::tokens::literal("false").parent()).unwrap(); | 1243 | let lit_false = make::expr_literal("false"); |
1250 | with_tail_expr(block, lit_false.into()) | 1244 | with_tail_expr(block, lit_false.into()) |
1251 | } | 1245 | } |
1252 | FlowHandler::IfOption { .. } => { | 1246 | FlowHandler::IfOption { .. } => { |
@@ -1420,9 +1414,7 @@ fn update_external_control_flow(handler: &FlowHandler, syntax: &SyntaxNode) -> S | |||
1420 | fn make_rewritten_flow(handler: &FlowHandler, arg_expr: Option<ast::Expr>) -> Option<ast::Expr> { | 1414 | fn make_rewritten_flow(handler: &FlowHandler, arg_expr: Option<ast::Expr>) -> Option<ast::Expr> { |
1421 | let value = match handler { | 1415 | let value = match handler { |
1422 | FlowHandler::None | FlowHandler::Try { .. } => return None, | 1416 | FlowHandler::None | FlowHandler::Try { .. } => return None, |
1423 | FlowHandler::If { .. } => { | 1417 | FlowHandler::If { .. } => make::expr_literal("true").into(), |
1424 | ast::Literal::cast(make::tokens::literal("true").parent()).unwrap().into() | ||
1425 | } | ||
1426 | FlowHandler::IfOption { .. } => { | 1418 | FlowHandler::IfOption { .. } => { |
1427 | let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new())); | 1419 | let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new())); |
1428 | let args = make::arg_list(iter::once(expr)); | 1420 | let args = make::arg_list(iter::once(expr)); |
diff --git a/crates/ide_assists/src/handlers/flip_trait_bound.rs b/crates/ide_assists/src/handlers/flip_trait_bound.rs index d419d263e..a868aa43d 100644 --- a/crates/ide_assists/src/handlers/flip_trait_bound.rs +++ b/crates/ide_assists/src/handlers/flip_trait_bound.rs | |||
@@ -23,7 +23,7 @@ pub(crate) fn flip_trait_bound(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
23 | let plus = ctx.find_token_syntax_at_offset(T![+])?; | 23 | let plus = ctx.find_token_syntax_at_offset(T![+])?; |
24 | 24 | ||
25 | // Make sure we're in a `TypeBoundList` | 25 | // Make sure we're in a `TypeBoundList` |
26 | if ast::TypeBoundList::cast(plus.parent()).is_none() { | 26 | if ast::TypeBoundList::cast(plus.parent()?).is_none() { |
27 | return None; | 27 | return None; |
28 | } | 28 | } |
29 | 29 | ||
diff --git a/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs b/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs index aa7072f25..b8834d283 100644 --- a/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs +++ b/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use hir::{known, HasSource, Name}; | 1 | use hir::{known, HasSource, Name}; |
2 | use syntax::{ | 2 | use syntax::{ |
3 | ast::{self, NameOwner}, | 3 | ast::{self, NameOwner}, |
4 | AstNode, TextRange, | 4 | AstNode, |
5 | }; | 5 | }; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
@@ -51,12 +51,19 @@ pub(crate) fn generate_is_empty_from_len(acc: &mut Assists, ctx: &AssistContext) | |||
51 | } | 51 | } |
52 | 52 | ||
53 | let impl_ = fn_node.syntax().ancestors().find_map(ast::Impl::cast)?; | 53 | let impl_ = fn_node.syntax().ancestors().find_map(ast::Impl::cast)?; |
54 | let len_fn = get_impl_method(ctx, &impl_, &known::len)?; | ||
55 | if !len_fn.ret_type(ctx.sema.db).is_usize() { | ||
56 | cov_mark::hit!(len_fn_different_return_type); | ||
57 | return None; | ||
58 | } | ||
59 | |||
54 | if get_impl_method(ctx, &impl_, &known::is_empty).is_some() { | 60 | if get_impl_method(ctx, &impl_, &known::is_empty).is_some() { |
55 | cov_mark::hit!(is_empty_already_implemented); | 61 | cov_mark::hit!(is_empty_already_implemented); |
56 | return None; | 62 | return None; |
57 | } | 63 | } |
58 | 64 | ||
59 | let range = get_text_range_of_len_function(ctx, &impl_)?; | 65 | let node = len_fn.source(ctx.sema.db)?; |
66 | let range = node.syntax().value.text_range(); | ||
60 | 67 | ||
61 | acc.add( | 68 | acc.add( |
62 | AssistId("generate_is_empty_from_len", AssistKind::Generate), | 69 | AssistId("generate_is_empty_from_len", AssistKind::Generate), |
@@ -89,13 +96,6 @@ fn get_impl_method( | |||
89 | ty.iterate_method_candidates(db, krate, &traits_in_scope, Some(fn_name), |_, func| Some(func)) | 96 | ty.iterate_method_candidates(db, krate, &traits_in_scope, Some(fn_name), |_, func| Some(func)) |
90 | } | 97 | } |
91 | 98 | ||
92 | fn get_text_range_of_len_function(ctx: &AssistContext, impl_: &ast::Impl) -> Option<TextRange> { | ||
93 | let db = ctx.sema.db; | ||
94 | let func = get_impl_method(ctx, impl_, &known::len)?; | ||
95 | let node = func.source(db)?; | ||
96 | Some(node.syntax().value.text_range()) | ||
97 | } | ||
98 | |||
99 | #[cfg(test)] | 99 | #[cfg(test)] |
100 | mod tests { | 100 | mod tests { |
101 | use crate::tests::{check_assist, check_assist_not_applicable}; | 101 | use crate::tests::{check_assist, check_assist_not_applicable}; |
@@ -158,6 +158,23 @@ impl MyStruct { | |||
158 | } | 158 | } |
159 | 159 | ||
160 | #[test] | 160 | #[test] |
161 | fn len_fn_different_return_type() { | ||
162 | cov_mark::check!(len_fn_different_return_type); | ||
163 | check_assist_not_applicable( | ||
164 | generate_is_empty_from_len, | ||
165 | r#" | ||
166 | struct MyStruct { data: Vec<String> } | ||
167 | |||
168 | impl MyStruct { | ||
169 | p$0ub fn len(&self) -> u32 { | ||
170 | self.data.len() | ||
171 | } | ||
172 | } | ||
173 | "#, | ||
174 | ); | ||
175 | } | ||
176 | |||
177 | #[test] | ||
161 | fn generate_is_empty() { | 178 | fn generate_is_empty() { |
162 | check_assist( | 179 | check_assist( |
163 | generate_is_empty_from_len, | 180 | generate_is_empty_from_len, |
diff --git a/crates/ide_assists/src/handlers/invert_if.rs b/crates/ide_assists/src/handlers/invert_if.rs index b131dc205..53612ec3f 100644 --- a/crates/ide_assists/src/handlers/invert_if.rs +++ b/crates/ide_assists/src/handlers/invert_if.rs | |||
@@ -30,7 +30,7 @@ use crate::{ | |||
30 | 30 | ||
31 | pub(crate) fn invert_if(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 31 | pub(crate) fn invert_if(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
32 | let if_keyword = ctx.find_token_syntax_at_offset(T![if])?; | 32 | let if_keyword = ctx.find_token_syntax_at_offset(T![if])?; |
33 | let expr = ast::IfExpr::cast(if_keyword.parent())?; | 33 | let expr = ast::IfExpr::cast(if_keyword.parent()?)?; |
34 | let if_range = if_keyword.text_range(); | 34 | let if_range = if_keyword.text_range(); |
35 | let cursor_in_range = if_range.contains_range(ctx.frange.range); | 35 | let cursor_in_range = if_range.contains_range(ctx.frange.range); |
36 | if !cursor_in_range { | 36 | if !cursor_in_range { |
diff --git a/crates/ide_assists/src/handlers/move_bounds.rs b/crates/ide_assists/src/handlers/move_bounds.rs index cf260c6f8..48efa67ed 100644 --- a/crates/ide_assists/src/handlers/move_bounds.rs +++ b/crates/ide_assists/src/handlers/move_bounds.rs | |||
@@ -1,8 +1,6 @@ | |||
1 | use syntax::{ | 1 | use syntax::{ |
2 | ast::{self, edit::AstNodeEdit, make, AstNode, NameOwner, TypeBoundsOwner}, | 2 | ast::{self, edit_in_place::GenericParamsOwnerEdit, make, AstNode, NameOwner, TypeBoundsOwner}, |
3 | match_ast, | 3 | match_ast, |
4 | SyntaxKind::*, | ||
5 | T, | ||
6 | }; | 4 | }; |
7 | 5 | ||
8 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 6 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
@@ -23,7 +21,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
23 | // } | 21 | // } |
24 | // ``` | 22 | // ``` |
25 | pub(crate) fn move_bounds_to_where_clause(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 23 | pub(crate) fn move_bounds_to_where_clause(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
26 | let type_param_list = ctx.find_node_at_offset::<ast::GenericParamList>()?; | 24 | let type_param_list = ctx.find_node_at_offset::<ast::GenericParamList>()?.clone_for_update(); |
27 | 25 | ||
28 | let mut type_params = type_param_list.type_params(); | 26 | let mut type_params = type_param_list.type_params(); |
29 | if type_params.all(|p| p.type_bound_list().is_none()) { | 27 | if type_params.all(|p| p.type_bound_list().is_none()) { |
@@ -31,23 +29,7 @@ pub(crate) fn move_bounds_to_where_clause(acc: &mut Assists, ctx: &AssistContext | |||
31 | } | 29 | } |
32 | 30 | ||
33 | let parent = type_param_list.syntax().parent()?; | 31 | let parent = type_param_list.syntax().parent()?; |
34 | if parent.children_with_tokens().any(|it| it.kind() == WHERE_CLAUSE) { | 32 | let original_parent_range = parent.text_range(); |
35 | return None; | ||
36 | } | ||
37 | |||
38 | let anchor = match_ast! { | ||
39 | match parent { | ||
40 | ast::Fn(it) => it.body()?.syntax().clone().into(), | ||
41 | ast::Trait(it) => it.assoc_item_list()?.syntax().clone().into(), | ||
42 | ast::Impl(it) => it.assoc_item_list()?.syntax().clone().into(), | ||
43 | ast::Enum(it) => it.variant_list()?.syntax().clone().into(), | ||
44 | ast::Struct(it) => { | ||
45 | it.syntax().children_with_tokens() | ||
46 | .find(|it| it.kind() == RECORD_FIELD_LIST || it.kind() == T![;])? | ||
47 | }, | ||
48 | _ => return None | ||
49 | } | ||
50 | }; | ||
51 | 33 | ||
52 | let target = type_param_list.syntax().text_range(); | 34 | let target = type_param_list.syntax().text_range(); |
53 | acc.add( | 35 | acc.add( |
@@ -55,29 +37,27 @@ pub(crate) fn move_bounds_to_where_clause(acc: &mut Assists, ctx: &AssistContext | |||
55 | "Move to where clause", | 37 | "Move to where clause", |
56 | target, | 38 | target, |
57 | |edit| { | 39 | |edit| { |
58 | let new_params = type_param_list | 40 | let where_clause: ast::WhereClause = match_ast! { |
59 | .type_params() | 41 | match parent { |
60 | .filter(|it| it.type_bound_list().is_some()) | 42 | ast::Fn(it) => it.get_or_create_where_clause(), |
61 | .map(|type_param| { | 43 | // ast::Trait(it) => it.get_or_create_where_clause(), |
62 | let without_bounds = type_param.remove_bounds(); | 44 | ast::Impl(it) => it.get_or_create_where_clause(), |
63 | (type_param, without_bounds) | 45 | // ast::Enum(it) => it.get_or_create_where_clause(), |
64 | }); | 46 | ast::Struct(it) => it.get_or_create_where_clause(), |
65 | 47 | _ => return, | |
66 | let new_type_param_list = type_param_list.replace_descendants(new_params); | 48 | } |
67 | edit.replace_ast(type_param_list.clone(), new_type_param_list); | ||
68 | |||
69 | let where_clause = { | ||
70 | let predicates = type_param_list.type_params().filter_map(build_predicate); | ||
71 | make::where_clause(predicates) | ||
72 | }; | 49 | }; |
73 | 50 | ||
74 | let to_insert = match anchor.prev_sibling_or_token() { | 51 | for type_param in type_param_list.type_params() { |
75 | Some(ref elem) if elem.kind() == WHITESPACE => { | 52 | if let Some(tbl) = type_param.type_bound_list() { |
76 | format!("{} ", where_clause.syntax()) | 53 | if let Some(predicate) = build_predicate(type_param.clone()) { |
54 | where_clause.add_predicate(predicate.clone_for_update()) | ||
55 | } | ||
56 | tbl.remove() | ||
77 | } | 57 | } |
78 | _ => format!(" {}", where_clause.syntax()), | 58 | } |
79 | }; | 59 | |
80 | edit.insert(anchor.text_range().start(), to_insert); | 60 | edit.replace(original_parent_range, parent.to_string()) |
81 | }, | 61 | }, |
82 | ) | 62 | ) |
83 | } | 63 | } |
diff --git a/crates/ide_assists/src/handlers/split_import.rs b/crates/ide_assists/src/handlers/split_import.rs index 9319a4267..446f30544 100644 --- a/crates/ide_assists/src/handlers/split_import.rs +++ b/crates/ide_assists/src/handlers/split_import.rs | |||
@@ -17,7 +17,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
17 | // ``` | 17 | // ``` |
18 | pub(crate) fn split_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 18 | pub(crate) fn split_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
19 | let colon_colon = ctx.find_token_syntax_at_offset(T![::])?; | 19 | let colon_colon = ctx.find_token_syntax_at_offset(T![::])?; |
20 | let path = ast::Path::cast(colon_colon.parent())?.qualifier()?; | 20 | let path = ast::Path::cast(colon_colon.parent()?)?.qualifier()?; |
21 | let top_path = successors(Some(path.clone()), |it| it.parent_path()).last()?; | 21 | let top_path = successors(Some(path.clone()), |it| it.parent_path()).last()?; |
22 | 22 | ||
23 | let use_tree = top_path.syntax().ancestors().find_map(ast::UseTree::cast)?; | 23 | let use_tree = top_path.syntax().ancestors().find_map(ast::UseTree::cast)?; |
diff --git a/crates/ide_assists/src/handlers/unwrap_block.rs b/crates/ide_assists/src/handlers/unwrap_block.rs index ed6f6177d..440639322 100644 --- a/crates/ide_assists/src/handlers/unwrap_block.rs +++ b/crates/ide_assists/src/handlers/unwrap_block.rs | |||
@@ -30,7 +30,7 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
30 | let assist_label = "Unwrap block"; | 30 | let assist_label = "Unwrap block"; |
31 | 31 | ||
32 | let l_curly_token = ctx.find_token_syntax_at_offset(T!['{'])?; | 32 | let l_curly_token = ctx.find_token_syntax_at_offset(T!['{'])?; |
33 | let mut block = ast::BlockExpr::cast(l_curly_token.parent())?; | 33 | let mut block = ast::BlockExpr::cast(l_curly_token.parent()?)?; |
34 | let target = block.syntax().text_range(); | 34 | let target = block.syntax().text_range(); |
35 | let mut parent = block.syntax().parent()?; | 35 | let mut parent = block.syntax().parent()?; |
36 | if ast::MatchArm::can_cast(parent.kind()) { | 36 | if ast::MatchArm::can_cast(parent.kind()) { |