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.rs160
1 files changed, 0 insertions, 160 deletions
diff --git a/crates/ra_hir/src/lang_item.rs b/crates/ra_hir/src/lang_item.rs
deleted file mode 100644
index 89fd85f59..000000000
--- a/crates/ra_hir/src/lang_item.rs
+++ /dev/null
@@ -1,160 +0,0 @@
1//! FIXME: write short doc here
2
3use rustc_hash::FxHashMap;
4use std::sync::Arc;
5
6use ra_syntax::{ast::AttrsOwner, SmolStr};
7
8use crate::{
9 db::{AstDatabase, DefDatabase, HirDatabase},
10 Adt, Crate, Enum, Function, HasSource, ImplBlock, Module, ModuleDef, Static, Struct, Trait,
11};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub enum LangItemTarget {
15 Enum(Enum),
16 Function(Function),
17 ImplBlock(ImplBlock),
18 Static(Static),
19 Struct(Struct),
20 Trait(Trait),
21}
22
23impl LangItemTarget {
24 pub(crate) fn krate(&self, db: &impl HirDatabase) -> Option<Crate> {
25 Some(match self {
26 LangItemTarget::Enum(e) => e.module(db).krate(),
27 LangItemTarget::Function(f) => f.module(db).krate(),
28 LangItemTarget::ImplBlock(i) => i.krate(db),
29 LangItemTarget::Static(s) => s.module(db).krate(),
30 LangItemTarget::Struct(s) => s.module(db).krate(),
31 LangItemTarget::Trait(t) => t.module(db).krate(),
32 })
33 }
34}
35
36#[derive(Default, Debug, Clone, PartialEq, Eq)]
37pub struct LangItems {
38 items: FxHashMap<SmolStr, LangItemTarget>,
39}
40
41impl LangItems {
42 pub fn target<'a>(&'a self, item: &str) -> Option<&'a LangItemTarget> {
43 self.items.get(item)
44 }
45
46 /// Salsa query. This will look for lang items in a specific crate.
47 pub(crate) fn crate_lang_items_query(
48 db: &(impl DefDatabase + AstDatabase),
49 krate: Crate,
50 ) -> Arc<LangItems> {
51 let mut lang_items = LangItems::default();
52
53 if let Some(module) = krate.root_module(db) {
54 lang_items.collect_lang_items_recursive(db, module);
55 }
56
57 Arc::new(lang_items)
58 }
59
60 pub(crate) fn module_lang_items_query(
61 db: &(impl DefDatabase + AstDatabase),
62 module: Module,
63 ) -> Option<Arc<LangItems>> {
64 let mut lang_items = LangItems::default();
65 lang_items.collect_lang_items(db, module);
66 if lang_items.items.is_empty() {
67 None
68 } else {
69 Some(Arc::new(lang_items))
70 }
71 }
72
73 /// Salsa query. Look for a lang item, starting from the specified crate and recursively
74 /// traversing its dependencies.
75 pub(crate) fn lang_item_query(
76 db: &impl DefDatabase,
77 start_crate: Crate,
78 item: SmolStr,
79 ) -> Option<LangItemTarget> {
80 let lang_items = db.crate_lang_items(start_crate);
81 let start_crate_target = lang_items.items.get(&item);
82 if let Some(target) = start_crate_target {
83 Some(*target)
84 } else {
85 for dep in start_crate.dependencies(db) {
86 let dep_crate = dep.krate;
87 let dep_target = db.lang_item(dep_crate, item.clone());
88 if dep_target.is_some() {
89 return dep_target;
90 }
91 }
92 None
93 }
94 }
95
96 fn collect_lang_items(&mut self, db: &(impl DefDatabase + AstDatabase), module: Module) {
97 // Look for impl targets
98 for impl_block in module.impl_blocks(db) {
99 let src = impl_block.source(db);
100 if let Some(lang_item_name) = lang_item_name(&src.value) {
101 self.items
102 .entry(lang_item_name)
103 .or_insert_with(|| LangItemTarget::ImplBlock(impl_block));
104 }
105 }
106
107 for def in module.declarations(db) {
108 match def {
109 ModuleDef::Trait(trait_) => {
110 self.collect_lang_item(db, trait_, LangItemTarget::Trait)
111 }
112 ModuleDef::Adt(Adt::Enum(e)) => self.collect_lang_item(db, e, LangItemTarget::Enum),
113 ModuleDef::Adt(Adt::Struct(s)) => {
114 self.collect_lang_item(db, s, LangItemTarget::Struct)
115 }
116 ModuleDef::Function(f) => self.collect_lang_item(db, f, LangItemTarget::Function),
117 ModuleDef::Static(s) => self.collect_lang_item(db, s, LangItemTarget::Static),
118 _ => {}
119 }
120 }
121 }
122
123 fn collect_lang_items_recursive(
124 &mut self,
125 db: &(impl DefDatabase + AstDatabase),
126 module: Module,
127 ) {
128 if let Some(module_lang_items) = db.module_lang_items(module) {
129 self.items.extend(module_lang_items.items.iter().map(|(k, v)| (k.clone(), *v)))
130 }
131
132 // Look for lang items in the children
133 for child in module.children(db) {
134 self.collect_lang_items_recursive(db, child);
135 }
136 }
137
138 fn collect_lang_item<T, N>(
139 &mut self,
140 db: &(impl DefDatabase + AstDatabase),
141 item: T,
142 constructor: fn(T) -> LangItemTarget,
143 ) where
144 T: Copy + HasSource<Ast = N>,
145 N: AttrsOwner,
146 {
147 let node = item.source(db).value;
148 if let Some(lang_item_name) = lang_item_name(&node) {
149 self.items.entry(lang_item_name).or_insert_with(|| constructor(item));
150 }
151 }
152}
153
154fn lang_item_name<T: AttrsOwner>(node: &T) -> Option<SmolStr> {
155 node.attrs()
156 .filter_map(|a| a.as_simple_key_value())
157 .filter(|(key, _)| key == "lang")
158 .map(|(_, val)| val)
159 .nth(0)
160}