diff options
Diffstat (limited to 'crates/ra_assists/src/utils.rs')
-rw-r--r-- | crates/ra_assists/src/utils.rs | 94 |
1 files changed, 77 insertions, 17 deletions
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs index efd988697..0038a9764 100644 --- a/crates/ra_assists/src/utils.rs +++ b/crates/ra_assists/src/utils.rs | |||
@@ -1,19 +1,58 @@ | |||
1 | //! Assorted functions shared by several assists. | 1 | //! Assorted functions shared by several assists. |
2 | pub(crate) mod insert_use; | 2 | pub(crate) mod insert_use; |
3 | 3 | ||
4 | use std::iter; | 4 | use std::{iter, ops}; |
5 | 5 | ||
6 | use hir::{Adt, Crate, Semantics, Trait, Type}; | 6 | use hir::{Adt, Crate, Enum, ScopeDef, Semantics, Trait, Type}; |
7 | use ra_ide_db::RootDatabase; | 7 | use ra_ide_db::RootDatabase; |
8 | use ra_syntax::{ | 8 | use ra_syntax::{ |
9 | ast::{self, make, NameOwner}, | 9 | ast::{self, make, NameOwner}, |
10 | AstNode, T, | 10 | AstNode, SyntaxNode, T, |
11 | }; | 11 | }; |
12 | use rustc_hash::FxHashSet; | 12 | use rustc_hash::FxHashSet; |
13 | 13 | ||
14 | pub use insert_use::insert_use_statement; | 14 | use crate::assist_config::SnippetCap; |
15 | 15 | ||
16 | pub fn get_missing_impl_items( | 16 | pub(crate) use insert_use::insert_use_statement; |
17 | |||
18 | #[derive(Clone, Copy, Debug)] | ||
19 | pub(crate) enum Cursor<'a> { | ||
20 | Replace(&'a SyntaxNode), | ||
21 | Before(&'a SyntaxNode), | ||
22 | } | ||
23 | |||
24 | impl<'a> Cursor<'a> { | ||
25 | fn node(self) -> &'a SyntaxNode { | ||
26 | match self { | ||
27 | Cursor::Replace(node) | Cursor::Before(node) => node, | ||
28 | } | ||
29 | } | ||
30 | } | ||
31 | |||
32 | pub(crate) fn render_snippet(_cap: SnippetCap, node: &SyntaxNode, cursor: Cursor) -> String { | ||
33 | assert!(cursor.node().ancestors().any(|it| it == *node)); | ||
34 | let range = cursor.node().text_range() - node.text_range().start(); | ||
35 | let range: ops::Range<usize> = range.into(); | ||
36 | |||
37 | let mut placeholder = cursor.node().to_string(); | ||
38 | escape(&mut placeholder); | ||
39 | let tab_stop = match cursor { | ||
40 | Cursor::Replace(placeholder) => format!("${{0:{}}}", placeholder), | ||
41 | Cursor::Before(placeholder) => format!("$0{}", placeholder), | ||
42 | }; | ||
43 | |||
44 | let mut buf = node.to_string(); | ||
45 | buf.replace_range(range, &tab_stop); | ||
46 | return buf; | ||
47 | |||
48 | fn escape(buf: &mut String) { | ||
49 | stdx::replace(buf, '{', r"\{"); | ||
50 | stdx::replace(buf, '}', r"\}"); | ||
51 | stdx::replace(buf, '$', r"\$"); | ||
52 | } | ||
53 | } | ||
54 | |||
55 | pub fn get_missing_assoc_items( | ||
17 | sema: &Semantics<RootDatabase>, | 56 | sema: &Semantics<RootDatabase>, |
18 | impl_def: &ast::ImplDef, | 57 | impl_def: &ast::ImplDef, |
19 | ) -> Vec<hir::AssocItem> { | 58 | ) -> Vec<hir::AssocItem> { |
@@ -23,21 +62,21 @@ pub fn get_missing_impl_items( | |||
23 | let mut impl_type = FxHashSet::default(); | 62 | let mut impl_type = FxHashSet::default(); |
24 | 63 | ||
25 | if let Some(item_list) = impl_def.item_list() { | 64 | if let Some(item_list) = impl_def.item_list() { |
26 | for item in item_list.impl_items() { | 65 | for item in item_list.assoc_items() { |
27 | match item { | 66 | match item { |
28 | ast::ImplItem::FnDef(f) => { | 67 | ast::AssocItem::FnDef(f) => { |
29 | if let Some(n) = f.name() { | 68 | if let Some(n) = f.name() { |
30 | impl_fns_consts.insert(n.syntax().to_string()); | 69 | impl_fns_consts.insert(n.syntax().to_string()); |
31 | } | 70 | } |
32 | } | 71 | } |
33 | 72 | ||
34 | ast::ImplItem::TypeAliasDef(t) => { | 73 | ast::AssocItem::TypeAliasDef(t) => { |
35 | if let Some(n) = t.name() { | 74 | if let Some(n) = t.name() { |
36 | impl_type.insert(n.syntax().to_string()); | 75 | impl_type.insert(n.syntax().to_string()); |
37 | } | 76 | } |
38 | } | 77 | } |
39 | 78 | ||
40 | ast::ImplItem::ConstDef(c) => { | 79 | ast::AssocItem::ConstDef(c) => { |
41 | if let Some(n) = c.name() { | 80 | if let Some(n) = c.name() { |
42 | impl_fns_consts.insert(n.syntax().to_string()); | 81 | impl_fns_consts.insert(n.syntax().to_string()); |
43 | } | 82 | } |
@@ -103,7 +142,7 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> { | |||
103 | } | 142 | } |
104 | 143 | ||
105 | #[derive(Clone, Copy)] | 144 | #[derive(Clone, Copy)] |
106 | pub(crate) enum TryEnum { | 145 | pub enum TryEnum { |
107 | Result, | 146 | Result, |
108 | Option, | 147 | Option, |
109 | } | 148 | } |
@@ -111,7 +150,7 @@ pub(crate) enum TryEnum { | |||
111 | impl TryEnum { | 150 | impl TryEnum { |
112 | const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result]; | 151 | const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result]; |
113 | 152 | ||
114 | pub(crate) fn from_ty(sema: &Semantics<RootDatabase>, ty: &Type) -> Option<TryEnum> { | 153 | pub fn from_ty(sema: &Semantics<RootDatabase>, ty: &Type) -> Option<TryEnum> { |
115 | let enum_ = match ty.as_adt() { | 154 | let enum_ = match ty.as_adt() { |
116 | Some(Adt::Enum(it)) => it, | 155 | Some(Adt::Enum(it)) => it, |
117 | _ => return None, | 156 | _ => return None, |
@@ -161,13 +200,19 @@ impl FamousDefs<'_, '_> { | |||
161 | #[cfg(test)] | 200 | #[cfg(test)] |
162 | pub(crate) const FIXTURE: &'static str = r#" | 201 | pub(crate) const FIXTURE: &'static str = r#" |
163 | //- /libcore.rs crate:core | 202 | //- /libcore.rs crate:core |
164 | pub mod convert{ | 203 | pub mod convert { |
165 | pub trait From<T> { | 204 | pub trait From<T> { |
166 | fn from(T) -> Self; | 205 | fn from(T) -> Self; |
167 | } | 206 | } |
168 | } | 207 | } |
169 | 208 | ||
170 | pub mod prelude { pub use crate::convert::From } | 209 | pub mod option { |
210 | pub enum Option<T> { None, Some(T)} | ||
211 | } | ||
212 | |||
213 | pub mod prelude { | ||
214 | pub use crate::{convert::From, option::Option::{self, *}}; | ||
215 | } | ||
171 | #[prelude_import] | 216 | #[prelude_import] |
172 | pub use prelude::*; | 217 | pub use prelude::*; |
173 | "#; | 218 | "#; |
@@ -176,7 +221,25 @@ pub use prelude::*; | |||
176 | self.find_trait("core:convert:From") | 221 | self.find_trait("core:convert:From") |
177 | } | 222 | } |
178 | 223 | ||
224 | pub(crate) fn core_option_Option(&self) -> Option<Enum> { | ||
225 | self.find_enum("core:option:Option") | ||
226 | } | ||
227 | |||
179 | fn find_trait(&self, path: &str) -> Option<Trait> { | 228 | fn find_trait(&self, path: &str) -> Option<Trait> { |
229 | match self.find_def(path)? { | ||
230 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it), | ||
231 | _ => None, | ||
232 | } | ||
233 | } | ||
234 | |||
235 | fn find_enum(&self, path: &str) -> Option<Enum> { | ||
236 | match self.find_def(path)? { | ||
237 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(it))) => Some(it), | ||
238 | _ => None, | ||
239 | } | ||
240 | } | ||
241 | |||
242 | fn find_def(&self, path: &str) -> Option<ScopeDef> { | ||
180 | let db = self.0.db; | 243 | let db = self.0.db; |
181 | let mut path = path.split(':'); | 244 | let mut path = path.split(':'); |
182 | let trait_ = path.next_back()?; | 245 | let trait_ = path.next_back()?; |
@@ -201,9 +264,6 @@ pub use prelude::*; | |||
201 | } | 264 | } |
202 | let def = | 265 | let def = |
203 | module.scope(db, None).into_iter().find(|(name, _def)| &name.to_string() == trait_)?.1; | 266 | module.scope(db, None).into_iter().find(|(name, _def)| &name.to_string() == trait_)?.1; |
204 | match def { | 267 | Some(def) |
205 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it), | ||
206 | _ => None, | ||
207 | } | ||
208 | } | 268 | } |
209 | } | 269 | } |