aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock10
-rw-r--r--Cargo.toml1
-rw-r--r--crates/base_db/src/lib.rs1
-rw-r--r--crates/hir/src/lib.rs4
-rw-r--r--crates/hir_def/src/import_map.rs169
-rw-r--r--crates/hir_def/src/lang_item.rs1
-rw-r--r--crates/hir_def/src/per_ns.rs2
-rw-r--r--crates/ide/src/prime_caches.rs7
-rw-r--r--crates/ide/src/references.rs20
-rw-r--r--crates/ide_assists/src/handlers/change_visibility.rs11
-rw-r--r--crates/ide_assists/src/handlers/remove_unused_param.rs30
-rw-r--r--crates/ide_db/src/defs.rs8
-rw-r--r--crates/ide_db/src/symbol_index.rs2
-rw-r--r--crates/proc_macro_srv/src/dylib.rs11
-rw-r--r--crates/proc_macro_srv/src/tests/utils.rs29
-rw-r--r--crates/proc_macro_test/Cargo.toml6
-rw-r--r--crates/proc_macro_test/build.rs48
-rw-r--r--crates/proc_macro_test/imp/.gitignore2
-rw-r--r--crates/proc_macro_test/imp/Cargo.toml17
-rw-r--r--crates/proc_macro_test/imp/src/lib.rs48
-rw-r--r--crates/proc_macro_test/src/lib.rs48
-rw-r--r--crates/profile/Cargo.toml3
-rw-r--r--crates/profile/src/memory_usage.rs16
-rw-r--r--crates/rust-analyzer/src/cli.rs1
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs1
-rw-r--r--crates/rust-analyzer/src/cli/diagnostics.rs8
-rw-r--r--crates/rust-analyzer/src/cli/load_cargo.rs18
-rw-r--r--crates/rust-analyzer/src/cli/ssr.rs9
-rw-r--r--crates/rust-analyzer/src/integrated_benchmarks.rs2
29 files changed, 350 insertions, 183 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 505263c64..ea2c1aed7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1158,6 +1158,15 @@ dependencies = [
1158[[package]] 1158[[package]]
1159name = "proc_macro_test" 1159name = "proc_macro_test"
1160version = "0.0.0" 1160version = "0.0.0"
1161dependencies = [
1162 "cargo_metadata",
1163 "proc_macro_test_impl",
1164 "toolchain",
1165]
1166
1167[[package]]
1168name = "proc_macro_test_impl"
1169version = "0.0.0"
1161 1170
1162[[package]] 1171[[package]]
1163name = "profile" 1172name = "profile"
@@ -1170,6 +1179,7 @@ dependencies = [
1170 "once_cell", 1179 "once_cell",
1171 "perf-event", 1180 "perf-event",
1172 "tikv-jemalloc-ctl", 1181 "tikv-jemalloc-ctl",
1182 "winapi",
1173] 1183]
1174 1184
1175[[package]] 1185[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 32ba3923b..4d6908fa9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,7 @@
1[workspace] 1[workspace]
2resolver = "2" 2resolver = "2"
3members = ["xtask/", "lib/*", "crates/*"] 3members = ["xtask/", "lib/*", "crates/*"]
4exclude = ["crates/proc_macro_test/imp"]
4 5
5[profile.dev] 6[profile.dev]
6# Disabling debug info speeds up builds a bunch, 7# Disabling debug info speeds up builds a bunch,
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 debc3ee62..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()),
@@ -2185,6 +2186,7 @@ impl Type {
2185 name: Option<&Name>, 2186 name: Option<&Name>,
2186 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 2187 mut callback: impl FnMut(&Ty, Function) -> Option<T>,
2187 ) -> Option<T> { 2188 ) -> Option<T> {
2189 let _p = profile::span("iterate_method_candidates");
2188 // There should be no inference vars in types passed here 2190 // There should be no inference vars in types passed here
2189 // FIXME check that? 2191 // FIXME check that?
2190 // FIXME replace Unknown by bound vars here 2192 // FIXME replace Unknown by bound vars here
@@ -2218,6 +2220,7 @@ impl Type {
2218 name: Option<&Name>, 2220 name: Option<&Name>,
2219 mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, 2221 mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
2220 ) -> Option<T> { 2222 ) -> Option<T> {
2223 let _p = profile::span("iterate_path_candidates");
2221 let canonical = hir_ty::replace_errors_with_variables(&self.ty); 2224 let canonical = hir_ty::replace_errors_with_variables(&self.ty);
2222 2225
2223 let env = self.env.clone(); 2226 let env = self.env.clone();
@@ -2255,6 +2258,7 @@ impl Type {
2255 &'a self, 2258 &'a self,
2256 db: &'a dyn HirDatabase, 2259 db: &'a dyn HirDatabase,
2257 ) -> impl Iterator<Item = Trait> + 'a { 2260 ) -> impl Iterator<Item = Trait> + 'a {
2261 let _p = profile::span("applicable_inherent_traits");
2258 self.autoderef(db) 2262 self.autoderef(db)
2259 .filter_map(|derefed_type| derefed_type.ty.dyn_trait()) 2263 .filter_map(|derefed_type| derefed_type.ty.dyn_trait())
2260 .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
3use std::{cmp::Ordering, fmt, hash::BuildHasherDefault, sync::Arc}; 3use std::{fmt, hash::BuildHasherDefault, sync::Arc};
4 4
5use base_db::CrateId; 5use base_db::CrateId;
6use fst::{self, Streamer}; 6use fst::{self, Streamer};
@@ -69,81 +69,11 @@ pub struct ImportMap {
69impl ImportMap { 69impl 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
144fn 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
213impl PartialEq for ImportMap { 222impl 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
242fn fst_path(path: &ImportPath) -> String { 251fn 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
248fn 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)]
255pub enum ImportKind { 259pub 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/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/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#"
1388macro_rules! m {
1389 () => {};
1390}
1391
1392#[proc_macro_test::attr_noop]
1393m$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/change_visibility.rs b/crates/ide_assists/src/handlers/change_visibility.rs
index d7e39b2ae..ed936667f 100644
--- a/crates/ide_assists/src/handlers/change_visibility.rs
+++ b/crates/ide_assists/src/handlers/change_visibility.rs
@@ -1,7 +1,9 @@
1use syntax::{ 1use syntax::{
2 ast::{self, NameOwner, VisibilityOwner}, 2 ast::{self, NameOwner, VisibilityOwner},
3 AstNode, 3 AstNode,
4 SyntaxKind::{CONST, ENUM, FN, MODULE, STATIC, STRUCT, TRAIT, TYPE_ALIAS, VISIBILITY}, 4 SyntaxKind::{
5 CONST, ENUM, FN, MACRO_DEF, MODULE, STATIC, STRUCT, TRAIT, TYPE_ALIAS, USE, VISIBILITY,
6 },
5 T, 7 T,
6}; 8};
7 9
@@ -37,12 +39,15 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
37 | T![enum] 39 | T![enum]
38 | T![trait] 40 | T![trait]
39 | T![type] 41 | T![type]
42 | T![use]
43 | T![macro]
40 ) 44 )
41 }); 45 });
42 46
43 let (offset, target) = if let Some(keyword) = item_keyword { 47 let (offset, target) = if let Some(keyword) = item_keyword {
44 let parent = keyword.parent()?; 48 let parent = keyword.parent()?;
45 let def_kws = vec![CONST, STATIC, TYPE_ALIAS, FN, MODULE, STRUCT, ENUM, TRAIT]; 49 let def_kws =
50 vec![CONST, STATIC, TYPE_ALIAS, FN, MODULE, STRUCT, ENUM, TRAIT, USE, MACRO_DEF];
46 // Parent is not a definition, can't add visibility 51 // Parent is not a definition, can't add visibility
47 if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) { 52 if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) {
48 return None; 53 return None;
@@ -122,6 +127,8 @@ mod tests {
122 check_assist(change_visibility, "$0trait Foo {}", "pub(crate) trait Foo {}"); 127 check_assist(change_visibility, "$0trait Foo {}", "pub(crate) trait Foo {}");
123 check_assist(change_visibility, "m$0od {}", "pub(crate) mod {}"); 128 check_assist(change_visibility, "m$0od {}", "pub(crate) mod {}");
124 check_assist(change_visibility, "unsafe f$0n foo() {}", "pub(crate) unsafe fn foo() {}"); 129 check_assist(change_visibility, "unsafe f$0n foo() {}", "pub(crate) unsafe fn foo() {}");
130 check_assist(change_visibility, "$0macro foo() {}", "pub(crate) macro foo() {}");
131 check_assist(change_visibility, "$0use foo;", "pub(crate) use foo;");
125 } 132 }
126 133
127 #[test] 134 #[test]
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#"
274trait Trait {
275 fn foo(x: i32);
276}
277impl 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_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(&macro_call) { 365 if let Some(macro_def) = sema.resolve_macro_call(&macro_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
199pub fn crate_symbols(db: &RootDatabase, krate: CrateId, query: Query) -> Vec<FileSymbol> { 199pub 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
322impl Query { 323impl 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/proc_macro_srv/src/dylib.rs b/crates/proc_macro_srv/src/dylib.rs
index cccc53220..5133e7c50 100644
--- a/crates/proc_macro_srv/src/dylib.rs
+++ b/crates/proc_macro_srv/src/dylib.rs
@@ -188,7 +188,9 @@ impl Expander {
188/// Copy the dylib to temp directory to prevent locking in Windows 188/// Copy the dylib to temp directory to prevent locking in Windows
189#[cfg(windows)] 189#[cfg(windows)]
190fn ensure_file_with_lock_free_access(path: &Path) -> io::Result<PathBuf> { 190fn ensure_file_with_lock_free_access(path: &Path) -> io::Result<PathBuf> {
191 use std::{ffi::OsString, time::SystemTime}; 191 use std::collections::hash_map::RandomState;
192 use std::ffi::OsString;
193 use std::hash::{BuildHasher, Hasher};
192 194
193 let mut to = std::env::temp_dir(); 195 let mut to = std::env::temp_dir();
194 196
@@ -199,10 +201,11 @@ fn ensure_file_with_lock_free_access(path: &Path) -> io::Result<PathBuf> {
199 ) 201 )
200 })?; 202 })?;
201 203
202 // generate a time deps unique number 204 // Generate a unique number by abusing `HashMap`'s hasher.
203 let t = SystemTime::now().duration_since(std::time::UNIX_EPOCH).expect("Time went backwards"); 205 // Maybe this will also "inspire" a libs team member to finally put `rand` in libstd.
206 let t = RandomState::new().build_hasher().finish();
204 207
205 let mut unique_name = OsString::from(t.as_millis().to_string()); 208 let mut unique_name = OsString::from(t.to_string());
206 unique_name.push(file_name); 209 unique_name.push(file_name);
207 210
208 to.push(unique_name); 211 to.push(unique_name);
diff --git a/crates/proc_macro_srv/src/tests/utils.rs b/crates/proc_macro_srv/src/tests/utils.rs
index 2e950c113..2c093aa0a 100644
--- a/crates/proc_macro_srv/src/tests/utils.rs
+++ b/crates/proc_macro_srv/src/tests/utils.rs
@@ -7,35 +7,8 @@ use proc_macro_api::ListMacrosTask;
7use std::str::FromStr; 7use std::str::FromStr;
8 8
9pub mod fixtures { 9pub mod fixtures {
10 use cargo_metadata::Message;
11 use std::path::PathBuf;
12 use std::process::Command;
13
14 // Use current project metadata to get the proc-macro dylib path
15 pub fn proc_macro_test_dylib_path() -> std::path::PathBuf { 10 pub fn proc_macro_test_dylib_path() -> std::path::PathBuf {
16 let name = "proc_macro_test"; 11 proc_macro_test::PROC_MACRO_TEST_LOCATION.into()
17 let version = "0.0.0";
18 let command = Command::new(toolchain::cargo())
19 .args(&["check", "--tests", "--message-format", "json"])
20 .output()
21 .unwrap()
22 .stdout;
23
24 for message in Message::parse_stream(command.as_slice()) {
25 match message.unwrap() {
26 Message::CompilerArtifact(artifact) => {
27 if artifact.target.kind.contains(&"proc-macro".to_string()) {
28 let repr = format!("{} {}", name, version);
29 if artifact.package_id.repr.starts_with(&repr) {
30 return PathBuf::from(&artifact.filenames[0]);
31 }
32 }
33 }
34 _ => (), // Unknown message
35 }
36 }
37
38 panic!("No proc-macro dylib for {} found!", name);
39 } 12 }
40} 13}
41 14
diff --git a/crates/proc_macro_test/Cargo.toml b/crates/proc_macro_test/Cargo.toml
index 753443be2..1a88e361e 100644
--- a/crates/proc_macro_test/Cargo.toml
+++ b/crates/proc_macro_test/Cargo.toml
@@ -8,4 +8,8 @@ publish = false
8 8
9[lib] 9[lib]
10doctest = false 10doctest = false
11proc-macro = true 11
12[build-dependencies]
13proc_macro_test_impl = { path = "imp", version = "0.0.0" }
14toolchain = { path = "../toolchain", version = "0.0.0" }
15cargo_metadata = "0.13"
diff --git a/crates/proc_macro_test/build.rs b/crates/proc_macro_test/build.rs
new file mode 100644
index 000000000..4653a93dd
--- /dev/null
+++ b/crates/proc_macro_test/build.rs
@@ -0,0 +1,48 @@
1//! This will build the proc macro in `imp`, and copy the resulting dylib artifact into the
2//! `OUT_DIR`.
3//!
4//! `proc_macro_test` itself contains only a path to that artifact.
5
6use std::{
7 env, fs,
8 path::{Path, PathBuf},
9 process::Command,
10};
11
12use cargo_metadata::Message;
13
14fn main() {
15 let out_dir = env::var_os("OUT_DIR").unwrap();
16 let out_dir = Path::new(&out_dir);
17
18 let name = "proc_macro_test_impl";
19 let version = "0.0.0";
20 let output = Command::new(toolchain::cargo())
21 .current_dir("imp")
22 .args(&["build", "-p", "proc_macro_test_impl", "--message-format", "json"])
23 .output()
24 .unwrap();
25 assert!(output.status.success());
26
27 let mut artifact_path = None;
28 for message in Message::parse_stream(output.stdout.as_slice()) {
29 match message.unwrap() {
30 Message::CompilerArtifact(artifact) => {
31 if artifact.target.kind.contains(&"proc-macro".to_string()) {
32 let repr = format!("{} {}", name, version);
33 if artifact.package_id.repr.starts_with(&repr) {
34 artifact_path = Some(PathBuf::from(&artifact.filenames[0]));
35 }
36 }
37 }
38 _ => (), // Unknown message
39 }
40 }
41
42 let src_path = artifact_path.expect("no dylib for proc_macro_test_impl found");
43 let dest_path = out_dir.join(src_path.file_name().unwrap());
44 fs::copy(src_path, &dest_path).unwrap();
45
46 let info_path = out_dir.join("proc_macro_test_location.txt");
47 fs::write(info_path, dest_path.to_str().unwrap()).unwrap();
48}
diff --git a/crates/proc_macro_test/imp/.gitignore b/crates/proc_macro_test/imp/.gitignore
new file mode 100644
index 000000000..2c96eb1b6
--- /dev/null
+++ b/crates/proc_macro_test/imp/.gitignore
@@ -0,0 +1,2 @@
1target/
2Cargo.lock
diff --git a/crates/proc_macro_test/imp/Cargo.toml b/crates/proc_macro_test/imp/Cargo.toml
new file mode 100644
index 000000000..1c2e75401
--- /dev/null
+++ b/crates/proc_macro_test/imp/Cargo.toml
@@ -0,0 +1,17 @@
1[package]
2name = "proc_macro_test_impl"
3version = "0.0.0"
4license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"]
6edition = "2018"
7publish = false
8
9[lib]
10doctest = false
11proc-macro = true
12
13[workspace]
14
15[dependencies]
16# this crate should not have any dependencies, since it uses its own workspace,
17# and its own `Cargo.lock`
diff --git a/crates/proc_macro_test/imp/src/lib.rs b/crates/proc_macro_test/imp/src/lib.rs
new file mode 100644
index 000000000..4b26d2472
--- /dev/null
+++ b/crates/proc_macro_test/imp/src/lib.rs
@@ -0,0 +1,48 @@
1//! Exports a few trivial procedural macros for testing.
2
3use proc_macro::TokenStream;
4
5#[proc_macro]
6pub fn fn_like_noop(args: TokenStream) -> TokenStream {
7 args
8}
9
10#[proc_macro]
11pub fn fn_like_panic(args: TokenStream) -> TokenStream {
12 panic!("fn_like_panic!({})", args);
13}
14
15#[proc_macro]
16pub fn fn_like_error(args: TokenStream) -> TokenStream {
17 format!("compile_error!(\"fn_like_error!({})\");", args).parse().unwrap()
18}
19
20#[proc_macro_attribute]
21pub fn attr_noop(_args: TokenStream, item: TokenStream) -> TokenStream {
22 item
23}
24
25#[proc_macro_attribute]
26pub fn attr_panic(args: TokenStream, item: TokenStream) -> TokenStream {
27 panic!("#[attr_panic {}] {}", args, item);
28}
29
30#[proc_macro_attribute]
31pub fn attr_error(args: TokenStream, item: TokenStream) -> TokenStream {
32 format!("compile_error!(\"#[attr_error({})] {}\");", args, item).parse().unwrap()
33}
34
35#[proc_macro_derive(DeriveEmpty)]
36pub fn derive_empty(_item: TokenStream) -> TokenStream {
37 TokenStream::new()
38}
39
40#[proc_macro_derive(DerivePanic)]
41pub fn derive_panic(item: TokenStream) -> TokenStream {
42 panic!("#[derive(DerivePanic)] {}", item);
43}
44
45#[proc_macro_derive(DeriveError)]
46pub fn derive_error(item: TokenStream) -> TokenStream {
47 format!("compile_error!(\"#[derive(DeriveError)] {}\");", item).parse().unwrap()
48}
diff --git a/crates/proc_macro_test/src/lib.rs b/crates/proc_macro_test/src/lib.rs
index 4b26d2472..2edf23a63 100644
--- a/crates/proc_macro_test/src/lib.rs
+++ b/crates/proc_macro_test/src/lib.rs
@@ -1,48 +1,4 @@
1//! Exports a few trivial procedural macros for testing. 1//! Exports a few trivial procedural macros for testing.
2 2
3use proc_macro::TokenStream; 3pub static PROC_MACRO_TEST_LOCATION: &str =
4 4 include_str!(concat!(env!("OUT_DIR"), "/proc_macro_test_location.txt"));
5#[proc_macro]
6pub fn fn_like_noop(args: TokenStream) -> TokenStream {
7 args
8}
9
10#[proc_macro]
11pub fn fn_like_panic(args: TokenStream) -> TokenStream {
12 panic!("fn_like_panic!({})", args);
13}
14
15#[proc_macro]
16pub fn fn_like_error(args: TokenStream) -> TokenStream {
17 format!("compile_error!(\"fn_like_error!({})\");", args).parse().unwrap()
18}
19
20#[proc_macro_attribute]
21pub fn attr_noop(_args: TokenStream, item: TokenStream) -> TokenStream {
22 item
23}
24
25#[proc_macro_attribute]
26pub fn attr_panic(args: TokenStream, item: TokenStream) -> TokenStream {
27 panic!("#[attr_panic {}] {}", args, item);
28}
29
30#[proc_macro_attribute]
31pub fn attr_error(args: TokenStream, item: TokenStream) -> TokenStream {
32 format!("compile_error!(\"#[attr_error({})] {}\");", args, item).parse().unwrap()
33}
34
35#[proc_macro_derive(DeriveEmpty)]
36pub fn derive_empty(_item: TokenStream) -> TokenStream {
37 TokenStream::new()
38}
39
40#[proc_macro_derive(DerivePanic)]
41pub fn derive_panic(item: TokenStream) -> TokenStream {
42 panic!("#[derive(DerivePanic)] {}", item);
43}
44
45#[proc_macro_derive(DeriveError)]
46pub fn derive_error(item: TokenStream) -> TokenStream {
47 format!("compile_error!(\"#[derive(DeriveError)] {}\");", item).parse().unwrap()
48}
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]
21perf-event = "0.4" 21perf-event = "0.4"
22 22
23[target.'cfg(windows)'.dependencies]
24winapi = { version = "0.3.8", features = ["psapi"] }
25
23[features] 26[features]
24cpu_profiler = [] 27cpu_profiler = []
25jemalloc = ["jemalloc-ctl"] 28jemalloc = ["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;
16pub use self::{ 16pub 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
15use crate::reload::{ProjectFolders, SourceRootConfig}; 15use crate::reload::{ProjectFolders, SourceRootConfig};
16 16
17pub struct LoadCargoConfig { 17pub(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
23pub fn load_workspace_at( 24pub(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
36pub fn load_workspace( 37fn 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) = {