2
2
//! metadata` or `rust-project.json`) into representation stored in the salsa
3
3
//! database -- `CrateGraph`.
4
4
5
- use std:: { collections:: VecDeque , fmt, fs, process:: Command , sync:: Arc } ;
5
+ use std:: {
6
+ collections:: { hash_map:: Entry , VecDeque } ,
7
+ fmt, fs,
8
+ process:: Command ,
9
+ sync:: Arc ,
10
+ } ;
6
11
7
12
use anyhow:: { format_err, Context , Result } ;
8
13
use base_db:: {
@@ -858,32 +863,6 @@ fn cargo_to_crate_graph(
858
863
for pkg in cargo. packages ( ) {
859
864
has_private |= cargo[ pkg] . metadata . rustc_private ;
860
865
861
- let cfg_options = {
862
- let mut cfg_options = cfg_options. clone ( ) ;
863
-
864
- // Add test cfg for local crates
865
- if cargo[ pkg] . is_local {
866
- cfg_options. insert_atom ( "test" . into ( ) ) ;
867
- }
868
-
869
- let overrides = match override_cfg {
870
- CfgOverrides :: Wildcard ( cfg_diff) => Some ( cfg_diff) ,
871
- CfgOverrides :: Selective ( cfg_overrides) => cfg_overrides. get ( & cargo[ pkg] . name ) ,
872
- } ;
873
-
874
- if let Some ( overrides) = overrides {
875
- // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen
876
- // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while
877
- // working on rust-lang/rust as that's the only time it appears outside sysroot).
878
- //
879
- // A more ideal solution might be to reanalyze crates based on where the cursor is and
880
- // figure out the set of cfgs that would have to apply to make it active.
881
-
882
- cfg_options. apply_diff ( overrides. clone ( ) ) ;
883
- } ;
884
- cfg_options
885
- } ;
886
-
887
866
let mut lib_tgt = None ;
888
867
for & tgt in cargo[ pkg] . targets . iter ( ) {
889
868
if cargo[ tgt] . kind != TargetKind :: Lib && !cargo[ pkg] . is_member {
@@ -894,7 +873,7 @@ fn cargo_to_crate_graph(
894
873
// https://github.com/rust-lang/rust-analyzer/issues/11300
895
874
continue ;
896
875
}
897
- let Some ( file_id) = load ( & cargo[ tgt] . root ) else { continue } ;
876
+ let Some ( file_id) = load ( & cargo[ tgt] . root ) else { continue } ;
898
877
899
878
let crate_id = add_target_crate_root (
900
879
crate_graph,
@@ -922,15 +901,19 @@ fn cargo_to_crate_graph(
922
901
pkg_crates. entry ( pkg) . or_insert_with ( Vec :: new) . push ( ( crate_id, cargo[ tgt] . kind ) ) ;
923
902
}
924
903
904
+ let Some ( targets) = pkg_crates. get ( & pkg) else { continue } ;
925
905
// Set deps to the core, std and to the lib target of the current package
926
- for & ( from, kind) in pkg_crates . get ( & pkg ) . into_iter ( ) . flatten ( ) {
906
+ for & ( from, kind) in targets {
927
907
// Add sysroot deps first so that a lib target named `core` etc. can overwrite them.
928
908
public_deps. add_to_crate_graph ( crate_graph, from) ;
929
909
930
910
// Add dep edge of all targets to the package's lib target
931
911
if let Some ( ( to, name) ) = lib_tgt. clone ( ) {
932
- if to != from && kind != TargetKind :: BuildScript {
933
- // (build script can not depend on its library target)
912
+ if to != from {
913
+ if kind == TargetKind :: BuildScript {
914
+ // build script can not depend on its library target
915
+ continue ;
916
+ }
934
917
935
918
// For root projects with dashes in their name,
936
919
// cargo metadata does not do any normalization,
@@ -942,6 +925,40 @@ fn cargo_to_crate_graph(
942
925
}
943
926
}
944
927
928
+ // Map from crate id to it's dev-dependency clone id
929
+ let mut test_dupes = FxHashMap :: default ( ) ;
930
+ let mut work = vec ! [ ] ;
931
+
932
+ // Get all dependencies of the workspace members that are used as dev-dependencies
933
+ for pkg in cargo. packages ( ) {
934
+ for dep in & cargo[ pkg] . dependencies {
935
+ if dep. kind == DepKind :: Dev {
936
+ work. push ( dep. pkg ) ;
937
+ }
938
+ }
939
+ }
940
+ while let Some ( pkg) = work. pop ( ) {
941
+ let Some ( & to) = pkg_to_lib_crate. get ( & pkg) else { continue } ;
942
+ match test_dupes. entry ( to) {
943
+ Entry :: Occupied ( _) => continue ,
944
+ Entry :: Vacant ( v) => {
945
+ for dep in & cargo[ pkg] . dependencies {
946
+ if dep. kind == DepKind :: Normal {
947
+ work. push ( dep. pkg ) ;
948
+ }
949
+ }
950
+ v. insert ( {
951
+ let duped = crate_graph. duplicate ( to) ;
952
+ if let Some ( proc_macro) = proc_macros. get ( & to) . cloned ( ) {
953
+ proc_macros. insert ( duped, proc_macro) ;
954
+ }
955
+ crate_graph[ duped] . cfg_options . insert_atom ( "test" . into ( ) ) ;
956
+ duped
957
+ } ) ;
958
+ }
959
+ }
960
+ }
961
+
945
962
// Now add a dep edge from all targets of upstream to the lib
946
963
// target of downstream.
947
964
for pkg in cargo. packages ( ) {
@@ -955,12 +972,65 @@ fn cargo_to_crate_graph(
955
972
if ( dep. kind == DepKind :: Build ) != ( kind == TargetKind :: BuildScript ) {
956
973
continue ;
957
974
}
975
+ add_dep (
976
+ crate_graph,
977
+ from,
978
+ name. clone ( ) ,
979
+ if dep. kind == DepKind :: Dev {
980
+ // point to the test enabled duplicate for dev-dependencies
981
+ test_dupes. get ( & to) . copied ( ) . unwrap ( )
982
+ } else {
983
+ to
984
+ } ,
985
+ ) ;
986
+
987
+ if dep. kind == DepKind :: Normal {
988
+ // Also apply the dependency as a test enabled dependency to the test duplicate
989
+ if let Some ( & dupe) = test_dupes. get ( & from) {
990
+ let to = test_dupes. get ( & to) . copied ( ) . unwrap_or_else ( || {
991
+ panic ! (
992
+ "dependency of a dev dependency did not get duplicated! {:?} {:?}" ,
993
+ crate_graph[ to] . display_name, crate_graph[ from] . display_name,
994
+ )
995
+ } ) ;
996
+ add_dep ( crate_graph, dupe, name. clone ( ) , to) ;
997
+ }
998
+ }
999
+ }
1000
+ }
1001
+ }
958
1002
959
- add_dep ( crate_graph, from, name. clone ( ) , to)
1003
+ for ( & pkg, targets) in & pkg_crates {
1004
+ for & ( krate, _) in targets {
1005
+ if test_dupes. get ( & krate) . is_some ( ) {
1006
+ continue ;
1007
+ }
1008
+ let cfg_options = & mut crate_graph[ krate] . cfg_options ;
1009
+
1010
+ // Add test cfg for local crates
1011
+ if cargo[ pkg] . is_local {
1012
+ cfg_options. insert_atom ( "test" . into ( ) ) ;
960
1013
}
1014
+
1015
+ let overrides = match override_cfg {
1016
+ CfgOverrides :: Wildcard ( cfg_diff) => Some ( cfg_diff) ,
1017
+ CfgOverrides :: Selective ( cfg_overrides) => cfg_overrides. get ( & cargo[ pkg] . name ) ,
1018
+ } ;
1019
+
1020
+ if let Some ( overrides) = overrides {
1021
+ // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen
1022
+ // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while
1023
+ // working on rust-lang/rust as that's the only time it appears outside sysroot).
1024
+ //
1025
+ // A more ideal solution might be to reanalyze crates based on where the cursor is and
1026
+ // figure out the set of cfgs that would have to apply to make it active.
1027
+
1028
+ cfg_options. apply_diff ( overrides. clone ( ) ) ;
1029
+ } ;
961
1030
}
962
1031
}
963
1032
1033
+ // FIXME: Handle rustc private crates properly when used as dev-dependencies
964
1034
if has_private {
965
1035
// If the user provided a path to rustc sources, we add all the rustc_private crates
966
1036
// and create dependencies on them for the crates which opt-in to that
@@ -1325,10 +1395,12 @@ fn sysroot_to_crate_graph(
1325
1395
( public_deps, libproc_macro)
1326
1396
}
1327
1397
1398
+ #[ track_caller]
1328
1399
fn add_dep ( graph : & mut CrateGraph , from : CrateId , name : CrateName , to : CrateId ) {
1329
1400
add_dep_inner ( graph, from, Dependency :: new ( name, to) )
1330
1401
}
1331
1402
1403
+ #[ track_caller]
1332
1404
fn add_dep_with_prelude (
1333
1405
graph : & mut CrateGraph ,
1334
1406
from : CrateId ,
@@ -1339,13 +1411,18 @@ fn add_dep_with_prelude(
1339
1411
add_dep_inner ( graph, from, Dependency :: with_prelude ( name, to, prelude) )
1340
1412
}
1341
1413
1414
+ #[ track_caller]
1342
1415
fn add_proc_macro_dep ( crate_graph : & mut CrateGraph , from : CrateId , to : CrateId , prelude : bool ) {
1343
1416
add_dep_with_prelude ( crate_graph, from, CrateName :: new ( "proc_macro" ) . unwrap ( ) , to, prelude) ;
1344
1417
}
1345
1418
1419
+ #[ track_caller]
1346
1420
fn add_dep_inner ( graph : & mut CrateGraph , from : CrateId , dep : Dependency ) {
1347
1421
if let Err ( err) = graph. add_dep ( from, dep) {
1348
- tracing:: error!( "{}" , err)
1422
+ if cfg ! ( test) {
1423
+ panic ! ( "{}" , err) ;
1424
+ }
1425
+ tracing:: error!( "{}" , err) ;
1349
1426
}
1350
1427
}
1351
1428
0 commit comments