diff options
29 files changed, 507 insertions, 321 deletions
diff --git a/Cargo.lock b/Cargo.lock index 215dd627c..ea2c1aed7 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -1179,6 +1179,7 @@ dependencies = [ | |||
1179 | "once_cell", | 1179 | "once_cell", |
1180 | "perf-event", | 1180 | "perf-event", |
1181 | "tikv-jemalloc-ctl", | 1181 | "tikv-jemalloc-ctl", |
1182 | "winapi", | ||
1182 | ] | 1183 | ] |
1183 | 1184 | ||
1184 | [[package]] | 1185 | [[package]] |
diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs index 62bf2a4b2..54baa3a63 100644 --- a/crates/base_db/src/lib.rs +++ b/crates/base_db/src/lib.rs | |||
@@ -120,6 +120,7 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> { | |||
120 | } | 120 | } |
121 | 121 | ||
122 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { | 122 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
123 | let _p = profile::span("relevant_crates"); | ||
123 | let source_root = self.0.file_source_root(file_id); | 124 | let source_root = self.0.file_source_root(file_id); |
124 | self.0.source_root_crates(source_root) | 125 | self.0.source_root_crates(source_root) |
125 | } | 126 | } |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index dba46df04..b9c1dc44d 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -191,6 +191,7 @@ impl Crate { | |||
191 | db: &dyn DefDatabase, | 191 | db: &dyn DefDatabase, |
192 | query: import_map::Query, | 192 | query: import_map::Query, |
193 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | 193 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { |
194 | let _p = profile::span("query_external_importables"); | ||
194 | import_map::search_dependencies(db, self.into(), query).into_iter().map(|item| match item { | 195 | import_map::search_dependencies(db, self.into(), query).into_iter().map(|item| match item { |
195 | ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()), | 196 | ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()), |
196 | ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), | 197 | ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), |
@@ -1344,6 +1345,7 @@ impl MacroDef { | |||
1344 | MacroDefKind::Declarative(_) => MacroKind::Declarative, | 1345 | MacroDefKind::Declarative(_) => MacroKind::Declarative, |
1345 | MacroDefKind::BuiltIn(_, _) | MacroDefKind::BuiltInEager(_, _) => MacroKind::BuiltIn, | 1346 | MacroDefKind::BuiltIn(_, _) | MacroDefKind::BuiltInEager(_, _) => MacroKind::BuiltIn, |
1346 | MacroDefKind::BuiltInDerive(_, _) => MacroKind::Derive, | 1347 | MacroDefKind::BuiltInDerive(_, _) => MacroKind::Derive, |
1348 | MacroDefKind::BuiltInAttr(_, _) => MacroKind::Attr, | ||
1347 | MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::CustomDerive, _) => { | 1349 | MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::CustomDerive, _) => { |
1348 | MacroKind::Derive | 1350 | MacroKind::Derive |
1349 | } | 1351 | } |
@@ -2184,6 +2186,7 @@ impl Type { | |||
2184 | name: Option<&Name>, | 2186 | name: Option<&Name>, |
2185 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | 2187 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, |
2186 | ) -> Option<T> { | 2188 | ) -> Option<T> { |
2189 | let _p = profile::span("iterate_method_candidates"); | ||
2187 | // There should be no inference vars in types passed here | 2190 | // There should be no inference vars in types passed here |
2188 | // FIXME check that? | 2191 | // FIXME check that? |
2189 | // FIXME replace Unknown by bound vars here | 2192 | // FIXME replace Unknown by bound vars here |
@@ -2217,6 +2220,7 @@ impl Type { | |||
2217 | name: Option<&Name>, | 2220 | name: Option<&Name>, |
2218 | mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, | 2221 | mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, |
2219 | ) -> Option<T> { | 2222 | ) -> Option<T> { |
2223 | let _p = profile::span("iterate_path_candidates"); | ||
2220 | let canonical = hir_ty::replace_errors_with_variables(&self.ty); | 2224 | let canonical = hir_ty::replace_errors_with_variables(&self.ty); |
2221 | 2225 | ||
2222 | let env = self.env.clone(); | 2226 | let env = self.env.clone(); |
@@ -2254,6 +2258,7 @@ impl Type { | |||
2254 | &'a self, | 2258 | &'a self, |
2255 | db: &'a dyn HirDatabase, | 2259 | db: &'a dyn HirDatabase, |
2256 | ) -> impl Iterator<Item = Trait> + 'a { | 2260 | ) -> impl Iterator<Item = Trait> + 'a { |
2261 | let _p = profile::span("applicable_inherent_traits"); | ||
2257 | self.autoderef(db) | 2262 | self.autoderef(db) |
2258 | .filter_map(|derefed_type| derefed_type.ty.dyn_trait()) | 2263 | .filter_map(|derefed_type| derefed_type.ty.dyn_trait()) |
2259 | .flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db.upcast(), dyn_trait_id)) | 2264 | .flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db.upcast(), dyn_trait_id)) |
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs index 960cabb5f..404e3e153 100644 --- a/crates/hir_def/src/import_map.rs +++ b/crates/hir_def/src/import_map.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! A map of all publicly exported items in a crate. | 1 | //! A map of all publicly exported items in a crate. |
2 | 2 | ||
3 | use std::{cmp::Ordering, fmt, hash::BuildHasherDefault, sync::Arc}; | 3 | use std::{fmt, hash::BuildHasherDefault, sync::Arc}; |
4 | 4 | ||
5 | use base_db::CrateId; | 5 | use base_db::CrateId; |
6 | use fst::{self, Streamer}; | 6 | use fst::{self, Streamer}; |
@@ -69,81 +69,11 @@ pub struct ImportMap { | |||
69 | impl ImportMap { | 69 | impl ImportMap { |
70 | pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> { | 70 | pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> { |
71 | let _p = profile::span("import_map_query"); | 71 | let _p = profile::span("import_map_query"); |
72 | let def_map = db.crate_def_map(krate); | ||
73 | let mut import_map = Self::default(); | ||
74 | |||
75 | // We look only into modules that are public(ly reexported), starting with the crate root. | ||
76 | let empty = ImportPath { segments: vec![] }; | ||
77 | let root = def_map.module_id(def_map.root()); | ||
78 | let mut worklist = vec![(root, empty)]; | ||
79 | while let Some((module, mod_path)) = worklist.pop() { | ||
80 | let ext_def_map; | ||
81 | let mod_data = if module.krate == krate { | ||
82 | &def_map[module.local_id] | ||
83 | } else { | ||
84 | // The crate might reexport a module defined in another crate. | ||
85 | ext_def_map = module.def_map(db); | ||
86 | &ext_def_map[module.local_id] | ||
87 | }; | ||
88 | |||
89 | let visible_items = mod_data.scope.entries().filter_map(|(name, per_ns)| { | ||
90 | let per_ns = per_ns.filter_visibility(|vis| vis == Visibility::Public); | ||
91 | if per_ns.is_none() { | ||
92 | None | ||
93 | } else { | ||
94 | Some((name, per_ns)) | ||
95 | } | ||
96 | }); | ||
97 | |||
98 | for (name, per_ns) in visible_items { | ||
99 | let mk_path = || { | ||
100 | let mut path = mod_path.clone(); | ||
101 | path.segments.push(name.clone()); | ||
102 | path | ||
103 | }; | ||
104 | |||
105 | for item in per_ns.iter_items() { | ||
106 | let path = mk_path(); | ||
107 | let path_len = path.len(); | ||
108 | let import_info = | ||
109 | ImportInfo { path, container: module, is_trait_assoc_item: false }; | ||
110 | |||
111 | if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() { | ||
112 | import_map.collect_trait_assoc_items( | ||
113 | db, | ||
114 | tr, | ||
115 | matches!(item, ItemInNs::Types(_)), | ||
116 | &import_info, | ||
117 | ); | ||
118 | } | ||
119 | 72 | ||
120 | match import_map.map.entry(item) { | 73 | let mut import_map = collect_import_map(db, krate); |
121 | Entry::Vacant(entry) => { | ||
122 | entry.insert(import_info); | ||
123 | } | ||
124 | Entry::Occupied(mut entry) => { | ||
125 | // If the new path is shorter, prefer that one. | ||
126 | if path_len < entry.get().path.len() { | ||
127 | *entry.get_mut() = import_info; | ||
128 | } else { | ||
129 | continue; | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | |||
134 | // If we've just added a path to a module, descend into it. We might traverse | ||
135 | // modules multiple times, but only if the new path to it is shorter than the | ||
136 | // first (else we `continue` above). | ||
137 | if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() { | ||
138 | worklist.push((mod_id, mk_path())); | ||
139 | } | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | 74 | ||
144 | let mut importables = import_map.map.iter().collect::<Vec<_>>(); | 75 | let mut importables = import_map.map.iter().collect::<Vec<_>>(); |
145 | 76 | importables.sort_by_cached_key(|(_, import_info)| fst_path(&import_info.path)); | |
146 | importables.sort_by(cmp); | ||
147 | 77 | ||
148 | // Build the FST, taking care not to insert duplicate values. | 78 | // Build the FST, taking care not to insert duplicate values. |
149 | 79 | ||
@@ -151,13 +81,13 @@ impl ImportMap { | |||
151 | let mut last_batch_start = 0; | 81 | let mut last_batch_start = 0; |
152 | 82 | ||
153 | for idx in 0..importables.len() { | 83 | for idx in 0..importables.len() { |
154 | if let Some(next_item) = importables.get(idx + 1) { | 84 | let key = fst_path(&importables[last_batch_start].1.path); |
155 | if cmp(&importables[last_batch_start], next_item) == Ordering::Equal { | 85 | if let Some((_, next_import_info)) = importables.get(idx + 1) { |
86 | if key == fst_path(&next_import_info.path) { | ||
156 | continue; | 87 | continue; |
157 | } | 88 | } |
158 | } | 89 | } |
159 | 90 | ||
160 | let key = fst_path(&importables[last_batch_start].1.path); | ||
161 | builder.insert(key, last_batch_start as u64).unwrap(); | 91 | builder.insert(key, last_batch_start as u64).unwrap(); |
162 | 92 | ||
163 | last_batch_start = idx + 1; | 93 | last_batch_start = idx + 1; |
@@ -185,6 +115,7 @@ impl ImportMap { | |||
185 | is_type_in_ns: bool, | 115 | is_type_in_ns: bool, |
186 | original_import_info: &ImportInfo, | 116 | original_import_info: &ImportInfo, |
187 | ) { | 117 | ) { |
118 | let _p = profile::span("collect_trait_assoc_items"); | ||
188 | for (assoc_item_name, item) in &db.trait_data(tr).items { | 119 | for (assoc_item_name, item) in &db.trait_data(tr).items { |
189 | let module_def_id = match item { | 120 | let module_def_id = match item { |
190 | AssocItemId::FunctionId(f) => ModuleDefId::from(*f), | 121 | AssocItemId::FunctionId(f) => ModuleDefId::from(*f), |
@@ -210,6 +141,84 @@ impl ImportMap { | |||
210 | } | 141 | } |
211 | } | 142 | } |
212 | 143 | ||
144 | fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMap { | ||
145 | let _p = profile::span("collect_import_map"); | ||
146 | |||
147 | let def_map = db.crate_def_map(krate); | ||
148 | let mut import_map = ImportMap::default(); | ||
149 | |||
150 | // We look only into modules that are public(ly reexported), starting with the crate root. | ||
151 | let empty = ImportPath { segments: vec![] }; | ||
152 | let root = def_map.module_id(def_map.root()); | ||
153 | let mut worklist = vec![(root, empty)]; | ||
154 | while let Some((module, mod_path)) = worklist.pop() { | ||
155 | let ext_def_map; | ||
156 | let mod_data = if module.krate == krate { | ||
157 | &def_map[module.local_id] | ||
158 | } else { | ||
159 | // The crate might reexport a module defined in another crate. | ||
160 | ext_def_map = module.def_map(db); | ||
161 | &ext_def_map[module.local_id] | ||
162 | }; | ||
163 | |||
164 | let visible_items = mod_data.scope.entries().filter_map(|(name, per_ns)| { | ||
165 | let per_ns = per_ns.filter_visibility(|vis| vis == Visibility::Public); | ||
166 | if per_ns.is_none() { | ||
167 | None | ||
168 | } else { | ||
169 | Some((name, per_ns)) | ||
170 | } | ||
171 | }); | ||
172 | |||
173 | for (name, per_ns) in visible_items { | ||
174 | let mk_path = || { | ||
175 | let mut path = mod_path.clone(); | ||
176 | path.segments.push(name.clone()); | ||
177 | path | ||
178 | }; | ||
179 | |||
180 | for item in per_ns.iter_items() { | ||
181 | let path = mk_path(); | ||
182 | let path_len = path.len(); | ||
183 | let import_info = | ||
184 | ImportInfo { path, container: module, is_trait_assoc_item: false }; | ||
185 | |||
186 | if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() { | ||
187 | import_map.collect_trait_assoc_items( | ||
188 | db, | ||
189 | tr, | ||
190 | matches!(item, ItemInNs::Types(_)), | ||
191 | &import_info, | ||
192 | ); | ||
193 | } | ||
194 | |||
195 | match import_map.map.entry(item) { | ||
196 | Entry::Vacant(entry) => { | ||
197 | entry.insert(import_info); | ||
198 | } | ||
199 | Entry::Occupied(mut entry) => { | ||
200 | // If the new path is shorter, prefer that one. | ||
201 | if path_len < entry.get().path.len() { | ||
202 | *entry.get_mut() = import_info; | ||
203 | } else { | ||
204 | continue; | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | |||
209 | // If we've just added a path to a module, descend into it. We might traverse | ||
210 | // modules multiple times, but only if the new path to it is shorter than the | ||
211 | // first (else we `continue` above). | ||
212 | if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() { | ||
213 | worklist.push((mod_id, mk_path())); | ||
214 | } | ||
215 | } | ||
216 | } | ||
217 | } | ||
218 | |||
219 | import_map | ||
220 | } | ||
221 | |||
213 | impl PartialEq for ImportMap { | 222 | impl PartialEq for ImportMap { |
214 | fn eq(&self, other: &Self) -> bool { | 223 | fn eq(&self, other: &Self) -> bool { |
215 | // `fst` and `importables` are built from `map`, so we don't need to compare them. | 224 | // `fst` and `importables` are built from `map`, so we don't need to compare them. |
@@ -240,17 +249,12 @@ impl fmt::Debug for ImportMap { | |||
240 | } | 249 | } |
241 | 250 | ||
242 | fn fst_path(path: &ImportPath) -> String { | 251 | fn fst_path(path: &ImportPath) -> String { |
252 | let _p = profile::span("fst_path"); | ||
243 | let mut s = path.to_string(); | 253 | let mut s = path.to_string(); |
244 | s.make_ascii_lowercase(); | 254 | s.make_ascii_lowercase(); |
245 | s | 255 | s |
246 | } | 256 | } |
247 | 257 | ||
248 | fn cmp((_, lhs): &(&ItemInNs, &ImportInfo), (_, rhs): &(&ItemInNs, &ImportInfo)) -> Ordering { | ||
249 | let lhs_str = fst_path(&lhs.path); | ||
250 | let rhs_str = fst_path(&rhs.path); | ||
251 | lhs_str.cmp(&rhs_str) | ||
252 | } | ||
253 | |||
254 | #[derive(Debug, Eq, PartialEq, Hash)] | 258 | #[derive(Debug, Eq, PartialEq, Hash)] |
255 | pub enum ImportKind { | 259 | pub enum ImportKind { |
256 | Module, | 260 | Module, |
@@ -338,6 +342,7 @@ impl Query { | |||
338 | } | 342 | } |
339 | 343 | ||
340 | fn import_matches(&self, import: &ImportInfo, enforce_lowercase: bool) -> bool { | 344 | fn import_matches(&self, import: &ImportInfo, enforce_lowercase: bool) -> bool { |
345 | let _p = profile::span("import_map::Query::import_matches"); | ||
341 | if import.is_trait_assoc_item { | 346 | if import.is_trait_assoc_item { |
342 | if self.exclude_import_kinds.contains(&ImportKind::AssociatedItem) { | 347 | if self.exclude_import_kinds.contains(&ImportKind::AssociatedItem) { |
343 | return false; | 348 | return false; |
diff --git a/crates/hir_def/src/lang_item.rs b/crates/hir_def/src/lang_item.rs index 9e90f745c..3a45cbfa1 100644 --- a/crates/hir_def/src/lang_item.rs +++ b/crates/hir_def/src/lang_item.rs | |||
@@ -141,6 +141,7 @@ impl LangItems { | |||
141 | ) where | 141 | ) where |
142 | T: Into<AttrDefId> + Copy, | 142 | T: Into<AttrDefId> + Copy, |
143 | { | 143 | { |
144 | let _p = profile::span("collect_lang_item"); | ||
144 | if let Some(lang_item_name) = lang_attr(db, item) { | 145 | if let Some(lang_item_name) = lang_attr(db, item) { |
145 | self.items.entry(lang_item_name).or_insert_with(|| constructor(item)); | 146 | self.items.entry(lang_item_name).or_insert_with(|| constructor(item)); |
146 | } | 147 | } |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index d019ba3a9..93f30f23d 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -9,6 +9,7 @@ use base_db::{CrateId, Edition, FileId, ProcMacroId}; | |||
9 | use cfg::{CfgExpr, CfgOptions}; | 9 | use cfg::{CfgExpr, CfgOptions}; |
10 | use hir_expand::{ | 10 | use hir_expand::{ |
11 | ast_id_map::FileAstId, | 11 | ast_id_map::FileAstId, |
12 | builtin_attr::find_builtin_attr, | ||
12 | builtin_derive::find_builtin_derive, | 13 | builtin_derive::find_builtin_derive, |
13 | builtin_macro::find_builtin_macro, | 14 | builtin_macro::find_builtin_macro, |
14 | name::{name, AsName, Name}, | 15 | name::{name, AsName, Name}, |
@@ -1836,7 +1837,8 @@ impl ModCollector<'_, '_> { | |||
1836 | let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into()); | 1837 | let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into()); |
1837 | if attrs.by_key("rustc_builtin_macro").exists() { | 1838 | if attrs.by_key("rustc_builtin_macro").exists() { |
1838 | let macro_id = find_builtin_macro(&mac.name, krate, ast_id) | 1839 | let macro_id = find_builtin_macro(&mac.name, krate, ast_id) |
1839 | .or_else(|| find_builtin_derive(&mac.name, krate, ast_id)); | 1840 | .or_else(|| find_builtin_derive(&mac.name, krate, ast_id)) |
1841 | .or_else(|| find_builtin_attr(&mac.name, krate, ast_id)); | ||
1840 | 1842 | ||
1841 | match macro_id { | 1843 | match macro_id { |
1842 | Some(macro_id) => { | 1844 | Some(macro_id) => { |
diff --git a/crates/hir_def/src/per_ns.rs b/crates/hir_def/src/per_ns.rs index a594afce6..a9f13cb82 100644 --- a/crates/hir_def/src/per_ns.rs +++ b/crates/hir_def/src/per_ns.rs | |||
@@ -62,6 +62,7 @@ impl PerNs { | |||
62 | } | 62 | } |
63 | 63 | ||
64 | pub fn filter_visibility(self, mut f: impl FnMut(Visibility) -> bool) -> PerNs { | 64 | pub fn filter_visibility(self, mut f: impl FnMut(Visibility) -> bool) -> PerNs { |
65 | let _p = profile::span("PerNs::filter_visibility"); | ||
65 | PerNs { | 66 | PerNs { |
66 | types: self.types.filter(|(_, v)| f(*v)), | 67 | types: self.types.filter(|(_, v)| f(*v)), |
67 | values: self.values.filter(|(_, v)| f(*v)), | 68 | values: self.values.filter(|(_, v)| f(*v)), |
@@ -86,6 +87,7 @@ impl PerNs { | |||
86 | } | 87 | } |
87 | 88 | ||
88 | pub fn iter_items(self) -> impl Iterator<Item = ItemInNs> { | 89 | pub fn iter_items(self) -> impl Iterator<Item = ItemInNs> { |
90 | let _p = profile::span("PerNs::iter_items"); | ||
89 | self.types | 91 | self.types |
90 | .map(|it| ItemInNs::Types(it.0)) | 92 | .map(|it| ItemInNs::Types(it.0)) |
91 | .into_iter() | 93 | .into_iter() |
diff --git a/crates/hir_expand/src/builtin_attr.rs b/crates/hir_expand/src/builtin_attr.rs new file mode 100644 index 000000000..c8432005e --- /dev/null +++ b/crates/hir_expand/src/builtin_attr.rs | |||
@@ -0,0 +1,67 @@ | |||
1 | //! Builtin derives. | ||
2 | |||
3 | use syntax::ast; | ||
4 | |||
5 | use crate::{db::AstDatabase, name, AstId, CrateId, MacroCallId, MacroDefId, MacroDefKind}; | ||
6 | |||
7 | macro_rules! register_builtin { | ||
8 | ( $(($name:ident, $variant:ident) => $expand:ident),* ) => { | ||
9 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
10 | pub enum BuiltinAttrExpander { | ||
11 | $($variant),* | ||
12 | } | ||
13 | |||
14 | impl BuiltinAttrExpander { | ||
15 | pub fn expand( | ||
16 | &self, | ||
17 | db: &dyn AstDatabase, | ||
18 | id: MacroCallId, | ||
19 | tt: &tt::Subtree, | ||
20 | ) -> Result<tt::Subtree, mbe::ExpandError> { | ||
21 | let expander = match *self { | ||
22 | $( BuiltinAttrExpander::$variant => $expand, )* | ||
23 | }; | ||
24 | expander(db, id, tt) | ||
25 | } | ||
26 | |||
27 | fn find_by_name(name: &name::Name) -> Option<Self> { | ||
28 | match name { | ||
29 | $( id if id == &name::name![$name] => Some(BuiltinAttrExpander::$variant), )* | ||
30 | _ => None, | ||
31 | } | ||
32 | } | ||
33 | } | ||
34 | |||
35 | }; | ||
36 | } | ||
37 | |||
38 | register_builtin! { | ||
39 | (bench, Bench) => dummy_attr_expand, | ||
40 | (cfg_accessible, CfgAccessible) => dummy_attr_expand, | ||
41 | (cfg_eval, CfgEval) => dummy_attr_expand, | ||
42 | (derive, Derive) => dummy_attr_expand, | ||
43 | (global_allocator, GlobalAllocator) => dummy_attr_expand, | ||
44 | (test, Test) => dummy_attr_expand, | ||
45 | (test_case, TestCase) => dummy_attr_expand | ||
46 | } | ||
47 | |||
48 | pub fn find_builtin_attr( | ||
49 | ident: &name::Name, | ||
50 | krate: CrateId, | ||
51 | ast_id: AstId<ast::Macro>, | ||
52 | ) -> Option<MacroDefId> { | ||
53 | let expander = BuiltinAttrExpander::find_by_name(ident)?; | ||
54 | Some(MacroDefId { | ||
55 | krate, | ||
56 | kind: MacroDefKind::BuiltInAttr(expander, ast_id), | ||
57 | local_inner: false, | ||
58 | }) | ||
59 | } | ||
60 | |||
61 | fn dummy_attr_expand( | ||
62 | _db: &dyn AstDatabase, | ||
63 | _id: MacroCallId, | ||
64 | tt: &tt::Subtree, | ||
65 | ) -> Result<tt::Subtree, mbe::ExpandError> { | ||
66 | Ok(tt.clone()) | ||
67 | } | ||
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 18a05579f..45e6e446a 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -12,9 +12,9 @@ use syntax::{ | |||
12 | }; | 12 | }; |
13 | 13 | ||
14 | use crate::{ | 14 | use crate::{ |
15 | ast_id_map::AstIdMap, hygiene::HygieneFrame, input::process_macro_input, BuiltinDeriveExpander, | 15 | ast_id_map::AstIdMap, hygiene::HygieneFrame, input::process_macro_input, BuiltinAttrExpander, |
16 | BuiltinFnLikeExpander, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind, MacroCallLoc, | 16 | BuiltinDeriveExpander, BuiltinFnLikeExpander, HirFileId, HirFileIdRepr, MacroCallId, |
17 | MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander, | 17 | MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander, |
18 | }; | 18 | }; |
19 | 19 | ||
20 | /// Total limit on the number of tokens produced by any macro invocation. | 20 | /// Total limit on the number of tokens produced by any macro invocation. |
@@ -31,6 +31,8 @@ pub enum TokenExpander { | |||
31 | MacroDef { mac: mbe::MacroDef, def_site_token_map: mbe::TokenMap }, | 31 | MacroDef { mac: mbe::MacroDef, def_site_token_map: mbe::TokenMap }, |
32 | /// Stuff like `line!` and `file!`. | 32 | /// Stuff like `line!` and `file!`. |
33 | Builtin(BuiltinFnLikeExpander), | 33 | Builtin(BuiltinFnLikeExpander), |
34 | /// `global_allocator` and such. | ||
35 | BuiltinAttr(BuiltinAttrExpander), | ||
34 | /// `derive(Copy)` and such. | 36 | /// `derive(Copy)` and such. |
35 | BuiltinDerive(BuiltinDeriveExpander), | 37 | BuiltinDerive(BuiltinDeriveExpander), |
36 | /// The thing we love the most here in rust-analyzer -- procedural macros. | 38 | /// The thing we love the most here in rust-analyzer -- procedural macros. |
@@ -49,6 +51,7 @@ impl TokenExpander { | |||
49 | TokenExpander::MacroDef { mac, .. } => mac.expand(tt), | 51 | TokenExpander::MacroDef { mac, .. } => mac.expand(tt), |
50 | TokenExpander::Builtin(it) => it.expand(db, id, tt), | 52 | TokenExpander::Builtin(it) => it.expand(db, id, tt), |
51 | // FIXME switch these to ExpandResult as well | 53 | // FIXME switch these to ExpandResult as well |
54 | TokenExpander::BuiltinAttr(it) => it.expand(db, id, tt).into(), | ||
52 | TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(), | 55 | TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(), |
53 | TokenExpander::ProcMacro(_) => { | 56 | TokenExpander::ProcMacro(_) => { |
54 | // We store the result in salsa db to prevent non-deterministic behavior in | 57 | // We store the result in salsa db to prevent non-deterministic behavior in |
@@ -64,6 +67,7 @@ impl TokenExpander { | |||
64 | TokenExpander::MacroRules { mac, .. } => mac.map_id_down(id), | 67 | TokenExpander::MacroRules { mac, .. } => mac.map_id_down(id), |
65 | TokenExpander::MacroDef { mac, .. } => mac.map_id_down(id), | 68 | TokenExpander::MacroDef { mac, .. } => mac.map_id_down(id), |
66 | TokenExpander::Builtin(..) | 69 | TokenExpander::Builtin(..) |
70 | | TokenExpander::BuiltinAttr(..) | ||
67 | | TokenExpander::BuiltinDerive(..) | 71 | | TokenExpander::BuiltinDerive(..) |
68 | | TokenExpander::ProcMacro(..) => id, | 72 | | TokenExpander::ProcMacro(..) => id, |
69 | } | 73 | } |
@@ -74,6 +78,7 @@ impl TokenExpander { | |||
74 | TokenExpander::MacroRules { mac, .. } => mac.map_id_up(id), | 78 | TokenExpander::MacroRules { mac, .. } => mac.map_id_up(id), |
75 | TokenExpander::MacroDef { mac, .. } => mac.map_id_up(id), | 79 | TokenExpander::MacroDef { mac, .. } => mac.map_id_up(id), |
76 | TokenExpander::Builtin(..) | 80 | TokenExpander::Builtin(..) |
81 | | TokenExpander::BuiltinAttr(..) | ||
77 | | TokenExpander::BuiltinDerive(..) | 82 | | TokenExpander::BuiltinDerive(..) |
78 | | TokenExpander::ProcMacro(..) => (id, mbe::Origin::Call), | 83 | | TokenExpander::ProcMacro(..) => (id, mbe::Origin::Call), |
79 | } | 84 | } |
@@ -299,6 +304,9 @@ fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<TokenExpander>> | |||
299 | } | 304 | } |
300 | }, | 305 | }, |
301 | MacroDefKind::BuiltIn(expander, _) => Some(Arc::new(TokenExpander::Builtin(expander))), | 306 | MacroDefKind::BuiltIn(expander, _) => Some(Arc::new(TokenExpander::Builtin(expander))), |
307 | MacroDefKind::BuiltInAttr(expander, _) => { | ||
308 | Some(Arc::new(TokenExpander::BuiltinAttr(expander))) | ||
309 | } | ||
302 | MacroDefKind::BuiltInDerive(expander, _) => { | 310 | MacroDefKind::BuiltInDerive(expander, _) => { |
303 | Some(Arc::new(TokenExpander::BuiltinDerive(expander))) | 311 | Some(Arc::new(TokenExpander::BuiltinDerive(expander))) |
304 | } | 312 | } |
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs index 14af628a1..9093255f4 100644 --- a/crates/hir_expand/src/eager.rs +++ b/crates/hir_expand/src/eager.rs | |||
@@ -224,6 +224,7 @@ fn eager_macro_recur( | |||
224 | } | 224 | } |
225 | MacroDefKind::Declarative(_) | 225 | MacroDefKind::Declarative(_) |
226 | | MacroDefKind::BuiltIn(..) | 226 | | MacroDefKind::BuiltIn(..) |
227 | | MacroDefKind::BuiltInAttr(..) | ||
227 | | MacroDefKind::BuiltInDerive(..) | 228 | | MacroDefKind::BuiltInDerive(..) |
228 | | MacroDefKind::ProcMacro(..) => { | 229 | | MacroDefKind::ProcMacro(..) => { |
229 | let res = lazy_expand(db, &def, curr.with_value(child.clone()), krate); | 230 | let res = lazy_expand(db, &def, curr.with_value(child.clone()), krate); |
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs index d98913907..05c6c3fb1 100644 --- a/crates/hir_expand/src/hygiene.rs +++ b/crates/hir_expand/src/hygiene.rs | |||
@@ -192,6 +192,7 @@ impl HygieneFrame { | |||
192 | (info, Some(loc.def.krate), loc.def.local_inner) | 192 | (info, Some(loc.def.krate), loc.def.local_inner) |
193 | } | 193 | } |
194 | MacroDefKind::BuiltIn(..) => (info, Some(loc.def.krate), false), | 194 | MacroDefKind::BuiltIn(..) => (info, Some(loc.def.krate), false), |
195 | MacroDefKind::BuiltInAttr(..) => (info, None, false), | ||
195 | MacroDefKind::BuiltInDerive(..) => (info, None, false), | 196 | MacroDefKind::BuiltInDerive(..) => (info, None, false), |
196 | MacroDefKind::BuiltInEager(..) => (info, None, false), | 197 | MacroDefKind::BuiltInEager(..) => (info, None, false), |
197 | MacroDefKind::ProcMacro(..) => (info, None, false), | 198 | MacroDefKind::ProcMacro(..) => (info, None, false), |
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index 618f26b95..623791b58 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs | |||
@@ -8,6 +8,7 @@ pub mod db; | |||
8 | pub mod ast_id_map; | 8 | pub mod ast_id_map; |
9 | pub mod name; | 9 | pub mod name; |
10 | pub mod hygiene; | 10 | pub mod hygiene; |
11 | pub mod builtin_attr; | ||
11 | pub mod builtin_derive; | 12 | pub mod builtin_derive; |
12 | pub mod builtin_macro; | 13 | pub mod builtin_macro; |
13 | pub mod proc_macro; | 14 | pub mod proc_macro; |
@@ -32,6 +33,7 @@ use syntax::{ | |||
32 | }; | 33 | }; |
33 | 34 | ||
34 | use crate::ast_id_map::FileAstId; | 35 | use crate::ast_id_map::FileAstId; |
36 | use crate::builtin_attr::BuiltinAttrExpander; | ||
35 | use crate::builtin_derive::BuiltinDeriveExpander; | 37 | use crate::builtin_derive::BuiltinDeriveExpander; |
36 | use crate::builtin_macro::{BuiltinFnLikeExpander, EagerExpander}; | 38 | use crate::builtin_macro::{BuiltinFnLikeExpander, EagerExpander}; |
37 | use crate::proc_macro::ProcMacroExpander; | 39 | use crate::proc_macro::ProcMacroExpander; |
@@ -206,6 +208,7 @@ impl MacroDefId { | |||
206 | let id = match &self.kind { | 208 | let id = match &self.kind { |
207 | MacroDefKind::Declarative(id) => id, | 209 | MacroDefKind::Declarative(id) => id, |
208 | MacroDefKind::BuiltIn(_, id) => id, | 210 | MacroDefKind::BuiltIn(_, id) => id, |
211 | MacroDefKind::BuiltInAttr(_, id) => id, | ||
209 | MacroDefKind::BuiltInDerive(_, id) => id, | 212 | MacroDefKind::BuiltInDerive(_, id) => id, |
210 | MacroDefKind::BuiltInEager(_, id) => id, | 213 | MacroDefKind::BuiltInEager(_, id) => id, |
211 | MacroDefKind::ProcMacro(.., id) => return Either::Right(*id), | 214 | MacroDefKind::ProcMacro(.., id) => return Either::Right(*id), |
@@ -223,6 +226,7 @@ pub enum MacroDefKind { | |||
223 | Declarative(AstId<ast::Macro>), | 226 | Declarative(AstId<ast::Macro>), |
224 | BuiltIn(BuiltinFnLikeExpander, AstId<ast::Macro>), | 227 | BuiltIn(BuiltinFnLikeExpander, AstId<ast::Macro>), |
225 | // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander | 228 | // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander |
229 | BuiltInAttr(BuiltinAttrExpander, AstId<ast::Macro>), | ||
226 | BuiltInDerive(BuiltinDeriveExpander, AstId<ast::Macro>), | 230 | BuiltInDerive(BuiltinDeriveExpander, AstId<ast::Macro>), |
227 | BuiltInEager(EagerExpander, AstId<ast::Macro>), | 231 | BuiltInEager(EagerExpander, AstId<ast::Macro>), |
228 | ProcMacro(ProcMacroExpander, ProcMacroKind, AstId<ast::Fn>), | 232 | ProcMacro(ProcMacroExpander, ProcMacroKind, AstId<ast::Fn>), |
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs index 00b8adc1e..376fe130f 100644 --- a/crates/hir_expand/src/name.rs +++ b/crates/hir_expand/src/name.rs | |||
@@ -160,7 +160,6 @@ pub mod known { | |||
160 | str, | 160 | str, |
161 | // Special names | 161 | // Special names |
162 | macro_rules, | 162 | macro_rules, |
163 | derive, | ||
164 | doc, | 163 | doc, |
165 | cfg, | 164 | cfg, |
166 | cfg_attr, | 165 | cfg_attr, |
@@ -240,6 +239,14 @@ pub mod known { | |||
240 | PartialOrd, | 239 | PartialOrd, |
241 | Eq, | 240 | Eq, |
242 | PartialEq, | 241 | PartialEq, |
242 | // Builtin attributes | ||
243 | bench, | ||
244 | cfg_accessible, | ||
245 | cfg_eval, | ||
246 | derive, | ||
247 | global_allocator, | ||
248 | test, | ||
249 | test_case, | ||
243 | // Safe intrinsics | 250 | // Safe intrinsics |
244 | abort, | 251 | abort, |
245 | size_of, | 252 | size_of, |
diff --git a/crates/ide/src/prime_caches.rs b/crates/ide/src/prime_caches.rs index d912a01b8..36801c964 100644 --- a/crates/ide/src/prime_caches.rs +++ b/crates/ide/src/prime_caches.rs | |||
@@ -33,14 +33,15 @@ pub(crate) fn prime_caches(db: &RootDatabase, cb: &(dyn Fn(PrimeCachesProgress) | |||
33 | // FIXME: This would be easy to parallelize, since it's in the ideal ordering for that. | 33 | // FIXME: This would be easy to parallelize, since it's in the ideal ordering for that. |
34 | // Unfortunately rayon prevents panics from propagation out of a `scope`, which breaks | 34 | // Unfortunately rayon prevents panics from propagation out of a `scope`, which breaks |
35 | // cancellation, so we cannot use rayon. | 35 | // cancellation, so we cannot use rayon. |
36 | for (i, krate) in topo.iter().enumerate() { | 36 | for (i, &crate_id) in topo.iter().enumerate() { |
37 | let crate_name = graph[*krate].display_name.as_deref().unwrap_or_default().to_string(); | 37 | let crate_name = graph[crate_id].display_name.as_deref().unwrap_or_default().to_string(); |
38 | 38 | ||
39 | cb(PrimeCachesProgress::StartedOnCrate { | 39 | cb(PrimeCachesProgress::StartedOnCrate { |
40 | on_crate: crate_name, | 40 | on_crate: crate_name, |
41 | n_done: i, | 41 | n_done: i, |
42 | n_total: topo.len(), | 42 | n_total: topo.len(), |
43 | }); | 43 | }); |
44 | db.crate_def_map(*krate); | 44 | db.crate_def_map(crate_id); |
45 | db.import_map(crate_id); | ||
45 | } | 46 | } |
46 | } | 47 | } |
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index ae492a264..f8b64a669 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs | |||
@@ -1380,4 +1380,24 @@ lib::foo!(); | |||
1380 | "#]], | 1380 | "#]], |
1381 | ); | 1381 | ); |
1382 | } | 1382 | } |
1383 | |||
1384 | #[test] | ||
1385 | fn macro_doesnt_reference_attribute_on_call() { | ||
1386 | check( | ||
1387 | r#" | ||
1388 | macro_rules! m { | ||
1389 | () => {}; | ||
1390 | } | ||
1391 | |||
1392 | #[proc_macro_test::attr_noop] | ||
1393 | m$0!(); | ||
1394 | |||
1395 | "#, | ||
1396 | expect![[r#" | ||
1397 | m Macro FileId(0) 0..32 13..14 | ||
1398 | |||
1399 | FileId(0) 64..65 | ||
1400 | "#]], | ||
1401 | ); | ||
1402 | } | ||
1383 | } | 1403 | } |
diff --git a/crates/ide_assists/src/handlers/remove_unused_param.rs b/crates/ide_assists/src/handlers/remove_unused_param.rs index 2699d2861..fabfe7e93 100644 --- a/crates/ide_assists/src/handlers/remove_unused_param.rs +++ b/crates/ide_assists/src/handlers/remove_unused_param.rs | |||
@@ -37,8 +37,20 @@ pub(crate) fn remove_unused_param(acc: &mut Assists, ctx: &AssistContext) -> Opt | |||
37 | _ => return None, | 37 | _ => return None, |
38 | }; | 38 | }; |
39 | let func = param.syntax().ancestors().find_map(ast::Fn::cast)?; | 39 | let func = param.syntax().ancestors().find_map(ast::Fn::cast)?; |
40 | let param_position = func.param_list()?.params().position(|it| it == param)?; | ||
41 | 40 | ||
41 | // check if fn is in impl Trait for .. | ||
42 | if func | ||
43 | .syntax() | ||
44 | .parent() // AssocItemList | ||
45 | .and_then(|x| x.parent()) | ||
46 | .and_then(ast::Impl::cast) | ||
47 | .map_or(false, |imp| imp.trait_().is_some()) | ||
48 | { | ||
49 | cov_mark::hit!(trait_impl); | ||
50 | return None; | ||
51 | } | ||
52 | |||
53 | let param_position = func.param_list()?.params().position(|it| it == param)?; | ||
42 | let fn_def = { | 54 | let fn_def = { |
43 | let func = ctx.sema.to_def(&func)?; | 55 | let func = ctx.sema.to_def(&func)?; |
44 | Definition::ModuleDef(func.into()) | 56 | Definition::ModuleDef(func.into()) |
@@ -254,6 +266,22 @@ fn main() { foo(9, 2) } | |||
254 | } | 266 | } |
255 | 267 | ||
256 | #[test] | 268 | #[test] |
269 | fn trait_impl() { | ||
270 | cov_mark::check!(trait_impl); | ||
271 | check_assist_not_applicable( | ||
272 | remove_unused_param, | ||
273 | r#" | ||
274 | trait Trait { | ||
275 | fn foo(x: i32); | ||
276 | } | ||
277 | impl Trait for () { | ||
278 | fn foo($0x: i32) {} | ||
279 | } | ||
280 | "#, | ||
281 | ); | ||
282 | } | ||
283 | |||
284 | #[test] | ||
257 | fn remove_across_files() { | 285 | fn remove_across_files() { |
258 | check_assist( | 286 | check_assist( |
259 | remove_unused_param, | 287 | remove_unused_param, |
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index 0b0a81410..58d4dd9ee 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs | |||
@@ -657,6 +657,32 @@ fn main() { let _ = crate::$0 } | |||
657 | } | 657 | } |
658 | 658 | ||
659 | #[test] | 659 | #[test] |
660 | fn does_not_complete_non_fn_macros() { | ||
661 | check( | ||
662 | r#" | ||
663 | mod m { | ||
664 | #[rustc_builtin_macro] | ||
665 | pub macro Clone {} | ||
666 | } | ||
667 | |||
668 | fn f() {m::$0} | ||
669 | "#, | ||
670 | expect![[r#""#]], | ||
671 | ); | ||
672 | check( | ||
673 | r#" | ||
674 | mod m { | ||
675 | #[rustc_builtin_macro] | ||
676 | pub macro bench {} | ||
677 | } | ||
678 | |||
679 | fn f() {m::$0} | ||
680 | "#, | ||
681 | expect![[r#""#]], | ||
682 | ); | ||
683 | } | ||
684 | |||
685 | #[test] | ||
660 | fn completes_in_assoc_item_list() { | 686 | fn completes_in_assoc_item_list() { |
661 | check( | 687 | check( |
662 | r#" | 688 | r#" |
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 1f6c4069f..b1e6b2b77 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs | |||
@@ -481,14 +481,14 @@ impl S { | |||
481 | ); | 481 | ); |
482 | check( | 482 | check( |
483 | r#" | 483 | r#" |
484 | mod m { | 484 | #[rustc_builtin_macro] |
485 | #[rustc_builtin_macro] | 485 | pub macro bench {} |
486 | pub macro Clone {} | ||
487 | } | ||
488 | 486 | ||
489 | fn f() {m::$0} | 487 | fn f() {$0} |
490 | "#, | 488 | "#, |
491 | expect![[r#""#]], | 489 | expect![[r#" |
490 | fn f() fn() | ||
491 | "#]], | ||
492 | ); | 492 | ); |
493 | } | 493 | } |
494 | 494 | ||
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index 7118183fe..902df46ca 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs | |||
@@ -24,34 +24,34 @@ use crate::{ | |||
24 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, | 24 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, |
25 | }; | 25 | }; |
26 | 26 | ||
27 | pub(crate) fn render_field<'a>( | 27 | pub(crate) fn render_field( |
28 | ctx: RenderContext<'a>, | 28 | ctx: RenderContext<'_>, |
29 | receiver: Option<hir::Name>, | 29 | receiver: Option<hir::Name>, |
30 | field: hir::Field, | 30 | field: hir::Field, |
31 | ty: &hir::Type, | 31 | ty: &hir::Type, |
32 | ) -> CompletionItem { | 32 | ) -> CompletionItem { |
33 | Render::new(ctx).render_field(receiver, field, ty) | 33 | render_field_(ctx, receiver, field, ty) |
34 | } | 34 | } |
35 | 35 | ||
36 | pub(crate) fn render_tuple_field<'a>( | 36 | pub(crate) fn render_tuple_field( |
37 | ctx: RenderContext<'a>, | 37 | ctx: RenderContext<'_>, |
38 | receiver: Option<hir::Name>, | 38 | receiver: Option<hir::Name>, |
39 | field: usize, | 39 | field: usize, |
40 | ty: &hir::Type, | 40 | ty: &hir::Type, |
41 | ) -> CompletionItem { | 41 | ) -> CompletionItem { |
42 | Render::new(ctx).render_tuple_field(receiver, field, ty) | 42 | render_tuple_field_(ctx, receiver, field, ty) |
43 | } | 43 | } |
44 | 44 | ||
45 | pub(crate) fn render_resolution<'a>( | 45 | pub(crate) fn render_resolution( |
46 | ctx: RenderContext<'a>, | 46 | ctx: RenderContext<'_>, |
47 | local_name: hir::Name, | 47 | local_name: hir::Name, |
48 | resolution: &hir::ScopeDef, | 48 | resolution: &hir::ScopeDef, |
49 | ) -> Option<CompletionItem> { | 49 | ) -> Option<CompletionItem> { |
50 | Render::new(ctx).render_resolution(local_name, None, resolution) | 50 | render_resolution_(ctx, local_name, None, resolution) |
51 | } | 51 | } |
52 | 52 | ||
53 | pub(crate) fn render_resolution_with_import<'a>( | 53 | pub(crate) fn render_resolution_with_import( |
54 | ctx: RenderContext<'a>, | 54 | ctx: RenderContext<'_>, |
55 | import_edit: ImportEdit, | 55 | import_edit: ImportEdit, |
56 | ) -> Option<CompletionItem> { | 56 | ) -> Option<CompletionItem> { |
57 | let resolution = hir::ScopeDef::from(import_edit.import.original_item); | 57 | let resolution = hir::ScopeDef::from(import_edit.import.original_item); |
@@ -64,12 +64,10 @@ pub(crate) fn render_resolution_with_import<'a>( | |||
64 | hir::ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db), | 64 | hir::ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db), |
65 | _ => item_name(ctx.db(), import_edit.import.original_item)?, | 65 | _ => item_name(ctx.db(), import_edit.import.original_item)?, |
66 | }; | 66 | }; |
67 | Render::new(ctx).render_resolution(local_name, Some(import_edit), &resolution).map( | 67 | render_resolution_(ctx, local_name, Some(import_edit), &resolution).map(|mut item| { |
68 | |mut item| { | 68 | item.completion_kind = CompletionKind::Magic; |
69 | item.completion_kind = CompletionKind::Magic; | 69 | item |
70 | item | 70 | }) |
71 | }, | ||
72 | ) | ||
73 | } | 71 | } |
74 | 72 | ||
75 | /// Interface for data and methods required for items rendering. | 73 | /// Interface for data and methods required for items rendering. |
@@ -121,216 +119,188 @@ impl<'a> RenderContext<'a> { | |||
121 | } | 119 | } |
122 | } | 120 | } |
123 | 121 | ||
124 | /// Generic renderer for completion items. | 122 | fn render_field_( |
125 | #[derive(Debug)] | 123 | ctx: RenderContext<'_>, |
126 | struct Render<'a> { | 124 | receiver: Option<hir::Name>, |
127 | ctx: RenderContext<'a>, | 125 | field: hir::Field, |
128 | } | 126 | ty: &hir::Type, |
129 | 127 | ) -> CompletionItem { | |
130 | impl<'a> Render<'a> { | 128 | let is_deprecated = ctx.is_deprecated(field); |
131 | fn new(ctx: RenderContext<'a>) -> Render<'a> { | 129 | let name = field.name(ctx.db()).to_string(); |
132 | Render { ctx } | 130 | let mut item = CompletionItem::new( |
131 | CompletionKind::Reference, | ||
132 | ctx.source_range(), | ||
133 | receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)), | ||
134 | ); | ||
135 | item.kind(SymbolKind::Field) | ||
136 | .detail(ty.display(ctx.db()).to_string()) | ||
137 | .set_documentation(field.docs(ctx.db())) | ||
138 | .set_deprecated(is_deprecated); | ||
139 | |||
140 | item.set_relevance(CompletionRelevance { | ||
141 | type_match: compute_type_match(ctx.completion, ty), | ||
142 | exact_name_match: compute_exact_name_match(ctx.completion, &name), | ||
143 | ..CompletionRelevance::default() | ||
144 | }); | ||
145 | |||
146 | if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) { | ||
147 | // FIXME | ||
148 | // For now we don't properly calculate the edits for ref match | ||
149 | // completions on struct fields, so we've disabled them. See #8058. | ||
133 | } | 150 | } |
134 | 151 | ||
135 | fn render_field( | 152 | item.build() |
136 | &self, | 153 | } |
137 | receiver: Option<hir::Name>, | ||
138 | field: hir::Field, | ||
139 | ty: &hir::Type, | ||
140 | ) -> CompletionItem { | ||
141 | let is_deprecated = self.ctx.is_deprecated(field); | ||
142 | let name = field.name(self.ctx.db()).to_string(); | ||
143 | let mut item = CompletionItem::new( | ||
144 | CompletionKind::Reference, | ||
145 | self.ctx.source_range(), | ||
146 | receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)), | ||
147 | ); | ||
148 | item.kind(SymbolKind::Field) | ||
149 | .detail(ty.display(self.ctx.db()).to_string()) | ||
150 | .set_documentation(field.docs(self.ctx.db())) | ||
151 | .set_deprecated(is_deprecated); | ||
152 | |||
153 | item.set_relevance(CompletionRelevance { | ||
154 | type_match: compute_type_match(self.ctx.completion, ty), | ||
155 | exact_name_match: compute_exact_name_match(self.ctx.completion, &name), | ||
156 | ..CompletionRelevance::default() | ||
157 | }); | ||
158 | |||
159 | if let Some(_ref_match) = compute_ref_match(self.ctx.completion, ty) { | ||
160 | // FIXME | ||
161 | // For now we don't properly calculate the edits for ref match | ||
162 | // completions on struct fields, so we've disabled them. See #8058. | ||
163 | } | ||
164 | 154 | ||
165 | item.build() | 155 | fn render_tuple_field_( |
166 | } | 156 | ctx: RenderContext<'_>, |
157 | receiver: Option<hir::Name>, | ||
158 | field: usize, | ||
159 | ty: &hir::Type, | ||
160 | ) -> CompletionItem { | ||
161 | let mut item = CompletionItem::new( | ||
162 | CompletionKind::Reference, | ||
163 | ctx.source_range(), | ||
164 | receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)), | ||
165 | ); | ||
167 | 166 | ||
168 | fn render_tuple_field( | 167 | item.kind(SymbolKind::Field).detail(ty.display(ctx.db()).to_string()); |
169 | &self, | ||
170 | receiver: Option<hir::Name>, | ||
171 | field: usize, | ||
172 | ty: &hir::Type, | ||
173 | ) -> CompletionItem { | ||
174 | let mut item = CompletionItem::new( | ||
175 | CompletionKind::Reference, | ||
176 | self.ctx.source_range(), | ||
177 | receiver | ||
178 | .map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)), | ||
179 | ); | ||
180 | 168 | ||
181 | item.kind(SymbolKind::Field).detail(ty.display(self.ctx.db()).to_string()); | 169 | item.build() |
170 | } | ||
182 | 171 | ||
183 | item.build() | 172 | fn render_resolution_( |
184 | } | 173 | ctx: RenderContext<'_>, |
174 | local_name: hir::Name, | ||
175 | import_to_add: Option<ImportEdit>, | ||
176 | resolution: &hir::ScopeDef, | ||
177 | ) -> Option<CompletionItem> { | ||
178 | let _p = profile::span("render_resolution"); | ||
179 | use hir::ModuleDef::*; | ||
185 | 180 | ||
186 | fn render_resolution( | 181 | let completion_kind = match resolution { |
187 | self, | 182 | hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType, |
188 | local_name: hir::Name, | 183 | _ => CompletionKind::Reference, |
189 | import_to_add: Option<ImportEdit>, | 184 | }; |
190 | resolution: &hir::ScopeDef, | ||
191 | ) -> Option<CompletionItem> { | ||
192 | let _p = profile::span("render_resolution"); | ||
193 | use hir::ModuleDef::*; | ||
194 | |||
195 | let completion_kind = match resolution { | ||
196 | hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType, | ||
197 | _ => CompletionKind::Reference, | ||
198 | }; | ||
199 | 185 | ||
200 | let kind = match resolution { | 186 | let kind = match resolution { |
201 | hir::ScopeDef::ModuleDef(Function(func)) => { | 187 | hir::ScopeDef::ModuleDef(Function(func)) => { |
202 | return render_fn(self.ctx, import_to_add, Some(local_name), *func); | 188 | return render_fn(ctx, import_to_add, Some(local_name), *func); |
203 | } | 189 | } |
204 | hir::ScopeDef::ModuleDef(Variant(_)) | 190 | hir::ScopeDef::ModuleDef(Variant(_)) if ctx.completion.is_pat_or_const.is_some() => { |
205 | if self.ctx.completion.is_pat_or_const.is_some() => | 191 | CompletionItemKind::SymbolKind(SymbolKind::Variant) |
206 | { | 192 | } |
207 | CompletionItemKind::SymbolKind(SymbolKind::Variant) | 193 | hir::ScopeDef::ModuleDef(Variant(var)) => { |
208 | } | 194 | let item = render_variant(ctx, import_to_add, Some(local_name), *var, None); |
209 | hir::ScopeDef::ModuleDef(Variant(var)) => { | 195 | return Some(item); |
210 | let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None); | 196 | } |
211 | return Some(item); | 197 | hir::ScopeDef::MacroDef(mac) => { |
212 | } | 198 | let item = render_macro(ctx, import_to_add, local_name, *mac); |
213 | hir::ScopeDef::MacroDef(mac) => { | 199 | return item; |
214 | let item = render_macro(self.ctx, import_to_add, local_name, *mac); | 200 | } |
215 | return item; | ||
216 | } | ||
217 | 201 | ||
218 | hir::ScopeDef::ModuleDef(Module(..)) => { | 202 | hir::ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module), |
219 | CompletionItemKind::SymbolKind(SymbolKind::Module) | 203 | hir::ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt { |
220 | } | 204 | hir::Adt::Struct(_) => SymbolKind::Struct, |
221 | hir::ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt { | 205 | hir::Adt::Union(_) => SymbolKind::Union, |
222 | hir::Adt::Struct(_) => SymbolKind::Struct, | 206 | hir::Adt::Enum(_) => SymbolKind::Enum, |
223 | hir::Adt::Union(_) => SymbolKind::Union, | 207 | }), |
224 | hir::Adt::Enum(_) => SymbolKind::Enum, | 208 | hir::ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const), |
225 | }), | 209 | hir::ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::SymbolKind(SymbolKind::Static), |
226 | hir::ScopeDef::ModuleDef(Const(..)) => { | 210 | hir::ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::SymbolKind(SymbolKind::Trait), |
227 | CompletionItemKind::SymbolKind(SymbolKind::Const) | 211 | hir::ScopeDef::ModuleDef(TypeAlias(..)) => { |
228 | } | 212 | CompletionItemKind::SymbolKind(SymbolKind::TypeAlias) |
229 | hir::ScopeDef::ModuleDef(Static(..)) => { | 213 | } |
230 | CompletionItemKind::SymbolKind(SymbolKind::Static) | 214 | hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType, |
231 | } | 215 | hir::ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param { |
232 | hir::ScopeDef::ModuleDef(Trait(..)) => { | 216 | hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam, |
233 | CompletionItemKind::SymbolKind(SymbolKind::Trait) | 217 | hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam, |
234 | } | 218 | hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam, |
235 | hir::ScopeDef::ModuleDef(TypeAlias(..)) => { | 219 | }), |
236 | CompletionItemKind::SymbolKind(SymbolKind::TypeAlias) | 220 | hir::ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local), |
237 | } | 221 | hir::ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label), |
238 | hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType, | 222 | hir::ScopeDef::AdtSelfType(..) | hir::ScopeDef::ImplSelfType(..) => { |
239 | hir::ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param { | 223 | CompletionItemKind::SymbolKind(SymbolKind::SelfParam) |
240 | hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam, | 224 | } |
241 | hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam, | 225 | hir::ScopeDef::Unknown => { |
242 | hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam, | 226 | let mut item = CompletionItem::new( |
243 | }), | 227 | CompletionKind::Reference, |
244 | hir::ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local), | 228 | ctx.source_range(), |
245 | hir::ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label), | 229 | local_name.to_string(), |
246 | hir::ScopeDef::AdtSelfType(..) | hir::ScopeDef::ImplSelfType(..) => { | 230 | ); |
247 | CompletionItemKind::SymbolKind(SymbolKind::SelfParam) | 231 | item.kind(CompletionItemKind::UnresolvedReference).add_import(import_to_add); |
248 | } | 232 | return Some(item.build()); |
249 | hir::ScopeDef::Unknown => { | 233 | } |
250 | let mut item = CompletionItem::new( | 234 | }; |
251 | CompletionKind::Reference, | ||
252 | self.ctx.source_range(), | ||
253 | local_name.to_string(), | ||
254 | ); | ||
255 | item.kind(CompletionItemKind::UnresolvedReference).add_import(import_to_add); | ||
256 | return Some(item.build()); | ||
257 | } | ||
258 | }; | ||
259 | 235 | ||
260 | let local_name = local_name.to_string(); | 236 | let local_name = local_name.to_string(); |
261 | let mut item = | 237 | let mut item = CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone()); |
262 | CompletionItem::new(completion_kind, self.ctx.source_range(), local_name.clone()); | 238 | if let hir::ScopeDef::Local(local) = resolution { |
263 | if let hir::ScopeDef::Local(local) = resolution { | 239 | let ty = local.ty(ctx.db()); |
264 | let ty = local.ty(self.ctx.db()); | 240 | if !ty.is_unknown() { |
265 | if !ty.is_unknown() { | 241 | item.detail(ty.display(ctx.db()).to_string()); |
266 | item.detail(ty.display(self.ctx.db()).to_string()); | 242 | } |
267 | } | ||
268 | 243 | ||
269 | item.set_relevance(CompletionRelevance { | 244 | item.set_relevance(CompletionRelevance { |
270 | type_match: compute_type_match(self.ctx.completion, &ty), | 245 | type_match: compute_type_match(ctx.completion, &ty), |
271 | exact_name_match: compute_exact_name_match(self.ctx.completion, &local_name), | 246 | exact_name_match: compute_exact_name_match(ctx.completion, &local_name), |
272 | is_local: true, | 247 | is_local: true, |
273 | ..CompletionRelevance::default() | 248 | ..CompletionRelevance::default() |
274 | }); | 249 | }); |
275 | 250 | ||
276 | if let Some(ref_match) = compute_ref_match(self.ctx.completion, &ty) { | 251 | if let Some(ref_match) = compute_ref_match(ctx.completion, &ty) { |
277 | item.ref_match(ref_match); | 252 | item.ref_match(ref_match); |
278 | } | 253 | } |
279 | }; | 254 | }; |
280 | 255 | ||
281 | // Add `<>` for generic types | 256 | // Add `<>` for generic types |
282 | if matches!( | 257 | if matches!( |
283 | self.ctx.completion.path_context, | 258 | ctx.completion.path_context, |
284 | Some(PathCompletionContext { kind: Some(PathKind::Type), has_type_args: false, .. }) | 259 | Some(PathCompletionContext { kind: Some(PathKind::Type), has_type_args: false, .. }) |
285 | ) && self.ctx.completion.config.add_call_parenthesis | 260 | ) && ctx.completion.config.add_call_parenthesis |
286 | { | 261 | { |
287 | if let Some(cap) = self.ctx.snippet_cap() { | 262 | if let Some(cap) = ctx.snippet_cap() { |
288 | let has_non_default_type_params = match resolution { | 263 | let has_non_default_type_params = match resolution { |
289 | hir::ScopeDef::ModuleDef(Adt(it)) => { | 264 | hir::ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db()), |
290 | it.has_non_default_type_params(self.ctx.db()) | 265 | hir::ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db()), |
291 | } | 266 | _ => false, |
292 | hir::ScopeDef::ModuleDef(TypeAlias(it)) => { | 267 | }; |
293 | it.has_non_default_type_params(self.ctx.db()) | 268 | if has_non_default_type_params { |
294 | } | 269 | cov_mark::hit!(inserts_angle_brackets_for_generics); |
295 | _ => false, | 270 | item.lookup_by(local_name.clone()) |
296 | }; | 271 | .label(format!("{}<…>", local_name)) |
297 | if has_non_default_type_params { | 272 | .insert_snippet(cap, format!("{}<$0>", local_name)); |
298 | cov_mark::hit!(inserts_angle_brackets_for_generics); | ||
299 | item.lookup_by(local_name.clone()) | ||
300 | .label(format!("{}<…>", local_name)) | ||
301 | .insert_snippet(cap, format!("{}<$0>", local_name)); | ||
302 | } | ||
303 | } | 273 | } |
304 | } | 274 | } |
305 | item.kind(kind) | ||
306 | .add_import(import_to_add) | ||
307 | .set_documentation(self.docs(resolution)) | ||
308 | .set_deprecated(self.is_deprecated(resolution)); | ||
309 | Some(item.build()) | ||
310 | } | 275 | } |
276 | item.kind(kind) | ||
277 | .add_import(import_to_add) | ||
278 | .set_documentation(scope_def_docs(ctx.db(), resolution)) | ||
279 | .set_deprecated(scope_def_is_deprecated(&ctx, resolution)); | ||
280 | Some(item.build()) | ||
281 | } | ||
311 | 282 | ||
312 | fn docs(&self, resolution: &hir::ScopeDef) -> Option<hir::Documentation> { | 283 | fn scope_def_docs(db: &RootDatabase, resolution: &hir::ScopeDef) -> Option<hir::Documentation> { |
313 | use hir::ModuleDef::*; | 284 | use hir::ModuleDef::*; |
314 | match resolution { | 285 | match resolution { |
315 | hir::ScopeDef::ModuleDef(Module(it)) => it.docs(self.ctx.db()), | 286 | hir::ScopeDef::ModuleDef(Module(it)) => it.docs(db), |
316 | hir::ScopeDef::ModuleDef(Adt(it)) => it.docs(self.ctx.db()), | 287 | hir::ScopeDef::ModuleDef(Adt(it)) => it.docs(db), |
317 | hir::ScopeDef::ModuleDef(Variant(it)) => it.docs(self.ctx.db()), | 288 | hir::ScopeDef::ModuleDef(Variant(it)) => it.docs(db), |
318 | hir::ScopeDef::ModuleDef(Const(it)) => it.docs(self.ctx.db()), | 289 | hir::ScopeDef::ModuleDef(Const(it)) => it.docs(db), |
319 | hir::ScopeDef::ModuleDef(Static(it)) => it.docs(self.ctx.db()), | 290 | hir::ScopeDef::ModuleDef(Static(it)) => it.docs(db), |
320 | hir::ScopeDef::ModuleDef(Trait(it)) => it.docs(self.ctx.db()), | 291 | hir::ScopeDef::ModuleDef(Trait(it)) => it.docs(db), |
321 | hir::ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(self.ctx.db()), | 292 | hir::ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(db), |
322 | _ => None, | 293 | _ => None, |
323 | } | ||
324 | } | 294 | } |
295 | } | ||
325 | 296 | ||
326 | fn is_deprecated(&self, resolution: &hir::ScopeDef) -> bool { | 297 | fn scope_def_is_deprecated(ctx: &RenderContext<'_>, resolution: &hir::ScopeDef) -> bool { |
327 | match resolution { | 298 | match resolution { |
328 | hir::ScopeDef::ModuleDef(it) => self.ctx.is_deprecated_assoc_item(*it), | 299 | hir::ScopeDef::ModuleDef(it) => ctx.is_deprecated_assoc_item(*it), |
329 | hir::ScopeDef::MacroDef(it) => self.ctx.is_deprecated(*it), | 300 | hir::ScopeDef::MacroDef(it) => ctx.is_deprecated(*it), |
330 | hir::ScopeDef::GenericParam(it) => self.ctx.is_deprecated(*it), | 301 | hir::ScopeDef::GenericParam(it) => ctx.is_deprecated(*it), |
331 | hir::ScopeDef::AdtSelfType(it) => self.ctx.is_deprecated(*it), | 302 | hir::ScopeDef::AdtSelfType(it) => ctx.is_deprecated(*it), |
332 | _ => false, | 303 | _ => false, |
333 | } | ||
334 | } | 304 | } |
335 | } | 305 | } |
336 | 306 | ||
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs index 1dcccbb8b..1b69d72f9 100644 --- a/crates/ide_db/src/defs.rs +++ b/crates/ide_db/src/defs.rs | |||
@@ -357,9 +357,9 @@ impl NameRefClass { | |||
357 | } | 357 | } |
358 | } | 358 | } |
359 | 359 | ||
360 | if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) { | 360 | if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) { |
361 | if let Some(path) = macro_call.path() { | 361 | if path.qualifier().is_none() { |
362 | if path.qualifier().is_none() { | 362 | if let Some(macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { |
363 | // Only use this to resolve single-segment macro calls like `foo!()`. Multi-segment | 363 | // Only use this to resolve single-segment macro calls like `foo!()`. Multi-segment |
364 | // paths are handled below (allowing `log$0::info!` to resolve to the log crate). | 364 | // paths are handled below (allowing `log$0::info!` to resolve to the log crate). |
365 | if let Some(macro_def) = sema.resolve_macro_call(¯o_call) { | 365 | if let Some(macro_def) = sema.resolve_macro_call(¯o_call) { |
@@ -367,9 +367,7 @@ impl NameRefClass { | |||
367 | } | 367 | } |
368 | } | 368 | } |
369 | } | 369 | } |
370 | } | ||
371 | 370 | ||
372 | if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) { | ||
373 | if let Some(resolved) = sema.resolve_path(&path) { | 371 | if let Some(resolved) = sema.resolve_path(&path) { |
374 | if path.syntax().parent().and_then(ast::Attr::cast).is_some() { | 372 | if path.syntax().parent().and_then(ast::Attr::cast).is_some() { |
375 | if let PathResolution::Def(ModuleDef::Function(func)) = resolved { | 373 | if let PathResolution::Def(ModuleDef::Function(func)) = resolved { |
diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs index 5c372a7e5..000f87a85 100644 --- a/crates/ide_db/src/symbol_index.rs +++ b/crates/ide_db/src/symbol_index.rs | |||
@@ -197,6 +197,7 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> { | |||
197 | } | 197 | } |
198 | 198 | ||
199 | pub fn crate_symbols(db: &RootDatabase, krate: CrateId, query: Query) -> Vec<FileSymbol> { | 199 | pub fn crate_symbols(db: &RootDatabase, krate: CrateId, query: Query) -> Vec<FileSymbol> { |
200 | let _p = profile::span("crate_symbols").detail(|| format!("{:?}", query)); | ||
200 | // FIXME(#4842): This now depends on CrateDefMap, why not build the entire symbol index from | 201 | // FIXME(#4842): This now depends on CrateDefMap, why not build the entire symbol index from |
201 | // that instead? | 202 | // that instead? |
202 | 203 | ||
@@ -321,6 +322,7 @@ impl SymbolIndex { | |||
321 | 322 | ||
322 | impl Query { | 323 | impl Query { |
323 | pub(crate) fn search(self, indices: &[&SymbolIndex]) -> Vec<FileSymbol> { | 324 | pub(crate) fn search(self, indices: &[&SymbolIndex]) -> Vec<FileSymbol> { |
325 | let _p = profile::span("symbol_index::Query::search"); | ||
324 | let mut op = fst::map::OpBuilder::new(); | 326 | let mut op = fst::map::OpBuilder::new(); |
325 | for file_symbols in indices.iter() { | 327 | for file_symbols in indices.iter() { |
326 | let automaton = fst::automaton::Subsequence::new(&self.lowercased); | 328 | let automaton = fst::automaton::Subsequence::new(&self.lowercased); |
diff --git a/crates/profile/Cargo.toml b/crates/profile/Cargo.toml index 1a8c8f862..653d3d983 100644 --- a/crates/profile/Cargo.toml +++ b/crates/profile/Cargo.toml | |||
@@ -20,6 +20,9 @@ jemalloc-ctl = { version = "0.4.1", package = "tikv-jemalloc-ctl", optional = tr | |||
20 | [target.'cfg(target_os = "linux")'.dependencies] | 20 | [target.'cfg(target_os = "linux")'.dependencies] |
21 | perf-event = "0.4" | 21 | perf-event = "0.4" |
22 | 22 | ||
23 | [target.'cfg(windows)'.dependencies] | ||
24 | winapi = { version = "0.3.8", features = ["psapi"] } | ||
25 | |||
23 | [features] | 26 | [features] |
24 | cpu_profiler = [] | 27 | cpu_profiler = [] |
25 | jemalloc = ["jemalloc-ctl"] | 28 | jemalloc = ["jemalloc-ctl"] |
diff --git a/crates/profile/src/memory_usage.rs b/crates/profile/src/memory_usage.rs index 2917ded60..6ef58c9c1 100644 --- a/crates/profile/src/memory_usage.rs +++ b/crates/profile/src/memory_usage.rs | |||
@@ -35,6 +35,22 @@ impl MemoryUsage { | |||
35 | // Note: This is incredibly slow. | 35 | // Note: This is incredibly slow. |
36 | let alloc = unsafe { libc::mallinfo() }.uordblks as isize; | 36 | let alloc = unsafe { libc::mallinfo() }.uordblks as isize; |
37 | MemoryUsage { allocated: Bytes(alloc) } | 37 | MemoryUsage { allocated: Bytes(alloc) } |
38 | } else if #[cfg(windows)] { | ||
39 | // There doesn't seem to be an API for determining heap usage, so we try to | ||
40 | // approximate that by using the Commit Charge value. | ||
41 | |||
42 | use winapi::um::processthreadsapi::*; | ||
43 | use winapi::um::psapi::*; | ||
44 | use std::mem::{MaybeUninit, size_of}; | ||
45 | |||
46 | let proc = unsafe { GetCurrentProcess() }; | ||
47 | let mut mem_counters = MaybeUninit::uninit(); | ||
48 | let cb = size_of::<PROCESS_MEMORY_COUNTERS>(); | ||
49 | let ret = unsafe { GetProcessMemoryInfo(proc, mem_counters.as_mut_ptr(), cb as u32) }; | ||
50 | assert!(ret != 0); | ||
51 | |||
52 | let usage = unsafe { mem_counters.assume_init().PagefileUsage }; | ||
53 | MemoryUsage { allocated: Bytes(usage as isize) } | ||
38 | } else { | 54 | } else { |
39 | MemoryUsage { allocated: Bytes(0) } | 55 | MemoryUsage { allocated: Bytes(0) } |
40 | } | 56 | } |
diff --git a/crates/rust-analyzer/src/cli.rs b/crates/rust-analyzer/src/cli.rs index 76b666dc2..25ebcc0ec 100644 --- a/crates/rust-analyzer/src/cli.rs +++ b/crates/rust-analyzer/src/cli.rs | |||
@@ -16,7 +16,6 @@ use vfs::Vfs; | |||
16 | pub use self::{ | 16 | pub use self::{ |
17 | analysis_stats::AnalysisStatsCmd, | 17 | analysis_stats::AnalysisStatsCmd, |
18 | diagnostics::diagnostics, | 18 | diagnostics::diagnostics, |
19 | load_cargo::{load_workspace, load_workspace_at, LoadCargoConfig}, | ||
20 | ssr::{apply_ssr_rules, search_for_patterns}, | 19 | ssr::{apply_ssr_rules, search_for_patterns}, |
21 | }; | 20 | }; |
22 | 21 | ||
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 5364e907c..843c0ca37 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs | |||
@@ -70,6 +70,7 @@ impl AnalysisStatsCmd { | |||
70 | load_out_dirs_from_check: self.enable_build_scripts, | 70 | load_out_dirs_from_check: self.enable_build_scripts, |
71 | wrap_rustc: false, | 71 | wrap_rustc: false, |
72 | with_proc_macro: self.enable_proc_macros, | 72 | with_proc_macro: self.enable_proc_macros, |
73 | prefill_caches: false, | ||
73 | }; | 74 | }; |
74 | let (host, vfs, _proc_macro) = | 75 | let (host, vfs, _proc_macro) = |
75 | load_workspace_at(&self.path, &cargo_config, &load_cargo_config, &|_| {})?; | 76 | load_workspace_at(&self.path, &cargo_config, &load_cargo_config, &|_| {})?; |
diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs index c33c8179c..dc9a390fe 100644 --- a/crates/rust-analyzer/src/cli/diagnostics.rs +++ b/crates/rust-analyzer/src/cli/diagnostics.rs | |||
@@ -34,8 +34,12 @@ pub fn diagnostics( | |||
34 | with_proc_macro: bool, | 34 | with_proc_macro: bool, |
35 | ) -> Result<()> { | 35 | ) -> Result<()> { |
36 | let cargo_config = Default::default(); | 36 | let cargo_config = Default::default(); |
37 | let load_cargo_config = | 37 | let load_cargo_config = LoadCargoConfig { |
38 | LoadCargoConfig { load_out_dirs_from_check, with_proc_macro, wrap_rustc: false }; | 38 | load_out_dirs_from_check, |
39 | with_proc_macro, | ||
40 | wrap_rustc: false, | ||
41 | prefill_caches: false, | ||
42 | }; | ||
39 | let (host, _vfs, _proc_macro) = | 43 | let (host, _vfs, _proc_macro) = |
40 | load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {})?; | 44 | load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {})?; |
41 | let db = host.raw_database(); | 45 | let db = host.raw_database(); |
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 8cee65478..19cb1c046 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs | |||
@@ -14,13 +14,14 @@ use vfs::{loader::Handle, AbsPath, AbsPathBuf}; | |||
14 | 14 | ||
15 | use crate::reload::{ProjectFolders, SourceRootConfig}; | 15 | use crate::reload::{ProjectFolders, SourceRootConfig}; |
16 | 16 | ||
17 | pub struct LoadCargoConfig { | 17 | pub(crate) struct LoadCargoConfig { |
18 | pub load_out_dirs_from_check: bool, | 18 | pub(crate) load_out_dirs_from_check: bool, |
19 | pub wrap_rustc: bool, | 19 | pub(crate) wrap_rustc: bool, |
20 | pub with_proc_macro: bool, | 20 | pub(crate) with_proc_macro: bool, |
21 | pub(crate) prefill_caches: bool, | ||
21 | } | 22 | } |
22 | 23 | ||
23 | pub fn load_workspace_at( | 24 | pub(crate) fn load_workspace_at( |
24 | root: &Path, | 25 | root: &Path, |
25 | cargo_config: &CargoConfig, | 26 | cargo_config: &CargoConfig, |
26 | load_config: &LoadCargoConfig, | 27 | load_config: &LoadCargoConfig, |
@@ -33,7 +34,7 @@ pub fn load_workspace_at( | |||
33 | load_workspace(workspace, load_config, progress) | 34 | load_workspace(workspace, load_config, progress) |
34 | } | 35 | } |
35 | 36 | ||
36 | pub fn load_workspace( | 37 | fn load_workspace( |
37 | ws: ProjectWorkspace, | 38 | ws: ProjectWorkspace, |
38 | config: &LoadCargoConfig, | 39 | config: &LoadCargoConfig, |
39 | progress: &dyn Fn(String), | 40 | progress: &dyn Fn(String), |
@@ -82,6 +83,10 @@ pub fn load_workspace( | |||
82 | log::debug!("crate graph: {:?}", crate_graph); | 83 | log::debug!("crate graph: {:?}", crate_graph); |
83 | let host = | 84 | let host = |
84 | load_crate_graph(crate_graph, project_folders.source_root_config, &mut vfs, &receiver); | 85 | load_crate_graph(crate_graph, project_folders.source_root_config, &mut vfs, &receiver); |
86 | |||
87 | if config.prefill_caches { | ||
88 | host.analysis().prime_caches(|_| {})?; | ||
89 | } | ||
85 | Ok((host, vfs, proc_macro_client)) | 90 | Ok((host, vfs, proc_macro_client)) |
86 | } | 91 | } |
87 | 92 | ||
@@ -144,6 +149,7 @@ mod tests { | |||
144 | load_out_dirs_from_check: false, | 149 | load_out_dirs_from_check: false, |
145 | wrap_rustc: false, | 150 | wrap_rustc: false, |
146 | with_proc_macro: false, | 151 | with_proc_macro: false, |
152 | prefill_caches: false, | ||
147 | }; | 153 | }; |
148 | let (host, _vfs, _proc_macro) = | 154 | let (host, _vfs, _proc_macro) = |
149 | load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {})?; | 155 | load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {})?; |
diff --git a/crates/rust-analyzer/src/cli/ssr.rs b/crates/rust-analyzer/src/cli/ssr.rs index 1fd9b5a9b..0b3475e09 100644 --- a/crates/rust-analyzer/src/cli/ssr.rs +++ b/crates/rust-analyzer/src/cli/ssr.rs | |||
@@ -13,6 +13,7 @@ pub fn apply_ssr_rules(rules: Vec<SsrRule>) -> Result<()> { | |||
13 | load_out_dirs_from_check: true, | 13 | load_out_dirs_from_check: true, |
14 | wrap_rustc: false, | 14 | wrap_rustc: false, |
15 | with_proc_macro: true, | 15 | with_proc_macro: true, |
16 | prefill_caches: false, | ||
16 | }; | 17 | }; |
17 | let (host, vfs, _proc_macro) = | 18 | let (host, vfs, _proc_macro) = |
18 | load_workspace_at(&std::env::current_dir()?, &cargo_config, &load_cargo_config, &|_| {})?; | 19 | load_workspace_at(&std::env::current_dir()?, &cargo_config, &load_cargo_config, &|_| {})?; |
@@ -39,8 +40,12 @@ pub fn search_for_patterns(patterns: Vec<SsrPattern>, debug_snippet: Option<Stri | |||
39 | use ide_db::base_db::SourceDatabaseExt; | 40 | use ide_db::base_db::SourceDatabaseExt; |
40 | use ide_db::symbol_index::SymbolsDatabase; | 41 | use ide_db::symbol_index::SymbolsDatabase; |
41 | let cargo_config = Default::default(); | 42 | let cargo_config = Default::default(); |
42 | let load_cargo_config = | 43 | let load_cargo_config = LoadCargoConfig { |
43 | LoadCargoConfig { load_out_dirs_from_check: true, wrap_rustc: true, with_proc_macro: true }; | 44 | load_out_dirs_from_check: true, |
45 | wrap_rustc: true, | ||
46 | with_proc_macro: true, | ||
47 | prefill_caches: false, | ||
48 | }; | ||
44 | let (host, _vfs, _proc_macro) = | 49 | let (host, _vfs, _proc_macro) = |
45 | load_workspace_at(&std::env::current_dir()?, &cargo_config, &load_cargo_config, &|_| {})?; | 50 | load_workspace_at(&std::env::current_dir()?, &cargo_config, &load_cargo_config, &|_| {})?; |
46 | let db = host.raw_database(); | 51 | let db = host.raw_database(); |
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs index ec36a5f5c..8ddeb59f7 100644 --- a/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/crates/rust-analyzer/src/integrated_benchmarks.rs | |||
@@ -37,6 +37,7 @@ fn integrated_highlighting_benchmark() { | |||
37 | load_out_dirs_from_check: true, | 37 | load_out_dirs_from_check: true, |
38 | wrap_rustc: false, | 38 | wrap_rustc: false, |
39 | with_proc_macro: false, | 39 | with_proc_macro: false, |
40 | prefill_caches: false, | ||
40 | }; | 41 | }; |
41 | 42 | ||
42 | let (mut host, vfs, _proc_macro) = { | 43 | let (mut host, vfs, _proc_macro) = { |
@@ -91,6 +92,7 @@ fn integrated_completion_benchmark() { | |||
91 | load_out_dirs_from_check: true, | 92 | load_out_dirs_from_check: true, |
92 | wrap_rustc: false, | 93 | wrap_rustc: false, |
93 | with_proc_macro: false, | 94 | with_proc_macro: false, |
95 | prefill_caches: true, | ||
94 | }; | 96 | }; |
95 | 97 | ||
96 | let (mut host, vfs, _proc_macro) = { | 98 | let (mut host, vfs, _proc_macro) = { |