aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/utils.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/utils.rs')
-rw-r--r--crates/ra_assists/src/utils.rs94
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.
2pub(crate) mod insert_use; 2pub(crate) mod insert_use;
3 3
4use std::iter; 4use std::{iter, ops};
5 5
6use hir::{Adt, Crate, Semantics, Trait, Type}; 6use hir::{Adt, Crate, Enum, ScopeDef, Semantics, Trait, Type};
7use ra_ide_db::RootDatabase; 7use ra_ide_db::RootDatabase;
8use ra_syntax::{ 8use ra_syntax::{
9 ast::{self, make, NameOwner}, 9 ast::{self, make, NameOwner},
10 AstNode, T, 10 AstNode, SyntaxNode, T,
11}; 11};
12use rustc_hash::FxHashSet; 12use rustc_hash::FxHashSet;
13 13
14pub use insert_use::insert_use_statement; 14use crate::assist_config::SnippetCap;
15 15
16pub fn get_missing_impl_items( 16pub(crate) use insert_use::insert_use_statement;
17
18#[derive(Clone, Copy, Debug)]
19pub(crate) enum Cursor<'a> {
20 Replace(&'a SyntaxNode),
21 Before(&'a SyntaxNode),
22}
23
24impl<'a> Cursor<'a> {
25 fn node(self) -> &'a SyntaxNode {
26 match self {
27 Cursor::Replace(node) | Cursor::Before(node) => node,
28 }
29 }
30}
31
32pub(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
55pub 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)]
106pub(crate) enum TryEnum { 145pub enum TryEnum {
107 Result, 146 Result,
108 Option, 147 Option,
109} 148}
@@ -111,7 +150,7 @@ pub(crate) enum TryEnum {
111impl TryEnum { 150impl 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
164pub mod convert{ 203pub 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
170pub mod prelude { pub use crate::convert::From } 209pub mod option {
210 pub enum Option<T> { None, Some(T)}
211}
212
213pub mod prelude {
214 pub use crate::{convert::From, option::Option::{self, *}};
215}
171#[prelude_import] 216#[prelude_import]
172pub use prelude::*; 217pub 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}