33#![ feature( is_sorted) ]
44#![ cfg_attr( feature = "deny-warnings" , deny( warnings) ) ]
55#![ warn( rust_2018_idioms, unused_lifetimes) ]
6+ #![ allow( unused_extern_crates) ]
67
78use compiletest:: { status_emitter, CommandBuilder } ;
89use ui_test as compiletest;
910use ui_test:: Mode as TestMode ;
1011
12+ use std:: collections:: BTreeMap ;
1113use std:: env:: { self , remove_var, set_var, var_os} ;
1214use std:: ffi:: { OsStr , OsString } ;
1315use std:: fs;
1416use std:: path:: { Path , PathBuf } ;
17+ use std:: sync:: LazyLock ;
1518use test_utils:: IS_RUSTC_TEST_SUITE ;
1619
20+ // Test dependencies may need an `extern crate` here to ensure that they show up
21+ // in the depinfo file (otherwise cargo thinks they are unused)
22+ extern crate clippy_lints;
23+ extern crate clippy_utils;
24+ extern crate derive_new;
25+ extern crate futures;
26+ extern crate if_chain;
27+ extern crate itertools;
28+ extern crate parking_lot;
29+ extern crate quote;
30+ extern crate syn;
31+ extern crate tokio;
32+
33+ /// All crates used in UI tests are listed here
34+ static TEST_DEPENDENCIES : & [ & str ] = & [
35+ "clippy_lints" ,
36+ "clippy_utils" ,
37+ "derive_new" ,
38+ "futures" ,
39+ "if_chain" ,
40+ "itertools" ,
41+ "parking_lot" ,
42+ "quote" ,
43+ "regex" ,
44+ "serde_derive" ,
45+ "serde" ,
46+ "syn" ,
47+ "tokio" ,
48+ ] ;
49+
50+ /// Produces a string with an `--extern` flag for all UI test crate
51+ /// dependencies.
52+ ///
53+ /// The dependency files are located by parsing the depinfo file for this test
54+ /// module. This assumes the `-Z binary-dep-depinfo` flag is enabled. All test
55+ /// dependencies must be added to Cargo.toml at the project root. Test
56+ /// dependencies that are not *directly* used by this test module require an
57+ /// `extern crate` declaration.
58+ static EXTERN_FLAGS : LazyLock < Vec < String > > = LazyLock :: new ( || {
59+ let current_exe_depinfo = {
60+ let mut path = env:: current_exe ( ) . unwrap ( ) ;
61+ path. set_extension ( "d" ) ;
62+ fs:: read_to_string ( path) . unwrap ( )
63+ } ;
64+ let mut crates = BTreeMap :: < & str , & str > :: new ( ) ;
65+ for line in current_exe_depinfo. lines ( ) {
66+ // each dependency is expected to have a Makefile rule like `/path/to/crate-hash.rlib:`
67+ let parse_name_path = || {
68+ if line. starts_with ( char:: is_whitespace) {
69+ return None ;
70+ }
71+ let path_str = line. strip_suffix ( ':' ) ?;
72+ let path = Path :: new ( path_str) ;
73+ if !matches ! ( path. extension( ) ?. to_str( ) ?, "rlib" | "so" | "dylib" | "dll" ) {
74+ return None ;
75+ }
76+ let ( name, _hash) = path. file_stem ( ) ?. to_str ( ) ?. rsplit_once ( '-' ) ?;
77+ // the "lib" prefix is not present for dll files
78+ let name = name. strip_prefix ( "lib" ) . unwrap_or ( name) ;
79+ Some ( ( name, path_str) )
80+ } ;
81+ if let Some ( ( name, path) ) = parse_name_path ( ) {
82+ if TEST_DEPENDENCIES . contains ( & name) {
83+ // A dependency may be listed twice if it is available in sysroot,
84+ // and the sysroot dependencies are listed first. As of the writing,
85+ // this only seems to apply to if_chain.
86+ crates. insert ( name, path) ;
87+ }
88+ }
89+ }
90+ let not_found: Vec < & str > = TEST_DEPENDENCIES
91+ . iter ( )
92+ . copied ( )
93+ . filter ( |n| !crates. contains_key ( n) )
94+ . collect ( ) ;
95+ assert ! (
96+ not_found. is_empty( ) ,
97+ "dependencies not found in depinfo: {not_found:?}\n \
98+ help: Make sure the `-Z binary-dep-depinfo` rust flag is enabled\n \
99+ help: Try adding to dev-dependencies in Cargo.toml\n \
100+ help: Be sure to also add `extern crate ...;` to tests/compile-test.rs",
101+ ) ;
102+ crates
103+ . into_iter ( )
104+ . map ( |( name, path) | format ! ( "--extern={name}={path}" ) )
105+ . collect ( )
106+ } ) ;
107+
17108mod test_utils;
18109
19110// whether to run internal tests or not
@@ -29,7 +120,6 @@ fn base_config(test_dir: &str) -> compiletest::Config {
29120 } else {
30121 compiletest:: OutputConflictHandling :: Error ( "cargo test -- -- --bless" . into ( ) )
31122 } ,
32- dependencies_crate_manifest_path : Some ( "clippy_test_deps/Cargo.toml" . into ( ) ) ,
33123 target : None ,
34124 out_dir : "target/ui_test" . into ( ) ,
35125 ..compiletest:: Config :: rustc ( Path :: new ( "tests" ) . join ( test_dir) )
@@ -44,10 +134,23 @@ fn base_config(test_dir: &str) -> compiletest::Config {
44134 let deps_path = current_exe_path. parent ( ) . unwrap ( ) ;
45135 let profile_path = deps_path. parent ( ) . unwrap ( ) ;
46136
47- config. program . args . push ( "--emit=metadata" . into ( ) ) ;
48- config. program . args . push ( "-Aunused" . into ( ) ) ;
49- config. program . args . push ( "-Zui-testing" . into ( ) ) ;
50- config. program . args . push ( "-Dwarnings" . into ( ) ) ;
137+ config. program . args . extend (
138+ [
139+ "--emit=metadata" ,
140+ "-Aunused" ,
141+ "-Zui-testing" ,
142+ "-Dwarnings" ,
143+ & format ! ( "-Ldependency={}" , deps_path. display( ) ) ,
144+ ]
145+ . map ( OsString :: from) ,
146+ ) ;
147+
148+ config. program . args . extend ( EXTERN_FLAGS . iter ( ) . map ( OsString :: from) ) ;
149+
150+ if let Some ( host_libs) = option_env ! ( "HOST_LIBS" ) {
151+ let dep = format ! ( "-Ldependency={}" , Path :: new( host_libs) . join( "deps" ) . display( ) ) ;
152+ config. program . args . push ( dep. into ( ) ) ;
153+ }
51154
52155 // Normalize away slashes in windows paths.
53156 config. stderr_filter ( r"\\" , "/" ) ;
@@ -105,9 +208,7 @@ fn run_internal_tests() {
105208 if !RUN_INTERNAL_TESTS {
106209 return ;
107210 }
108- let mut config = base_config ( "ui-internal" ) ;
109- config. dependency_builder . args . push ( "--features" . into ( ) ) ;
110- config. dependency_builder . args . push ( "internal" . into ( ) ) ;
211+ let config = base_config ( "ui-internal" ) ;
111212 compiletest:: run_tests ( config) . unwrap ( ) ;
112213}
113214
@@ -165,7 +266,6 @@ fn run_ui_cargo() {
165266 . push ( ( "RUSTFLAGS" . into ( ) , Some ( "-Dwarnings" . into ( ) ) ) ) ;
166267 // We need to do this while we still have a rustc in the `program` field.
167268 config. fill_host_and_target ( ) . unwrap ( ) ;
168- config. dependencies_crate_manifest_path = None ;
169269 config. program . program . set_file_name ( if cfg ! ( windows) {
170270 "cargo-clippy.exe"
171271 } else {
0 commit comments