aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/project_model/src/workspace.rs393
1 files changed, 207 insertions, 186 deletions
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index 2155687ec..3ea6ba47e 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -197,215 +197,236 @@ impl ProjectWorkspace {
197 proc_macro_client: &ProcMacroClient, 197 proc_macro_client: &ProcMacroClient,
198 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, 198 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
199 ) -> CrateGraph { 199 ) -> CrateGraph {
200 let mut crate_graph = CrateGraph::default(); 200 let mut crate_graph = match self {
201 match self {
202 ProjectWorkspace::Json { project, sysroot } => { 201 ProjectWorkspace::Json { project, sysroot } => {
203 let sysroot_deps = sysroot 202 project_json_to_crate_graph(target, proc_macro_client, load, project, sysroot)
204 .as_ref()
205 .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load));
206
207 let mut cfg_cache: FxHashMap<Option<&str>, Vec<CfgFlag>> = FxHashMap::default();
208 let crates: FxHashMap<CrateId, CrateId> = project
209 .crates()
210 .filter_map(|(crate_id, krate)| {
211 let file_path = &krate.root_module;
212 let file_id = load(&file_path)?;
213 Some((crate_id, krate, file_id))
214 })
215 .map(|(crate_id, krate, file_id)| {
216 let env = krate.env.clone().into_iter().collect();
217 let proc_macro = krate
218 .proc_macro_dylib_path
219 .clone()
220 .map(|it| proc_macro_client.by_dylib_path(&it));
221
222 let target = krate.target.as_deref().or(target);
223 let target_cfgs = cfg_cache
224 .entry(target)
225 .or_insert_with(|| get_rustc_cfg_options(target));
226
227 let mut cfg_options = CfgOptions::default();
228 cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned());
229 (
230 crate_id,
231 crate_graph.add_crate_root(
232 file_id,
233 krate.edition,
234 krate.display_name.clone(),
235 cfg_options,
236 env,
237 proc_macro.unwrap_or_default(),
238 ),
239 )
240 })
241 .collect();
242
243 for (from, krate) in project.crates() {
244 if let Some(&from) = crates.get(&from) {
245 if let Some((public_deps, _proc_macro)) = &sysroot_deps {
246 for (name, to) in public_deps.iter() {
247 add_dep(&mut crate_graph, from, name.clone(), *to)
248 }
249 }
250
251 for dep in &krate.deps {
252 if let Some(&to) = crates.get(&dep.crate_id) {
253 add_dep(&mut crate_graph, from, dep.name.clone(), to)
254 }
255 }
256 }
257 }
258 } 203 }
259 ProjectWorkspace::Cargo { cargo, sysroot, rustc } => { 204 ProjectWorkspace::Cargo { cargo, sysroot, rustc } => {
260 let (public_deps, libproc_macro) = 205 cargo_to_crate_graph(target, proc_macro_client, load, cargo, sysroot, rustc)
261 sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load); 206 }
207 };
208 if crate_graph.patch_cfg_if() {
209 log::debug!("Patched std to depend on cfg-if")
210 } else {
211 log::debug!("Did not patch std to depend on cfg-if")
212 }
213 crate_graph
214 }
215}
262 216
263 let mut cfg_options = CfgOptions::default(); 217fn project_json_to_crate_graph(
264 cfg_options.extend(get_rustc_cfg_options(target)); 218 target: Option<&str>,
219 proc_macro_client: &ProcMacroClient,
220 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
221 project: &ProjectJson,
222 sysroot: &Option<Sysroot>,
223) -> CrateGraph {
224 let mut crate_graph = CrateGraph::default();
225 let sysroot_deps = sysroot
226 .as_ref()
227 .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load));
228
229 let mut cfg_cache: FxHashMap<Option<&str>, Vec<CfgFlag>> = FxHashMap::default();
230 let crates: FxHashMap<CrateId, CrateId> = project
231 .crates()
232 .filter_map(|(crate_id, krate)| {
233 let file_path = &krate.root_module;
234 let file_id = load(&file_path)?;
235 Some((crate_id, krate, file_id))
236 })
237 .map(|(crate_id, krate, file_id)| {
238 let env = krate.env.clone().into_iter().collect();
239 let proc_macro =
240 krate.proc_macro_dylib_path.clone().map(|it| proc_macro_client.by_dylib_path(&it));
241
242 let target = krate.target.as_deref().or(target);
243 let target_cfgs =
244 cfg_cache.entry(target).or_insert_with(|| get_rustc_cfg_options(target));
245
246 let mut cfg_options = CfgOptions::default();
247 cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned());
248 (
249 crate_id,
250 crate_graph.add_crate_root(
251 file_id,
252 krate.edition,
253 krate.display_name.clone(),
254 cfg_options,
255 env,
256 proc_macro.unwrap_or_default(),
257 ),
258 )
259 })
260 .collect();
265 261
266 let mut pkg_to_lib_crate = FxHashMap::default(); 262 for (from, krate) in project.crates() {
263 if let Some(&from) = crates.get(&from) {
264 if let Some((public_deps, _proc_macro)) = &sysroot_deps {
265 for (name, to) in public_deps.iter() {
266 add_dep(&mut crate_graph, from, name.clone(), *to)
267 }
268 }
267 269
268 // Add test cfg for non-sysroot crates 270 for dep in &krate.deps {
269 cfg_options.insert_atom("test".into()); 271 if let Some(&to) = crates.get(&dep.crate_id) {
270 cfg_options.insert_atom("debug_assertions".into()); 272 add_dep(&mut crate_graph, from, dep.name.clone(), to)
273 }
274 }
275 }
276 }
277 crate_graph
278}
271 279
272 let mut pkg_crates = FxHashMap::default(); 280fn cargo_to_crate_graph(
281 target: Option<&str>,
282 proc_macro_client: &ProcMacroClient,
283 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
284 cargo: &CargoWorkspace,
285 sysroot: &Sysroot,
286 rustc: &Option<CargoWorkspace>,
287) -> CrateGraph {
288 let mut crate_graph = CrateGraph::default();
289 let (public_deps, libproc_macro) =
290 sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load);
273 291
274 // Next, create crates for each package, target pair 292 let mut cfg_options = CfgOptions::default();
275 for pkg in cargo.packages() { 293 cfg_options.extend(get_rustc_cfg_options(target));
276 let mut lib_tgt = None; 294
277 for &tgt in cargo[pkg].targets.iter() { 295 let mut pkg_to_lib_crate = FxHashMap::default();
278 if let Some(crate_id) = add_target_crate_root( 296
297 // Add test cfg for non-sysroot crates
298 cfg_options.insert_atom("test".into());
299 cfg_options.insert_atom("debug_assertions".into());
300
301 let mut pkg_crates = FxHashMap::default();
302
303 // Next, create crates for each package, target pair
304 for pkg in cargo.packages() {
305 let mut lib_tgt = None;
306 for &tgt in cargo[pkg].targets.iter() {
307 if let Some(crate_id) = add_target_crate_root(
308 &mut crate_graph,
309 &cargo[pkg],
310 &cargo[tgt],
311 &cfg_options,
312 proc_macro_client,
313 load,
314 ) {
315 if cargo[tgt].kind == TargetKind::Lib {
316 lib_tgt = Some((crate_id, cargo[tgt].name.clone()));
317 pkg_to_lib_crate.insert(pkg, crate_id);
318 }
319 if cargo[tgt].is_proc_macro {
320 if let Some(proc_macro) = libproc_macro {
321 add_dep(
279 &mut crate_graph, 322 &mut crate_graph,
280 &cargo[pkg], 323 crate_id,
281 &cargo[tgt], 324 CrateName::new("proc_macro").unwrap(),
282 &cfg_options, 325 proc_macro,
283 proc_macro_client, 326 );
284 load,
285 ) {
286 if cargo[tgt].kind == TargetKind::Lib {
287 lib_tgt = Some((crate_id, cargo[tgt].name.clone()));
288 pkg_to_lib_crate.insert(pkg, crate_id);
289 }
290 if cargo[tgt].is_proc_macro {
291 if let Some(proc_macro) = libproc_macro {
292 add_dep(
293 &mut crate_graph,
294 crate_id,
295 CrateName::new("proc_macro").unwrap(),
296 proc_macro,
297 );
298 }
299 }
300
301 pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
302 }
303 } 327 }
328 }
304 329
305 // Set deps to the core, std and to the lib target of the current package 330 pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
306 for &from in pkg_crates.get(&pkg).into_iter().flatten() { 331 }
307 if let Some((to, name)) = lib_tgt.clone() { 332 }
308 if to != from { 333
309 // For root projects with dashes in their name, 334 // Set deps to the core, std and to the lib target of the current package
310 // cargo metadata does not do any normalization, 335 for &from in pkg_crates.get(&pkg).into_iter().flatten() {
311 // so we do it ourselves currently 336 if let Some((to, name)) = lib_tgt.clone() {
312 let name = CrateName::normalize_dashes(&name); 337 if to != from {
313 add_dep(&mut crate_graph, from, name, to); 338 // For root projects with dashes in their name,
314 } 339 // cargo metadata does not do any normalization,
315 } 340 // so we do it ourselves currently
316 for (name, krate) in public_deps.iter() { 341 let name = CrateName::normalize_dashes(&name);
317 add_dep(&mut crate_graph, from, name.clone(), *krate); 342 add_dep(&mut crate_graph, from, name, to);
318 }
319 }
320 } 343 }
344 }
345 for (name, krate) in public_deps.iter() {
346 add_dep(&mut crate_graph, from, name.clone(), *krate);
347 }
348 }
349 }
321 350
322 // Now add a dep edge from all targets of upstream to the lib 351 // Now add a dep edge from all targets of upstream to the lib
323 // target of downstream. 352 // target of downstream.
324 for pkg in cargo.packages() { 353 for pkg in cargo.packages() {
325 for dep in cargo[pkg].dependencies.iter() { 354 for dep in cargo[pkg].dependencies.iter() {
326 let name = CrateName::new(&dep.name).unwrap(); 355 let name = CrateName::new(&dep.name).unwrap();
327 if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { 356 if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
328 for &from in pkg_crates.get(&pkg).into_iter().flatten() { 357 for &from in pkg_crates.get(&pkg).into_iter().flatten() {
329 add_dep(&mut crate_graph, from, name.clone(), to) 358 add_dep(&mut crate_graph, from, name.clone(), to)
330 } 359 }
331 } 360 }
332 } 361 }
362 }
363
364 let mut rustc_pkg_crates = FxHashMap::default();
365
366 // If the user provided a path to rustc sources, we add all the rustc_private crates
367 // and create dependencies on them for the crates in the current workspace
368 if let Some(rustc_workspace) = rustc {
369 for pkg in rustc_workspace.packages() {
370 for &tgt in rustc_workspace[pkg].targets.iter() {
371 if rustc_workspace[tgt].kind != TargetKind::Lib {
372 continue;
373 }
374 // Exclude alloc / core / std
375 if rustc_workspace[tgt]
376 .root
377 .components()
378 .any(|c| c == Component::Normal("library".as_ref()))
379 {
380 continue;
333 } 381 }
334 382
335 let mut rustc_pkg_crates = FxHashMap::default(); 383 if let Some(crate_id) = add_target_crate_root(
336 384 &mut crate_graph,
337 // If the user provided a path to rustc sources, we add all the rustc_private crates 385 &rustc_workspace[pkg],
338 // and create dependencies on them for the crates in the current workspace 386 &rustc_workspace[tgt],
339 if let Some(rustc_workspace) = rustc { 387 &cfg_options,
340 for pkg in rustc_workspace.packages() { 388 proc_macro_client,
341 for &tgt in rustc_workspace[pkg].targets.iter() { 389 load,
342 if rustc_workspace[tgt].kind != TargetKind::Lib { 390 ) {
343 continue; 391 pkg_to_lib_crate.insert(pkg, crate_id);
344 } 392 // Add dependencies on the core / std / alloc for rustc
345 // Exclude alloc / core / std 393 for (name, krate) in public_deps.iter() {
346 if rustc_workspace[tgt] 394 add_dep(&mut crate_graph, crate_id, name.clone(), *krate);
347 .root
348 .components()
349 .any(|c| c == Component::Normal("library".as_ref()))
350 {
351 continue;
352 }
353
354 if let Some(crate_id) = add_target_crate_root(
355 &mut crate_graph,
356 &rustc_workspace[pkg],
357 &rustc_workspace[tgt],
358 &cfg_options,
359 proc_macro_client,
360 load,
361 ) {
362 pkg_to_lib_crate.insert(pkg, crate_id);
363 // Add dependencies on the core / std / alloc for rustc
364 for (name, krate) in public_deps.iter() {
365 add_dep(&mut crate_graph, crate_id, name.clone(), *krate);
366 }
367 rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
368 }
369 }
370 } 395 }
371 // Now add a dep edge from all targets of upstream to the lib 396 rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
372 // target of downstream. 397 }
373 for pkg in rustc_workspace.packages() { 398 }
374 for dep in rustc_workspace[pkg].dependencies.iter() { 399 }
375 let name = CrateName::new(&dep.name).unwrap(); 400 // Now add a dep edge from all targets of upstream to the lib
376 if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { 401 // target of downstream.
377 for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() { 402 for pkg in rustc_workspace.packages() {
378 add_dep(&mut crate_graph, from, name.clone(), to); 403 for dep in rustc_workspace[pkg].dependencies.iter() {
379 } 404 let name = CrateName::new(&dep.name).unwrap();
380 } 405 if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
381 } 406 for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() {
407 add_dep(&mut crate_graph, from, name.clone(), to);
382 } 408 }
409 }
410 }
411 }
412
413 // Add dependencies for all the crates of the current workspace to rustc_private libraries
414 for dep in rustc_workspace.packages() {
415 let name = CrateName::normalize_dashes(&rustc_workspace[dep].name);
383 416
384 // Add dependencies for all the crates of the current workspace to rustc_private libraries 417 if let Some(&to) = pkg_to_lib_crate.get(&dep) {
385 for dep in rustc_workspace.packages() { 418 for pkg in cargo.packages() {
386 let name = CrateName::normalize_dashes(&rustc_workspace[dep].name); 419 if !cargo[pkg].is_member {
387 420 continue;
388 if let Some(&to) = pkg_to_lib_crate.get(&dep) { 421 }
389 for pkg in cargo.packages() { 422 for &from in pkg_crates.get(&pkg).into_iter().flatten() {
390 if !cargo[pkg].is_member { 423 add_dep(&mut crate_graph, from, name.clone(), to);
391 continue;
392 }
393 for &from in pkg_crates.get(&pkg).into_iter().flatten() {
394 add_dep(&mut crate_graph, from, name.clone(), to);
395 }
396 }
397 }
398 } 424 }
399 } 425 }
400 } 426 }
401 } 427 }
402 if crate_graph.patch_cfg_if() {
403 log::debug!("Patched std to depend on cfg-if")
404 } else {
405 log::debug!("Did not patch std to depend on cfg-if")
406 }
407 crate_graph
408 } 428 }
429 crate_graph
409} 430}
410 431
411fn add_target_crate_root( 432fn add_target_crate_root(