diff options
Diffstat (limited to 'crates/ra_hir/src/lang_item.rs')
-rw-r--r-- | crates/ra_hir/src/lang_item.rs | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/crates/ra_hir/src/lang_item.rs b/crates/ra_hir/src/lang_item.rs new file mode 100644 index 000000000..5f3f91cba --- /dev/null +++ b/crates/ra_hir/src/lang_item.rs | |||
@@ -0,0 +1,102 @@ | |||
1 | use std::sync::Arc; | ||
2 | use rustc_hash::FxHashMap; | ||
3 | |||
4 | use ra_syntax::{SmolStr, ast::AttrsOwner}; | ||
5 | |||
6 | use crate::{ | ||
7 | Crate, DefDatabase, Enum, Function, HirDatabase, ImplBlock, Module, Static, Struct, Trait | ||
8 | }; | ||
9 | |||
10 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
11 | pub enum LangItemTarget { | ||
12 | Enum(Enum), | ||
13 | Function(Function), | ||
14 | ImplBlock(ImplBlock), | ||
15 | Static(Static), | ||
16 | Struct(Struct), | ||
17 | Trait(Trait), | ||
18 | } | ||
19 | |||
20 | impl LangItemTarget { | ||
21 | pub(crate) fn krate(&self, db: &impl HirDatabase) -> Option<Crate> { | ||
22 | match self { | ||
23 | LangItemTarget::Enum(e) => e.module(db).krate(db), | ||
24 | LangItemTarget::Function(f) => f.module(db).krate(db), | ||
25 | LangItemTarget::ImplBlock(i) => i.module().krate(db), | ||
26 | LangItemTarget::Static(s) => s.module(db).krate(db), | ||
27 | LangItemTarget::Struct(s) => s.module(db).krate(db), | ||
28 | LangItemTarget::Trait(t) => t.module(db).krate(db), | ||
29 | } | ||
30 | } | ||
31 | } | ||
32 | |||
33 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
34 | pub struct LangItems { | ||
35 | items: FxHashMap<SmolStr, LangItemTarget>, | ||
36 | } | ||
37 | |||
38 | impl LangItems { | ||
39 | pub fn target<'a>(&'a self, item: &str) -> Option<&'a LangItemTarget> { | ||
40 | self.items.get(item) | ||
41 | } | ||
42 | |||
43 | /// Salsa query. This will look for lang items in a specific crate. | ||
44 | pub(crate) fn lang_items_query(db: &impl DefDatabase, krate: Crate) -> Arc<LangItems> { | ||
45 | let mut lang_items = LangItems { items: FxHashMap::default() }; | ||
46 | |||
47 | if let Some(module) = krate.root_module(db) { | ||
48 | lang_items.collect_lang_items_recursive(db, &module); | ||
49 | } | ||
50 | |||
51 | Arc::new(lang_items) | ||
52 | } | ||
53 | |||
54 | /// Salsa query. Look for a lang item, starting from the specified crate and recursively | ||
55 | /// traversing its dependencies. | ||
56 | pub(crate) fn lang_item_query( | ||
57 | db: &impl DefDatabase, | ||
58 | start_crate: Crate, | ||
59 | item: SmolStr, | ||
60 | ) -> Option<LangItemTarget> { | ||
61 | let lang_items = db.lang_items(start_crate); | ||
62 | let start_crate_target = lang_items.items.get(&item); | ||
63 | if let Some(target) = start_crate_target { | ||
64 | Some(*target) | ||
65 | } else { | ||
66 | for dep in start_crate.dependencies(db) { | ||
67 | let dep_crate = dep.krate; | ||
68 | let dep_target = db.lang_item(dep_crate, item.clone()); | ||
69 | if dep_target.is_some() { | ||
70 | return dep_target; | ||
71 | } | ||
72 | } | ||
73 | None | ||
74 | } | ||
75 | } | ||
76 | |||
77 | fn collect_lang_items_recursive(&mut self, db: &impl DefDatabase, module: &Module) { | ||
78 | // Look for impl targets | ||
79 | let (impl_blocks, source_map) = db.impls_in_module_with_source_map(module.clone()); | ||
80 | let source = module.definition_source(db).1; | ||
81 | for (impl_id, _) in impl_blocks.impls.iter() { | ||
82 | let impl_block = source_map.get(&source, impl_id); | ||
83 | let lang_item_name = impl_block | ||
84 | .attrs() | ||
85 | .filter_map(|a| a.as_key_value()) | ||
86 | .filter(|(key, _)| key == "lang") | ||
87 | .map(|(_, val)| val) | ||
88 | .nth(0); | ||
89 | if let Some(lang_item_name) = lang_item_name { | ||
90 | let imp = ImplBlock::from_id(*module, impl_id); | ||
91 | self.items.entry(lang_item_name).or_insert(LangItemTarget::ImplBlock(imp)); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | // FIXME we should look for the other lang item targets (traits, structs, ...) | ||
96 | |||
97 | // Look for lang items in the children | ||
98 | for child in module.children(db) { | ||
99 | self.collect_lang_items_recursive(db, &child); | ||
100 | } | ||
101 | } | ||
102 | } | ||