aboutsummaryrefslogtreecommitdiff
path: root/crates/assists
diff options
context:
space:
mode:
Diffstat (limited to 'crates/assists')
-rw-r--r--crates/assists/src/handlers/remove_unused_param.rs83
-rw-r--r--crates/assists/src/utils/insert_use.rs96
2 files changed, 159 insertions, 20 deletions
diff --git a/crates/assists/src/handlers/remove_unused_param.rs b/crates/assists/src/handlers/remove_unused_param.rs
index 5fccca54b..1ff5e92b0 100644
--- a/crates/assists/src/handlers/remove_unused_param.rs
+++ b/crates/assists/src/handlers/remove_unused_param.rs
@@ -73,7 +73,8 @@ fn process_usage(
73 let source_file = ctx.sema.parse(usage.file_range.file_id); 73 let source_file = ctx.sema.parse(usage.file_range.file_id);
74 let call_expr: ast::CallExpr = 74 let call_expr: ast::CallExpr =
75 find_node_at_range(source_file.syntax(), usage.file_range.range)?; 75 find_node_at_range(source_file.syntax(), usage.file_range.range)?;
76 if call_expr.expr()?.syntax().text_range() != usage.file_range.range { 76 let call_expr_range = call_expr.expr()?.syntax().text_range();
77 if !call_expr_range.contains_range(usage.file_range.range) {
77 return None; 78 return None;
78 } 79 }
79 let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?; 80 let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?;
@@ -118,6 +119,53 @@ fn b() { foo(9, ) }
118 } 119 }
119 120
120 #[test] 121 #[test]
122 fn remove_unused_qualified_call() {
123 check_assist(
124 remove_unused_param,
125 r#"
126mod bar { pub fn foo(x: i32, <|>y: i32) { x; } }
127fn b() { bar::foo(9, 2) }
128"#,
129 r#"
130mod bar { pub fn foo(x: i32) { x; } }
131fn b() { bar::foo(9) }
132"#,
133 );
134 }
135
136 #[test]
137 fn remove_unused_turbofished_func() {
138 check_assist(
139 remove_unused_param,
140 r#"
141pub fn foo<T>(x: T, <|>y: i32) { x; }
142fn b() { foo::<i32>(9, 2) }
143"#,
144 r#"
145pub fn foo<T>(x: T) { x; }
146fn b() { foo::<i32>(9) }
147"#,
148 );
149 }
150
151 #[test]
152 fn remove_unused_generic_unused_param_func() {
153 check_assist(
154 remove_unused_param,
155 r#"
156pub fn foo<T>(x: i32, <|>y: T) { x; }
157fn b() { foo::<i32>(9, 2) }
158fn b2() { foo(9, 2) }
159"#,
160 r#"
161pub fn foo<T>(x: i32) { x; }
162fn b() { foo::<i32>(9) }
163fn b2() { foo(9) }
164"#,
165 );
166 }
167
168 #[test]
121 fn keep_used() { 169 fn keep_used() {
122 mark::check!(keep_used); 170 mark::check!(keep_used);
123 check_assist_not_applicable( 171 check_assist_not_applicable(
@@ -128,4 +176,37 @@ fn main() { foo(9, 2) }
128"#, 176"#,
129 ); 177 );
130 } 178 }
179
180 #[test]
181 fn remove_across_files() {
182 check_assist(
183 remove_unused_param,
184 r#"
185//- /main.rs
186fn foo(x: i32, <|>y: i32) { x; }
187
188mod foo;
189
190//- /foo.rs
191use super::foo;
192
193fn bar() {
194 let _ = foo(1, 2);
195}
196"#,
197 r#"
198//- /main.rs
199fn foo(x: i32) { x; }
200
201mod foo;
202
203//- /foo.rs
204use super::foo;
205
206fn bar() {
207 let _ = foo(1);
208}
209"#,
210 )
211 }
131} 212}
diff --git a/crates/assists/src/utils/insert_use.rs b/crates/assists/src/utils/insert_use.rs
index 84a0dffdd..af3fc96b6 100644
--- a/crates/assists/src/utils/insert_use.rs
+++ b/crates/assists/src/utils/insert_use.rs
@@ -9,7 +9,7 @@ use syntax::{
9 edit::{AstNodeEdit, IndentLevel}, 9 edit::{AstNodeEdit, IndentLevel},
10 make, AstNode, PathSegmentKind, VisibilityOwner, 10 make, AstNode, PathSegmentKind, VisibilityOwner,
11 }, 11 },
12 InsertPosition, SyntaxElement, SyntaxNode, 12 AstToken, InsertPosition, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken,
13}; 13};
14use test_utils::mark; 14use test_utils::mark;
15 15
@@ -63,27 +63,30 @@ impl ImportScope {
63 } 63 }
64 } 64 }
65 65
66 fn insert_pos_after_inner_attribute(&self) -> (InsertPosition<SyntaxElement>, AddBlankLine) { 66 fn insert_pos_after_last_inner_element(&self) -> (InsertPosition<SyntaxElement>, AddBlankLine) {
67 // check if the scope has inner attributes, we dont want to insert in front of them 67 self.as_syntax_node()
68 match self 68 .children_with_tokens()
69 .as_syntax_node() 69 .filter(|child| match child {
70 .children() 70 NodeOrToken::Node(node) => is_inner_attribute(node.clone()),
71 // no flat_map here cause we want to short circuit the iterator 71 NodeOrToken::Token(token) => is_inner_comment(token.clone()),
72 .map(ast::Attr::cast)
73 .take_while(|attr| {
74 attr.as_ref().map(|attr| attr.kind() == ast::AttrKind::Inner).unwrap_or(false)
75 }) 72 })
76 .last() 73 .last()
77 .flatten() 74 .map(|last_inner_element| {
78 { 75 (InsertPosition::After(last_inner_element.into()), AddBlankLine::BeforeTwice)
79 Some(attr) => { 76 })
80 (InsertPosition::After(attr.syntax().clone().into()), AddBlankLine::BeforeTwice) 77 .unwrap_or_else(|| self.first_insert_pos())
81 }
82 None => self.first_insert_pos(),
83 }
84 } 78 }
85} 79}
86 80
81fn is_inner_attribute(node: SyntaxNode) -> bool {
82 ast::Attr::cast(node).map(|attr| attr.kind()) == Some(ast::AttrKind::Inner)
83}
84
85fn is_inner_comment(token: SyntaxToken) -> bool {
86 ast::Comment::cast(token).and_then(|comment| comment.kind().doc)
87 == Some(ast::CommentPlacement::Inner)
88}
89
87/// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. 90/// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur.
88pub(crate) fn insert_use<'a>( 91pub(crate) fn insert_use<'a>(
89 scope: &ImportScope, 92 scope: &ImportScope,
@@ -558,7 +561,7 @@ fn find_insert_position(
558 (InsertPosition::After(node.into()), AddBlankLine::BeforeTwice) 561 (InsertPosition::After(node.into()), AddBlankLine::BeforeTwice)
559 } 562 }
560 // there are no imports in this file at all 563 // there are no imports in this file at all
561 None => scope.insert_pos_after_inner_attribute(), 564 None => scope.insert_pos_after_last_inner_element(),
562 }, 565 },
563 } 566 }
564 } 567 }
@@ -830,12 +833,67 @@ use foo::bar;",
830 "foo::bar", 833 "foo::bar",
831 r"#![allow(unused_imports)] 834 r"#![allow(unused_imports)]
832 835
836#![no_std]
833fn main() {}", 837fn main() {}",
834 r"#![allow(unused_imports)] 838 r"#![allow(unused_imports)]
835 839
836use foo::bar; 840#![no_std]
837 841
842use foo::bar;
838fn main() {}", 843fn main() {}",
844 );
845 }
846
847 #[test]
848 fn inserts_after_single_line_inner_comments() {
849 check_none(
850 "foo::bar::Baz",
851 "//! Single line inner comments do not allow any code before them.",
852 r#"//! Single line inner comments do not allow any code before them.
853
854use foo::bar::Baz;"#,
855 );
856 }
857
858 #[test]
859 fn inserts_after_multiline_inner_comments() {
860 check_none(
861 "foo::bar::Baz",
862 r#"/*! Multiline inner comments do not allow any code before them. */
863
864/*! Still an inner comment, cannot place any code before. */
865fn main() {}"#,
866 r#"/*! Multiline inner comments do not allow any code before them. */
867
868/*! Still an inner comment, cannot place any code before. */
869
870use foo::bar::Baz;
871fn main() {}"#,
872 )
873 }
874
875 #[test]
876 fn inserts_after_all_inner_items() {
877 check_none(
878 "foo::bar::Baz",
879 r#"#![allow(unused_imports)]
880/*! Multiline line comment 2 */
881
882
883//! Single line comment 1
884#![no_std]
885//! Single line comment 2
886fn main() {}"#,
887 r#"#![allow(unused_imports)]
888/*! Multiline line comment 2 */
889
890
891//! Single line comment 1
892#![no_std]
893//! Single line comment 2
894
895use foo::bar::Baz;
896fn main() {}"#,
839 ) 897 )
840 } 898 }
841 899