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