diff options
Diffstat (limited to 'crates/assists/src/utils.rs')
-rw-r--r-- | crates/assists/src/utils.rs | 92 |
1 files changed, 89 insertions, 3 deletions
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index 56f925ee6..7071fe96b 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs | |||
@@ -4,17 +4,22 @@ pub(crate) mod import_assets; | |||
4 | 4 | ||
5 | use std::ops; | 5 | use std::ops; |
6 | 6 | ||
7 | use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait}; | 7 | use hir::{Crate, Enum, HasSource, Module, ScopeDef, Semantics, Trait}; |
8 | use ide_db::RootDatabase; | 8 | use ide_db::RootDatabase; |
9 | use itertools::Itertools; | 9 | use itertools::Itertools; |
10 | use syntax::{ | 10 | use syntax::{ |
11 | ast::{self, make, ArgListOwner}, | 11 | ast::edit::AstNodeEdit, |
12 | ast::NameOwner, | ||
13 | ast::{self, edit, make, ArgListOwner}, | ||
12 | AstNode, Direction, | 14 | AstNode, Direction, |
13 | SyntaxKind::*, | 15 | SyntaxKind::*, |
14 | SyntaxNode, TextSize, T, | 16 | SyntaxNode, TextSize, T, |
15 | }; | 17 | }; |
16 | 18 | ||
17 | use crate::assist_config::SnippetCap; | 19 | use crate::{ |
20 | assist_config::SnippetCap, | ||
21 | ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, | ||
22 | }; | ||
18 | 23 | ||
19 | pub use insert_use::MergeBehaviour; | 24 | pub use insert_use::MergeBehaviour; |
20 | pub(crate) use insert_use::{insert_use, ImportScope}; | 25 | pub(crate) use insert_use::{insert_use, ImportScope}; |
@@ -77,6 +82,87 @@ pub fn extract_trivial_expression(block: &ast::BlockExpr) -> Option<ast::Expr> { | |||
77 | None | 82 | None |
78 | } | 83 | } |
79 | 84 | ||
85 | #[derive(Copy, Clone, PartialEq)] | ||
86 | pub enum DefaultMethods { | ||
87 | Only, | ||
88 | No, | ||
89 | } | ||
90 | |||
91 | pub fn filter_assoc_items( | ||
92 | db: &RootDatabase, | ||
93 | items: &[hir::AssocItem], | ||
94 | default_methods: DefaultMethods, | ||
95 | ) -> Vec<ast::AssocItem> { | ||
96 | fn has_def_name(item: &ast::AssocItem) -> bool { | ||
97 | match item { | ||
98 | ast::AssocItem::Fn(def) => def.name(), | ||
99 | ast::AssocItem::TypeAlias(def) => def.name(), | ||
100 | ast::AssocItem::Const(def) => def.name(), | ||
101 | ast::AssocItem::MacroCall(_) => None, | ||
102 | } | ||
103 | .is_some() | ||
104 | }; | ||
105 | |||
106 | items | ||
107 | .iter() | ||
108 | .map(|i| match i { | ||
109 | hir::AssocItem::Function(i) => ast::AssocItem::Fn(i.source(db).value), | ||
110 | hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(i.source(db).value), | ||
111 | hir::AssocItem::Const(i) => ast::AssocItem::Const(i.source(db).value), | ||
112 | }) | ||
113 | .filter(has_def_name) | ||
114 | .filter(|it| match it { | ||
115 | ast::AssocItem::Fn(def) => matches!( | ||
116 | (default_methods, def.body()), | ||
117 | (DefaultMethods::Only, Some(_)) | (DefaultMethods::No, None) | ||
118 | ), | ||
119 | _ => default_methods == DefaultMethods::No, | ||
120 | }) | ||
121 | .collect::<Vec<_>>() | ||
122 | } | ||
123 | |||
124 | pub fn add_trait_assoc_items_to_impl( | ||
125 | sema: &hir::Semantics<ide_db::RootDatabase>, | ||
126 | items: Vec<ast::AssocItem>, | ||
127 | trait_: hir::Trait, | ||
128 | impl_def: ast::Impl, | ||
129 | target_scope: hir::SemanticsScope, | ||
130 | ) -> (ast::Impl, ast::AssocItem) { | ||
131 | let impl_item_list = impl_def.assoc_item_list().unwrap_or_else(make::assoc_item_list); | ||
132 | |||
133 | let n_existing_items = impl_item_list.assoc_items().count(); | ||
134 | let source_scope = sema.scope_for_def(trait_); | ||
135 | let ast_transform = QualifyPaths::new(&target_scope, &source_scope) | ||
136 | .or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_def.clone())); | ||
137 | |||
138 | let items = items | ||
139 | .into_iter() | ||
140 | .map(|it| ast_transform::apply(&*ast_transform, it)) | ||
141 | .map(|it| match it { | ||
142 | ast::AssocItem::Fn(def) => ast::AssocItem::Fn(add_body(def)), | ||
143 | ast::AssocItem::TypeAlias(def) => ast::AssocItem::TypeAlias(def.remove_bounds()), | ||
144 | _ => it, | ||
145 | }) | ||
146 | .map(|it| edit::remove_attrs_and_docs(&it)); | ||
147 | |||
148 | let new_impl_item_list = impl_item_list.append_items(items); | ||
149 | let new_impl_def = impl_def.with_assoc_item_list(new_impl_item_list); | ||
150 | let first_new_item = | ||
151 | new_impl_def.assoc_item_list().unwrap().assoc_items().nth(n_existing_items).unwrap(); | ||
152 | return (new_impl_def, first_new_item); | ||
153 | |||
154 | fn add_body(fn_def: ast::Fn) -> ast::Fn { | ||
155 | match fn_def.body() { | ||
156 | Some(_) => fn_def, | ||
157 | None => { | ||
158 | let body = | ||
159 | make::block_expr(None, Some(make::expr_todo())).indent(edit::IndentLevel(1)); | ||
160 | fn_def.with_body(body) | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | |||
80 | #[derive(Clone, Copy, Debug)] | 166 | #[derive(Clone, Copy, Debug)] |
81 | pub(crate) enum Cursor<'a> { | 167 | pub(crate) enum Cursor<'a> { |
82 | Replace(&'a SyntaxNode), | 168 | Replace(&'a SyntaxNode), |