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