aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/lang_item.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/lang_item.rs')
-rw-r--r--crates/ra_hir/src/lang_item.rs102
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 @@
1use std::sync::Arc;
2use rustc_hash::FxHashMap;
3
4use ra_syntax::{SmolStr, ast::AttrsOwner};
5
6use crate::{
7 Crate, DefDatabase, Enum, Function, HirDatabase, ImplBlock, Module, Static, Struct, Trait
8};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11pub enum LangItemTarget {
12 Enum(Enum),
13 Function(Function),
14 ImplBlock(ImplBlock),
15 Static(Static),
16 Struct(Struct),
17 Trait(Trait),
18}
19
20impl 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)]
34pub struct LangItems {
35 items: FxHashMap<SmolStr, LangItemTarget>,
36}
37
38impl 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}