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..adcc682a2
--- /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 Impl(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::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)]
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 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.
83pub(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}