• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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<'_, '_> {
std(&self) -> Option<Crate>25     pub fn std(&self) -> Option<Crate> {
26         self.find_lang_crate(LangCrateOrigin::Std)
27     }
28 
core(&self) -> Option<Crate>29     pub fn core(&self) -> Option<Crate> {
30         self.find_lang_crate(LangCrateOrigin::Core)
31     }
32 
alloc(&self) -> Option<Crate>33     pub fn alloc(&self) -> Option<Crate> {
34         self.find_lang_crate(LangCrateOrigin::Alloc)
35     }
36 
test(&self) -> Option<Crate>37     pub fn test(&self) -> Option<Crate> {
38         self.find_lang_crate(LangCrateOrigin::Test)
39     }
40 
proc_macro(&self) -> Option<Crate>41     pub fn proc_macro(&self) -> Option<Crate> {
42         self.find_lang_crate(LangCrateOrigin::ProcMacro)
43     }
44 
core_cmp_Ord(&self) -> Option<Trait>45     pub fn core_cmp_Ord(&self) -> Option<Trait> {
46         self.find_trait("core:cmp:Ord")
47     }
48 
core_convert_From(&self) -> Option<Trait>49     pub fn core_convert_From(&self) -> Option<Trait> {
50         self.find_trait("core:convert:From")
51     }
52 
core_convert_Into(&self) -> Option<Trait>53     pub fn core_convert_Into(&self) -> Option<Trait> {
54         self.find_trait("core:convert:Into")
55     }
56 
core_option_Option(&self) -> Option<Enum>57     pub fn core_option_Option(&self) -> Option<Enum> {
58         self.find_enum("core:option:Option")
59     }
60 
core_result_Result(&self) -> Option<Enum>61     pub fn core_result_Result(&self) -> Option<Enum> {
62         self.find_enum("core:result:Result")
63     }
64 
core_default_Default(&self) -> Option<Trait>65     pub fn core_default_Default(&self) -> Option<Trait> {
66         self.find_trait("core:default:Default")
67     }
68 
core_iter_Iterator(&self) -> Option<Trait>69     pub fn core_iter_Iterator(&self) -> Option<Trait> {
70         self.find_trait("core:iter:traits:iterator:Iterator")
71     }
72 
core_iter_IntoIterator(&self) -> Option<Trait>73     pub fn core_iter_IntoIterator(&self) -> Option<Trait> {
74         self.find_trait("core:iter:traits:collect:IntoIterator")
75     }
76 
core_iter(&self) -> Option<Module>77     pub fn core_iter(&self) -> Option<Module> {
78         self.find_module("core:iter")
79     }
80 
core_ops_Deref(&self) -> Option<Trait>81     pub fn core_ops_Deref(&self) -> Option<Trait> {
82         self.find_trait("core:ops:Deref")
83     }
84 
core_ops_DerefMut(&self) -> Option<Trait>85     pub fn core_ops_DerefMut(&self) -> Option<Trait> {
86         self.find_trait("core:ops:DerefMut")
87     }
88 
core_convert_AsRef(&self) -> Option<Trait>89     pub fn core_convert_AsRef(&self) -> Option<Trait> {
90         self.find_trait("core:convert:AsRef")
91     }
92 
core_ops_ControlFlow(&self) -> Option<Enum>93     pub fn core_ops_ControlFlow(&self) -> Option<Enum> {
94         self.find_enum("core:ops:ControlFlow")
95     }
96 
core_ops_Drop(&self) -> Option<Trait>97     pub fn core_ops_Drop(&self) -> Option<Trait> {
98         self.find_trait("core:ops:Drop")
99     }
100 
core_marker_Copy(&self) -> Option<Trait>101     pub fn core_marker_Copy(&self) -> Option<Trait> {
102         self.find_trait("core:marker:Copy")
103     }
104 
core_macros_builtin_derive(&self) -> Option<Macro>105     pub fn core_macros_builtin_derive(&self) -> Option<Macro> {
106         self.find_macro("core:macros:builtin:derive")
107     }
108 
builtin_crates(&self) -> impl Iterator<Item = Crate>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 
find_trait(&self, path: &str) -> Option<Trait>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 
find_macro(&self, path: &str) -> Option<Macro>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 
find_enum(&self, path: &str) -> Option<Enum>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 
find_module(&self, path: &str) -> Option<Module>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 
find_lang_crate(&self, origin: LangCrateOrigin) -> Option<Crate>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 
find_def(&self, path: &str) -> Option<ScopeDef>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 }
186