]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
Rollup merge of #102258 - cjgillot:core-kappa, r=m-ou-se
[rust.git] / src / tools / rust-analyzer / crates / ide-db / src / famous_defs.rs
1 //! See [`FamousDefs`].
2
3 use base_db::{CrateOrigin, LangCrateOrigin, SourceDatabase};
4 use hir::{Crate, Enum, Macro, Module, ScopeDef, Semantics, Trait};
5
6 use crate::RootDatabase;
7
8 /// Helps with finding well-know things inside the standard library. This is
9 /// somewhat similar to the known paths infra inside hir, but it different; We
10 /// want to make sure that IDE specific paths don't become interesting inside
11 /// the compiler itself as well.
12 ///
13 /// Note that, by default, rust-analyzer tests **do not** include core or std
14 /// libraries. If you are writing tests for functionality using [`FamousDefs`],
15 /// you'd want to include minicore (see `test_utils::MiniCore`) declaration at
16 /// the start of your tests:
17 ///
18 /// ```
19 /// //- minicore: iterator, ord, derive
20 /// ```
21 pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Crate);
22
23 #[allow(non_snake_case)]
24 impl FamousDefs<'_, '_> {
25     pub fn std(&self) -> Option<Crate> {
26         self.find_lang_crate(LangCrateOrigin::Std)
27     }
28
29     pub fn core(&self) -> Option<Crate> {
30         self.find_lang_crate(LangCrateOrigin::Core)
31     }
32
33     pub fn alloc(&self) -> Option<Crate> {
34         self.find_lang_crate(LangCrateOrigin::Alloc)
35     }
36
37     pub fn test(&self) -> Option<Crate> {
38         self.find_lang_crate(LangCrateOrigin::Test)
39     }
40
41     pub fn proc_macro(&self) -> Option<Crate> {
42         self.find_lang_crate(LangCrateOrigin::ProcMacro)
43     }
44
45     pub fn core_cmp_Ord(&self) -> Option<Trait> {
46         self.find_trait("core:cmp:Ord")
47     }
48
49     pub fn core_convert_From(&self) -> Option<Trait> {
50         self.find_trait("core:convert:From")
51     }
52
53     pub fn core_convert_Into(&self) -> Option<Trait> {
54         self.find_trait("core:convert:Into")
55     }
56
57     pub fn core_option_Option(&self) -> Option<Enum> {
58         self.find_enum("core:option:Option")
59     }
60
61     pub fn core_result_Result(&self) -> Option<Enum> {
62         self.find_enum("core:result:Result")
63     }
64
65     pub fn core_default_Default(&self) -> Option<Trait> {
66         self.find_trait("core:default:Default")
67     }
68
69     pub fn core_iter_Iterator(&self) -> Option<Trait> {
70         self.find_trait("core:iter:traits:iterator:Iterator")
71     }
72
73     pub fn core_iter_IntoIterator(&self) -> Option<Trait> {
74         self.find_trait("core:iter:traits:collect:IntoIterator")
75     }
76
77     pub fn core_iter(&self) -> Option<Module> {
78         self.find_module("core:iter")
79     }
80
81     pub fn core_ops_Deref(&self) -> Option<Trait> {
82         self.find_trait("core:ops:Deref")
83     }
84
85     pub fn core_ops_DerefMut(&self) -> Option<Trait> {
86         self.find_trait("core:ops:DerefMut")
87     }
88
89     pub fn core_convert_AsRef(&self) -> Option<Trait> {
90         self.find_trait("core:convert:AsRef")
91     }
92
93     pub fn core_ops_ControlFlow(&self) -> Option<Enum> {
94         self.find_enum("core:ops:ControlFlow")
95     }
96
97     pub fn core_ops_Drop(&self) -> Option<Trait> {
98         self.find_trait("core:ops:Drop")
99     }
100
101     pub fn core_marker_Copy(&self) -> Option<Trait> {
102         self.find_trait("core:marker:Copy")
103     }
104
105     pub fn core_macros_builtin_derive(&self) -> Option<Macro> {
106         self.find_macro("core:macros:builtin:derive")
107     }
108
109     pub fn builtin_crates(&self) -> impl Iterator<Item = Crate> {
110         IntoIterator::into_iter([
111             self.std(),
112             self.core(),
113             self.alloc(),
114             self.test(),
115             self.proc_macro(),
116         ])
117         .flatten()
118     }
119
120     fn find_trait(&self, path: &str) -> Option<Trait> {
121         match self.find_def(path)? {
122             hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it),
123             _ => None,
124         }
125     }
126
127     fn find_macro(&self, path: &str) -> Option<Macro> {
128         match self.find_def(path)? {
129             hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(it)) => Some(it),
130             _ => None,
131         }
132     }
133
134     fn find_enum(&self, path: &str) -> Option<Enum> {
135         match self.find_def(path)? {
136             hir::ScopeDef::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(it))) => Some(it),
137             _ => None,
138         }
139     }
140
141     fn find_module(&self, path: &str) -> Option<Module> {
142         match self.find_def(path)? {
143             hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(it)) => Some(it),
144             _ => None,
145         }
146     }
147
148     fn find_lang_crate(&self, origin: LangCrateOrigin) -> Option<Crate> {
149         let krate = self.1;
150         let db = self.0.db;
151         let crate_graph = self.0.db.crate_graph();
152         let res = krate
153             .dependencies(db)
154             .into_iter()
155             .find(|dep| crate_graph[dep.krate.into()].origin == CrateOrigin::Lang(origin))?
156             .krate;
157         Some(res)
158     }
159
160     fn find_def(&self, path: &str) -> Option<ScopeDef> {
161         let db = self.0.db;
162         let mut path = path.split(':');
163         let trait_ = path.next_back()?;
164         let lang_crate = path.next()?;
165         let lang_crate = match LangCrateOrigin::from(lang_crate) {
166             LangCrateOrigin::Other => return None,
167             lang_crate => lang_crate,
168         };
169         let std_crate = self.find_lang_crate(lang_crate)?;
170         let mut module = std_crate.root_module(db);
171         for segment in path {
172             module = module.children(db).find_map(|child| {
173                 let name = child.name(db)?;
174                 if name.to_smol_str() == segment {
175                     Some(child)
176                 } else {
177                     None
178                 }
179             })?;
180         }
181         let def =
182             module.scope(db, None).into_iter().find(|(name, _def)| name.to_smol_str() == trait_)?.1;
183         Some(def)
184     }
185 }