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..adcc682a2 --- /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 | Impl(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::Impl(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 query a specific crate for lang items. | ||
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 | fn collect_lang_items_recursive(&mut self, db: &impl DefDatabase, module: &Module) { | ||
55 | // Look for impl targets | ||
56 | let (impl_blocks, source_map) = db.impls_in_module_with_source_map(module.clone()); | ||
57 | let source = module.definition_source(db).1; | ||
58 | for (impl_id, _) in impl_blocks.impls.iter() { | ||
59 | let impl_block = source_map.get(&source, impl_id); | ||
60 | let lang_item_name = impl_block | ||
61 | .attrs() | ||
62 | .filter_map(|a| a.as_key_value()) | ||
63 | .filter(|(key, _)| key == "lang") | ||
64 | .map(|(_, val)| val) | ||
65 | .nth(0); | ||
66 | if let Some(lang_item_name) = lang_item_name { | ||
67 | let imp = ImplBlock::from_id(*module, impl_id); | ||
68 | self.items.entry(lang_item_name).or_insert(LangItemTarget::Impl(imp)); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | // FIXME we should look for the other lang item targets (traits, structs, ...) | ||
73 | |||
74 | // Look for lang items in the children | ||
75 | for child in module.children(db) { | ||
76 | self.collect_lang_items_recursive(db, &child); | ||
77 | } | ||
78 | } | ||
79 | } | ||
80 | |||
81 | /// Look for a lang item, starting from the specified crate and recursively traversing its | ||
82 | /// dependencies. | ||
83 | pub(crate) fn lang_item_lookup( | ||
84 | db: &impl DefDatabase, | ||
85 | start_krate: Crate, | ||
86 | item: &str, | ||
87 | ) -> Option<LangItemTarget> { | ||
88 | let lang_items = db.lang_items(start_krate); | ||
89 | let start_krate_target = lang_items.items.get(item); | ||
90 | if start_krate_target.is_some() { | ||
91 | start_krate_target.map(|t| *t) | ||
92 | } else { | ||
93 | for dep in start_krate.dependencies(db) { | ||
94 | let dep_krate = dep.krate; | ||
95 | let dep_target = lang_item_lookup(db, dep_krate, item); | ||
96 | if dep_target.is_some() { | ||
97 | return dep_target; | ||
98 | } | ||
99 | } | ||
100 | None | ||
101 | } | ||
102 | } | ||