aboutsummaryrefslogtreecommitdiff
path: root/crates/assists/src/utils.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/assists/src/utils.rs')
-rw-r--r--crates/assists/src/utils.rs146
1 files changed, 17 insertions, 129 deletions
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs
index b37b0d2b6..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,59 +156,11 @@ 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
277/// the compiler itself as well. 162/// the compiler itself as well.
278pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Crate); 163pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Option<Crate>);
279 164
280#[allow(non_snake_case)] 165#[allow(non_snake_case)]
281impl FamousDefs<'_, '_> { 166impl FamousDefs<'_, '_> {
@@ -362,6 +247,10 @@ pub mod prelude {
362pub use prelude::*; 247pub use prelude::*;
363"#; 248"#;
364 249
250 pub fn core(&self) -> Option<Crate> {
251 self.find_crate("core")
252 }
253
365 pub(crate) fn core_convert_From(&self) -> Option<Trait> { 254 pub(crate) fn core_convert_From(&self) -> Option<Trait> {
366 self.find_trait("core:convert:From") 255 self.find_trait("core:convert:From")
367 } 256 }
@@ -399,21 +288,20 @@ pub use prelude::*;
399 } 288 }
400 } 289 }
401 290
291 fn find_crate(&self, name: &str) -> Option<Crate> {
292 let krate = self.1?;
293 let db = self.0.db;
294 let res =
295 krate.dependencies(db).into_iter().find(|dep| dep.name.to_string() == name)?.krate;
296 Some(res)
297 }
298
402 fn find_def(&self, path: &str) -> Option<ScopeDef> { 299 fn find_def(&self, path: &str) -> Option<ScopeDef> {
403 let db = self.0.db; 300 let db = self.0.db;
404 let mut path = path.split(':'); 301 let mut path = path.split(':');
405 let trait_ = path.next_back()?; 302 let trait_ = path.next_back()?;
406 let std_crate = path.next()?; 303 let std_crate = path.next()?;
407 let std_crate = if self 304 let std_crate = self.find_crate(std_crate)?;
408 .1
409 .declaration_name(db)
410 .map(|name| name.to_string() == std_crate)
411 .unwrap_or(false)
412 {
413 self.1
414 } else {
415 self.1.dependencies(db).into_iter().find(|dep| dep.name.to_string() == std_crate)?.krate
416 };
417 let mut module = std_crate.root_module(db); 305 let mut module = std_crate.root_module(db);
418 for segment in path { 306 for segment in path {
419 module = module.children(db).find_map(|child| { 307 module = module.children(db).find_map(|child| {