diff options
Diffstat (limited to 'crates/ide_db/src')
-rw-r--r-- | crates/ide_db/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ide_db/src/traits.rs | 78 | ||||
-rw-r--r-- | crates/ide_db/src/ty_filter.rs | 58 |
3 files changed, 138 insertions, 0 deletions
diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs index 7eff247c7..88f74265c 100644 --- a/crates/ide_db/src/lib.rs +++ b/crates/ide_db/src/lib.rs | |||
@@ -10,6 +10,8 @@ pub mod defs; | |||
10 | pub mod search; | 10 | pub mod search; |
11 | pub mod imports_locator; | 11 | pub mod imports_locator; |
12 | pub mod source_change; | 12 | pub mod source_change; |
13 | pub mod ty_filter; | ||
14 | pub mod traits; | ||
13 | 15 | ||
14 | use std::{fmt, sync::Arc}; | 16 | use std::{fmt, sync::Arc}; |
15 | 17 | ||
diff --git a/crates/ide_db/src/traits.rs b/crates/ide_db/src/traits.rs new file mode 100644 index 000000000..dcd61a595 --- /dev/null +++ b/crates/ide_db/src/traits.rs | |||
@@ -0,0 +1,78 @@ | |||
1 | //! Functionality for obtaining data related to traits from the DB. | ||
2 | |||
3 | use crate::RootDatabase; | ||
4 | use hir::Semantics; | ||
5 | use rustc_hash::FxHashSet; | ||
6 | use syntax::{ | ||
7 | ast::{self, NameOwner}, | ||
8 | AstNode, | ||
9 | }; | ||
10 | |||
11 | /// Given the `impl` block, attempts to find the trait this `impl` corresponds to. | ||
12 | pub fn resolve_target_trait( | ||
13 | sema: &Semantics<RootDatabase>, | ||
14 | impl_def: &ast::Impl, | ||
15 | ) -> Option<hir::Trait> { | ||
16 | let ast_path = | ||
17 | impl_def.trait_().map(|it| it.syntax().clone()).and_then(ast::PathType::cast)?.path()?; | ||
18 | |||
19 | match sema.resolve_path(&ast_path) { | ||
20 | Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => Some(def), | ||
21 | _ => None, | ||
22 | } | ||
23 | } | ||
24 | |||
25 | /// Given the `impl` block, returns the list of associated items (e.g. functions or types) that are | ||
26 | /// missing in this `impl` block. | ||
27 | pub fn get_missing_assoc_items( | ||
28 | sema: &Semantics<RootDatabase>, | ||
29 | impl_def: &ast::Impl, | ||
30 | ) -> Vec<hir::AssocItem> { | ||
31 | // Names must be unique between constants and functions. However, type aliases | ||
32 | // may share the same name as a function or constant. | ||
33 | let mut impl_fns_consts = FxHashSet::default(); | ||
34 | let mut impl_type = FxHashSet::default(); | ||
35 | |||
36 | if let Some(item_list) = impl_def.assoc_item_list() { | ||
37 | for item in item_list.assoc_items() { | ||
38 | match item { | ||
39 | ast::AssocItem::Fn(f) => { | ||
40 | if let Some(n) = f.name() { | ||
41 | impl_fns_consts.insert(n.syntax().to_string()); | ||
42 | } | ||
43 | } | ||
44 | |||
45 | ast::AssocItem::TypeAlias(t) => { | ||
46 | if let Some(n) = t.name() { | ||
47 | impl_type.insert(n.syntax().to_string()); | ||
48 | } | ||
49 | } | ||
50 | |||
51 | ast::AssocItem::Const(c) => { | ||
52 | if let Some(n) = c.name() { | ||
53 | impl_fns_consts.insert(n.syntax().to_string()); | ||
54 | } | ||
55 | } | ||
56 | ast::AssocItem::MacroCall(_) => (), | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | |||
61 | resolve_target_trait(sema, impl_def).map_or(vec![], |target_trait| { | ||
62 | target_trait | ||
63 | .items(sema.db) | ||
64 | .iter() | ||
65 | .filter(|i| match i { | ||
66 | hir::AssocItem::Function(f) => { | ||
67 | !impl_fns_consts.contains(&f.name(sema.db).to_string()) | ||
68 | } | ||
69 | hir::AssocItem::TypeAlias(t) => !impl_type.contains(&t.name(sema.db).to_string()), | ||
70 | hir::AssocItem::Const(c) => c | ||
71 | .name(sema.db) | ||
72 | .map(|n| !impl_fns_consts.contains(&n.to_string())) | ||
73 | .unwrap_or_default(), | ||
74 | }) | ||
75 | .cloned() | ||
76 | .collect() | ||
77 | }) | ||
78 | } | ||
diff --git a/crates/ide_db/src/ty_filter.rs b/crates/ide_db/src/ty_filter.rs new file mode 100644 index 000000000..63a945282 --- /dev/null +++ b/crates/ide_db/src/ty_filter.rs | |||
@@ -0,0 +1,58 @@ | |||
1 | //! This module contains structures for filtering the expected types. | ||
2 | //! Use case for structures in this module is, for example, situation when you need to process | ||
3 | //! only certain `Enum`s. | ||
4 | |||
5 | use crate::RootDatabase; | ||
6 | use hir::{Adt, Semantics, Type}; | ||
7 | use std::iter; | ||
8 | use syntax::ast::{self, make}; | ||
9 | |||
10 | /// Enum types that implement `std::ops::Try` trait. | ||
11 | #[derive(Clone, Copy)] | ||
12 | pub enum TryEnum { | ||
13 | Result, | ||
14 | Option, | ||
15 | } | ||
16 | |||
17 | impl TryEnum { | ||
18 | const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result]; | ||
19 | |||
20 | /// Returns `Some(..)` if the provided type is an enum that implements `std::ops::Try`. | ||
21 | pub fn from_ty(sema: &Semantics<RootDatabase>, ty: &Type) -> Option<TryEnum> { | ||
22 | let enum_ = match ty.as_adt() { | ||
23 | Some(Adt::Enum(it)) => it, | ||
24 | _ => return None, | ||
25 | }; | ||
26 | TryEnum::ALL.iter().find_map(|&var| { | ||
27 | if &enum_.name(sema.db).to_string() == var.type_name() { | ||
28 | return Some(var); | ||
29 | } | ||
30 | None | ||
31 | }) | ||
32 | } | ||
33 | |||
34 | pub fn happy_case(self) -> &'static str { | ||
35 | match self { | ||
36 | TryEnum::Result => "Ok", | ||
37 | TryEnum::Option => "Some", | ||
38 | } | ||
39 | } | ||
40 | |||
41 | pub fn sad_pattern(self) -> ast::Pat { | ||
42 | match self { | ||
43 | TryEnum::Result => make::tuple_struct_pat( | ||
44 | make::path_unqualified(make::path_segment(make::name_ref("Err"))), | ||
45 | iter::once(make::wildcard_pat().into()), | ||
46 | ) | ||
47 | .into(), | ||
48 | TryEnum::Option => make::ident_pat(make::name("None")).into(), | ||
49 | } | ||
50 | } | ||
51 | |||
52 | fn type_name(self) -> &'static str { | ||
53 | match self { | ||
54 | TryEnum::Result => "Result", | ||
55 | TryEnum::Option => "Option", | ||
56 | } | ||
57 | } | ||
58 | } | ||