aboutsummaryrefslogtreecommitdiff
path: root/crates/assists
diff options
context:
space:
mode:
Diffstat (limited to 'crates/assists')
-rw-r--r--crates/assists/Cargo.toml1
-rw-r--r--crates/assists/src/assist_context.rs2
-rw-r--r--crates/assists/src/handlers/add_missing_impl_members.rs3
-rw-r--r--crates/assists/src/handlers/extract_struct_from_enum_variant.rs2
-rw-r--r--crates/assists/src/handlers/fix_visibility.rs2
-rw-r--r--crates/assists/src/handlers/generate_function.rs2
-rw-r--r--crates/assists/src/handlers/remove_dbg.rs87
-rw-r--r--crates/assists/src/handlers/replace_if_let_with_match.rs6
-rw-r--r--crates/assists/src/handlers/replace_let_with_if_let.rs3
-rw-r--r--crates/assists/src/handlers/replace_unwrap_with_match.rs3
-rw-r--r--crates/assists/src/lib.rs2
-rw-r--r--crates/assists/src/tests.rs2
-rw-r--r--crates/assists/src/utils.rs121
13 files changed, 101 insertions, 135 deletions
diff --git a/crates/assists/Cargo.toml b/crates/assists/Cargo.toml
index 264125651..108f656e9 100644
--- a/crates/assists/Cargo.toml
+++ b/crates/assists/Cargo.toml
@@ -18,7 +18,6 @@ stdx = { path = "../stdx", version = "0.0.0" }
18syntax = { path = "../syntax", version = "0.0.0" } 18syntax = { path = "../syntax", version = "0.0.0" }
19text_edit = { path = "../text_edit", version = "0.0.0" } 19text_edit = { path = "../text_edit", version = "0.0.0" }
20profile = { path = "../profile", version = "0.0.0" } 20profile = { path = "../profile", version = "0.0.0" }
21base_db = { path = "../base_db", version = "0.0.0" }
22ide_db = { path = "../ide_db", version = "0.0.0" } 21ide_db = { path = "../ide_db", version = "0.0.0" }
23hir = { path = "../hir", version = "0.0.0" } 22hir = { path = "../hir", version = "0.0.0" }
24test_utils = { path = "../test_utils", version = "0.0.0" } 23test_utils = { path = "../test_utils", version = "0.0.0" }
diff --git a/crates/assists/src/assist_context.rs b/crates/assists/src/assist_context.rs
index bf520069e..d11fee196 100644
--- a/crates/assists/src/assist_context.rs
+++ b/crates/assists/src/assist_context.rs
@@ -3,8 +3,8 @@
3use std::mem; 3use std::mem;
4 4
5use algo::find_covering_element; 5use algo::find_covering_element;
6use base_db::{FileId, FileRange};
7use hir::Semantics; 6use hir::Semantics;
7use ide_db::base_db::{FileId, FileRange};
8use ide_db::{ 8use ide_db::{
9 label::Label, 9 label::Label,
10 source_change::{SourceChange, SourceFileEdit}, 10 source_change::{SourceChange, SourceFileEdit},
diff --git a/crates/assists/src/handlers/add_missing_impl_members.rs b/crates/assists/src/handlers/add_missing_impl_members.rs
index 4c400f287..b82fb30ad 100644
--- a/crates/assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/assists/src/handlers/add_missing_impl_members.rs
@@ -1,4 +1,5 @@
1use hir::HasSource; 1use hir::HasSource;
2use ide_db::traits::{get_missing_assoc_items, resolve_target_trait};
2use syntax::{ 3use syntax::{
3 ast::{ 4 ast::{
4 self, 5 self,
@@ -11,7 +12,7 @@ use syntax::{
11use crate::{ 12use crate::{
12 assist_context::{AssistContext, Assists}, 13 assist_context::{AssistContext, Assists},
13 ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, 14 ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams},
14 utils::{get_missing_assoc_items, render_snippet, resolve_target_trait, Cursor}, 15 utils::{render_snippet, Cursor},
15 AssistId, AssistKind, 16 AssistId, AssistKind,
16}; 17};
17 18
diff --git a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
index 7f4f80b23..48433feb9 100644
--- a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -1,5 +1,5 @@
1use base_db::FileId;
2use hir::{EnumVariant, Module, ModuleDef, Name}; 1use hir::{EnumVariant, Module, ModuleDef, Name};
2use ide_db::base_db::FileId;
3use ide_db::{defs::Definition, search::Reference, RootDatabase}; 3use ide_db::{defs::Definition, search::Reference, RootDatabase};
4use itertools::Itertools; 4use itertools::Itertools;
5use rustc_hash::FxHashSet; 5use rustc_hash::FxHashSet;
diff --git a/crates/assists/src/handlers/fix_visibility.rs b/crates/assists/src/handlers/fix_visibility.rs
index 66f74150c..c86720787 100644
--- a/crates/assists/src/handlers/fix_visibility.rs
+++ b/crates/assists/src/handlers/fix_visibility.rs
@@ -1,5 +1,5 @@
1use base_db::FileId;
2use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution}; 1use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution};
2use ide_db::base_db::FileId;
3use syntax::{ 3use syntax::{
4 ast::{self, VisibilityOwner}, 4 ast::{self, VisibilityOwner},
5 AstNode, TextRange, TextSize, 5 AstNode, TextRange, TextSize,
diff --git a/crates/assists/src/handlers/generate_function.rs b/crates/assists/src/handlers/generate_function.rs
index d23f4293b..758188a42 100644
--- a/crates/assists/src/handlers/generate_function.rs
+++ b/crates/assists/src/handlers/generate_function.rs
@@ -1,5 +1,5 @@
1use base_db::FileId;
2use hir::HirDisplay; 1use hir::HirDisplay;
2use ide_db::base_db::FileId;
3use rustc_hash::{FxHashMap, FxHashSet}; 3use rustc_hash::{FxHashMap, FxHashSet};
4use syntax::{ 4use syntax::{
5 ast::{ 5 ast::{
diff --git a/crates/assists/src/handlers/remove_dbg.rs b/crates/assists/src/handlers/remove_dbg.rs
index e10616779..9731344b8 100644
--- a/crates/assists/src/handlers/remove_dbg.rs
+++ b/crates/assists/src/handlers/remove_dbg.rs
@@ -93,8 +93,9 @@ fn needs_parentheses_around_macro_contents(macro_contents: Vec<SyntaxElement>) -
93 if macro_contents.len() < 2 { 93 if macro_contents.len() < 2 {
94 return false; 94 return false;
95 } 95 }
96 let mut macro_contents = macro_contents.into_iter().peekable();
96 let mut unpaired_brackets_in_contents = Vec::new(); 97 let mut unpaired_brackets_in_contents = Vec::new();
97 for element in macro_contents { 98 while let Some(element) = macro_contents.next() {
98 match element.kind() { 99 match element.kind() {
99 T!['('] | T!['['] | T!['{'] => unpaired_brackets_in_contents.push(element), 100 T!['('] | T!['['] | T!['{'] => unpaired_brackets_in_contents.push(element),
100 T![')'] => { 101 T![')'] => {
@@ -118,8 +119,14 @@ fn needs_parentheses_around_macro_contents(macro_contents: Vec<SyntaxElement>) -
118 symbol_kind => { 119 symbol_kind => {
119 let symbol_not_in_bracket = unpaired_brackets_in_contents.is_empty(); 120 let symbol_not_in_bracket = unpaired_brackets_in_contents.is_empty();
120 if symbol_not_in_bracket 121 if symbol_not_in_bracket
121 && symbol_kind != SyntaxKind::COLON 122 && symbol_kind != SyntaxKind::COLON // paths
122 && symbol_kind.is_punct() 123 && (symbol_kind != SyntaxKind::DOT // field/method access
124 || macro_contents // range expressions consist of two SyntaxKind::Dot in macro invocations
125 .peek()
126 .map(|element| element.kind() == SyntaxKind::DOT)
127 .unwrap_or(false))
128 && symbol_kind != SyntaxKind::QUESTION // try operator
129 && (symbol_kind.is_punct() || symbol_kind == SyntaxKind::AS_KW)
123 { 130 {
124 return true; 131 return true;
125 } 132 }
@@ -243,6 +250,25 @@ fn main() {
243 } 250 }
244 251
245 #[test] 252 #[test]
253 fn test_remove_dbg_method_chaining() {
254 check_assist(
255 remove_dbg,
256 r#"let res = <|>dbg!(foo().bar()).baz();"#,
257 r#"let res = foo().bar().baz();"#,
258 );
259 check_assist(
260 remove_dbg,
261 r#"let res = <|>dbg!(foo.bar()).baz();"#,
262 r#"let res = foo.bar().baz();"#,
263 );
264 }
265
266 #[test]
267 fn test_remove_dbg_field_chaining() {
268 check_assist(remove_dbg, r#"let res = <|>dbg!(foo.bar).baz;"#, r#"let res = foo.bar.baz;"#);
269 }
270
271 #[test]
246 fn test_remove_dbg_from_inside_fn() { 272 fn test_remove_dbg_from_inside_fn() {
247 check_assist_target( 273 check_assist_target(
248 remove_dbg, 274 remove_dbg,
@@ -280,4 +306,59 @@ fn main() {
280}"#, 306}"#,
281 ); 307 );
282 } 308 }
309
310 #[test]
311 fn test_remove_dbg_try_expr() {
312 check_assist(
313 remove_dbg,
314 r#"let res = <|>dbg!(result?).foo();"#,
315 r#"let res = result?.foo();"#,
316 );
317 }
318
319 #[test]
320 fn test_remove_dbg_await_expr() {
321 check_assist(
322 remove_dbg,
323 r#"let res = <|>dbg!(fut.await).foo();"#,
324 r#"let res = fut.await.foo();"#,
325 );
326 }
327
328 #[test]
329 fn test_remove_dbg_as_cast() {
330 check_assist(
331 remove_dbg,
332 r#"let res = <|>dbg!(3 as usize).foo();"#,
333 r#"let res = (3 as usize).foo();"#,
334 );
335 }
336
337 #[test]
338 fn test_remove_dbg_index_expr() {
339 check_assist(
340 remove_dbg,
341 r#"let res = <|>dbg!(array[3]).foo();"#,
342 r#"let res = array[3].foo();"#,
343 );
344 check_assist(
345 remove_dbg,
346 r#"let res = <|>dbg!(tuple.3).foo();"#,
347 r#"let res = tuple.3.foo();"#,
348 );
349 }
350
351 #[test]
352 fn test_remove_dbg_range_expr() {
353 check_assist(
354 remove_dbg,
355 r#"let res = <|>dbg!(foo..bar).foo();"#,
356 r#"let res = (foo..bar).foo();"#,
357 );
358 check_assist(
359 remove_dbg,
360 r#"let res = <|>dbg!(foo..=bar).foo();"#,
361 r#"let res = (foo..=bar).foo();"#,
362 );
363 }
283} 364}
diff --git a/crates/assists/src/handlers/replace_if_let_with_match.rs b/crates/assists/src/handlers/replace_if_let_with_match.rs
index 79097621e..9a49c48c1 100644
--- a/crates/assists/src/handlers/replace_if_let_with_match.rs
+++ b/crates/assists/src/handlers/replace_if_let_with_match.rs
@@ -7,10 +7,8 @@ use syntax::{
7 AstNode, 7 AstNode,
8}; 8};
9 9
10use crate::{ 10use crate::{utils::unwrap_trivial_block, AssistContext, AssistId, AssistKind, Assists};
11 utils::{unwrap_trivial_block, TryEnum}, 11use ide_db::ty_filter::TryEnum;
12 AssistContext, AssistId, AssistKind, Assists,
13};
14 12
15// Assist: replace_if_let_with_match 13// Assist: replace_if_let_with_match
16// 14//
diff --git a/crates/assists/src/handlers/replace_let_with_if_let.rs b/crates/assists/src/handlers/replace_let_with_if_let.rs
index ed6d0c29b..a5bcbda24 100644
--- a/crates/assists/src/handlers/replace_let_with_if_let.rs
+++ b/crates/assists/src/handlers/replace_let_with_if_let.rs
@@ -9,7 +9,8 @@ use syntax::{
9 AstNode, T, 9 AstNode, T,
10}; 10};
11 11
12use crate::{utils::TryEnum, AssistContext, AssistId, AssistKind, Assists}; 12use crate::{AssistContext, AssistId, AssistKind, Assists};
13use ide_db::ty_filter::TryEnum;
13 14
14// Assist: replace_let_with_if_let 15// Assist: replace_let_with_if_let
15// 16//
diff --git a/crates/assists/src/handlers/replace_unwrap_with_match.rs b/crates/assists/src/handlers/replace_unwrap_with_match.rs
index 4043c219c..f547066f0 100644
--- a/crates/assists/src/handlers/replace_unwrap_with_match.rs
+++ b/crates/assists/src/handlers/replace_unwrap_with_match.rs
@@ -10,9 +10,10 @@ use syntax::{
10}; 10};
11 11
12use crate::{ 12use crate::{
13 utils::{render_snippet, Cursor, TryEnum}, 13 utils::{render_snippet, Cursor},
14 AssistContext, AssistId, AssistKind, Assists, 14 AssistContext, AssistId, AssistKind, Assists,
15}; 15};
16use ide_db::ty_filter::TryEnum;
16 17
17// Assist: replace_unwrap_with_match 18// Assist: replace_unwrap_with_match
18// 19//
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs
index 8a664f654..70a651e10 100644
--- a/crates/assists/src/lib.rs
+++ b/crates/assists/src/lib.rs
@@ -17,8 +17,8 @@ mod tests;
17pub mod utils; 17pub mod utils;
18pub mod ast_transform; 18pub mod ast_transform;
19 19
20use base_db::FileRange;
21use hir::Semantics; 20use hir::Semantics;
21use ide_db::base_db::FileRange;
22use ide_db::{label::Label, source_change::SourceChange, RootDatabase}; 22use ide_db::{label::Label, source_change::SourceChange, RootDatabase};
23use syntax::TextRange; 23use syntax::TextRange;
24 24
diff --git a/crates/assists/src/tests.rs b/crates/assists/src/tests.rs
index 2b687decf..849d85e76 100644
--- a/crates/assists/src/tests.rs
+++ b/crates/assists/src/tests.rs
@@ -1,7 +1,7 @@
1mod generated; 1mod generated;
2 2
3use base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt};
4use hir::Semantics; 3use hir::Semantics;
4use ide_db::base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt};
5use ide_db::RootDatabase; 5use ide_db::RootDatabase;
6use syntax::TextRange; 6use syntax::TextRange;
7use test_utils::{assert_eq_text, extract_offset, extract_range}; 7use test_utils::{assert_eq_text, extract_offset, extract_range};
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs
index 1a6b48b45..56f925ee6 100644
--- a/crates/assists/src/utils.rs
+++ b/crates/assists/src/utils.rs
@@ -2,14 +2,13 @@
2pub(crate) mod insert_use; 2pub(crate) mod insert_use;
3pub(crate) mod import_assets; 3pub(crate) mod import_assets;
4 4
5use std::{iter, ops}; 5use std::ops;
6 6
7use hir::{Adt, Crate, Enum, Module, ScopeDef, Semantics, Trait, Type}; 7use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait};
8use ide_db::RootDatabase; 8use ide_db::RootDatabase;
9use itertools::Itertools; 9use itertools::Itertools;
10use rustc_hash::FxHashSet;
11use syntax::{ 10use syntax::{
12 ast::{self, make, ArgListOwner, NameOwner}, 11 ast::{self, make, ArgListOwner},
13 AstNode, Direction, 12 AstNode, Direction,
14 SyntaxKind::*, 13 SyntaxKind::*,
15 SyntaxNode, TextSize, T, 14 SyntaxNode, TextSize, T,
@@ -115,72 +114,6 @@ pub(crate) fn render_snippet(_cap: SnippetCap, node: &SyntaxNode, cursor: Cursor
115 } 114 }
116} 115}
117 116
118pub fn get_missing_assoc_items(
119 sema: &Semantics<RootDatabase>,
120 impl_def: &ast::Impl,
121) -> Vec<hir::AssocItem> {
122 // Names must be unique between constants and functions. However, type aliases
123 // may share the same name as a function or constant.
124 let mut impl_fns_consts = FxHashSet::default();
125 let mut impl_type = FxHashSet::default();
126
127 if let Some(item_list) = impl_def.assoc_item_list() {
128 for item in item_list.assoc_items() {
129 match item {
130 ast::AssocItem::Fn(f) => {
131 if let Some(n) = f.name() {
132 impl_fns_consts.insert(n.syntax().to_string());
133 }
134 }
135
136 ast::AssocItem::TypeAlias(t) => {
137 if let Some(n) = t.name() {
138 impl_type.insert(n.syntax().to_string());
139 }
140 }
141
142 ast::AssocItem::Const(c) => {
143 if let Some(n) = c.name() {
144 impl_fns_consts.insert(n.syntax().to_string());
145 }
146 }
147 ast::AssocItem::MacroCall(_) => (),
148 }
149 }
150 }
151
152 resolve_target_trait(sema, impl_def).map_or(vec![], |target_trait| {
153 target_trait
154 .items(sema.db)
155 .iter()
156 .filter(|i| match i {
157 hir::AssocItem::Function(f) => {
158 !impl_fns_consts.contains(&f.name(sema.db).to_string())
159 }
160 hir::AssocItem::TypeAlias(t) => !impl_type.contains(&t.name(sema.db).to_string()),
161 hir::AssocItem::Const(c) => c
162 .name(sema.db)
163 .map(|n| !impl_fns_consts.contains(&n.to_string()))
164 .unwrap_or_default(),
165 })
166 .cloned()
167 .collect()
168 })
169}
170
171pub(crate) fn resolve_target_trait(
172 sema: &Semantics<RootDatabase>,
173 impl_def: &ast::Impl,
174) -> Option<hir::Trait> {
175 let ast_path =
176 impl_def.trait_().map(|it| it.syntax().clone()).and_then(ast::PathType::cast)?.path()?;
177
178 match sema.resolve_path(&ast_path) {
179 Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => Some(def),
180 _ => None,
181 }
182}
183
184pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize { 117pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize {
185 node.children_with_tokens() 118 node.children_with_tokens()
186 .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR)) 119 .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
@@ -223,54 +156,6 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
223 } 156 }
224} 157}
225 158
226#[derive(Clone, Copy)]
227pub enum TryEnum {
228 Result,
229 Option,
230}
231
232impl TryEnum {
233 const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result];
234
235 pub fn from_ty(sema: &Semantics<RootDatabase>, ty: &Type) -> Option<TryEnum> {
236 let enum_ = match ty.as_adt() {
237 Some(Adt::Enum(it)) => it,
238 _ => return None,
239 };
240 TryEnum::ALL.iter().find_map(|&var| {
241 if &enum_.name(sema.db).to_string() == var.type_name() {
242 return Some(var);
243 }
244 None
245 })
246 }
247
248 pub(crate) fn happy_case(self) -> &'static str {
249 match self {
250 TryEnum::Result => "Ok",
251 TryEnum::Option => "Some",
252 }
253 }
254
255 pub(crate) fn sad_pattern(self) -> ast::Pat {
256 match self {
257 TryEnum::Result => make::tuple_struct_pat(
258 make::path_unqualified(make::path_segment(make::name_ref("Err"))),
259 iter::once(make::wildcard_pat().into()),
260 )
261 .into(),
262 TryEnum::Option => make::ident_pat(make::name("None")).into(),
263 }
264 }
265
266 fn type_name(self) -> &'static str {
267 match self {
268 TryEnum::Result => "Result",
269 TryEnum::Option => "Option",
270 }
271 }
272}
273
274/// Helps with finding well-know things inside the standard library. This is 159/// Helps with finding well-know things inside the standard library. This is
275/// somewhat similar to the known paths infra inside hir, but it different; We 160/// somewhat similar to the known paths infra inside hir, but it different; We
276/// want to make sure that IDE specific paths don't become interesting inside 161/// want to make sure that IDE specific paths don't become interesting inside