• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #![allow(clippy::manual_assert)]
2 
3 mod progress;
4 
5 use self::progress::Progress;
6 use anyhow::Result;
7 use flate2::read::GzDecoder;
8 use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
9 use std::collections::BTreeSet;
10 use std::ffi::OsStr;
11 use std::fs;
12 use std::path::{Path, PathBuf};
13 use tar::Archive;
14 use walkdir::{DirEntry, WalkDir};
15 
16 const REVISION: &str = "9f5fc1bd443f59583e7af0d94d289f95fe1e20c4";
17 
18 #[rustfmt::skip]
19 static EXCLUDE_FILES: &[&str] = &[
20     // TODO: CStr literals: c"…", cr"…"
21     // https://github.com/dtolnay/syn/issues/1502
22     "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rs",
23 
24     // TODO: explicit tail calls: `become _g()`
25     // https://github.com/dtolnay/syn/issues/1501
26     "tests/ui/explicit-tail-calls/return-lifetime-sub.rs",
27 
28     // TODO: non-lifetime binders: `where for<'a, T> &'a Struct<T>: Trait`
29     // https://github.com/dtolnay/syn/issues/1435
30     "tests/rustdoc-json/non_lifetime_binders.rs",
31     "tests/rustdoc/non_lifetime_binders.rs",
32 
33     // TODO: return type notation: `where T: Trait<method(): Send>`
34     // https://github.com/dtolnay/syn/issues/1434
35     "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0208_associated_return_type_bounds.rs",
36     "tests/ui/associated-type-bounds/return-type-notation/basic.rs",
37     "tests/ui/feature-gates/feature-gate-return_type_notation.rs",
38 
39     // Compile-fail expr parameter in const generic position: f::<1 + 2>()
40     "tests/ui/const-generics/early/closing-args-token.rs",
41     "tests/ui/const-generics/early/const-expression-parameter.rs",
42 
43     // Compile-fail variadics in not the last position of a function parameter list
44     "tests/ui/parser/variadic-ffi-syntactic-pass.rs",
45 
46     // Need at least one trait in impl Trait, no such type as impl 'static
47     "tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs",
48 
49     // Negative polarity trait bound: `where T: !Copy`
50     "src/tools/rustfmt/tests/target/negative-bounds.rs",
51 
52     // Lifetime bound inside for<>: `T: ~const ?for<'a: 'b> Trait<'a>`
53     "tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs",
54 
55     // Const impl that is not a trait impl: `impl ~const T {}`
56     "tests/ui/rfcs/rfc-2632-const-trait-impl/syntax.rs",
57 
58     // Deprecated anonymous parameter syntax in traits
59     "src/tools/rustfmt/tests/source/trait.rs",
60     "src/tools/rustfmt/tests/target/trait.rs",
61     "tests/ui/issues/issue-13105.rs",
62     "tests/ui/issues/issue-13775.rs",
63     "tests/ui/issues/issue-34074.rs",
64     "tests/ui/proc-macro/trait-fn-args-2015.rs",
65 
66     // Deprecated where-clause location
67     "src/tools/rustfmt/tests/source/issue_4257.rs",
68     "src/tools/rustfmt/tests/source/issue_4911.rs",
69     "src/tools/rustfmt/tests/target/issue_4257.rs",
70     "src/tools/rustfmt/tests/target/issue_4911.rs",
71     "tests/pretty/gat-bounds.rs",
72     "tests/rustdoc/generic-associated-types/gats.rs",
73 
74     // Deprecated trait object syntax with parenthesized generic arguments and no dyn keyword
75     "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rs",
76     "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0104_path_fn_trait_args.rs",
77     "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs",
78     "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0209_bare_dyn_types_with_paren_as_generic_args.rs",
79     "src/tools/rustfmt/tests/source/attrib.rs",
80     "src/tools/rustfmt/tests/source/closure.rs",
81     "src/tools/rustfmt/tests/source/existential_type.rs",
82     "src/tools/rustfmt/tests/source/fn-simple.rs",
83     "src/tools/rustfmt/tests/source/fn_args_layout-vertical.rs",
84     "src/tools/rustfmt/tests/source/issue-4689/one.rs",
85     "src/tools/rustfmt/tests/source/issue-4689/two.rs",
86     "src/tools/rustfmt/tests/source/paths.rs",
87     "src/tools/rustfmt/tests/source/structs.rs",
88     "src/tools/rustfmt/tests/target/attrib.rs",
89     "src/tools/rustfmt/tests/target/closure.rs",
90     "src/tools/rustfmt/tests/target/existential_type.rs",
91     "src/tools/rustfmt/tests/target/fn-simple.rs",
92     "src/tools/rustfmt/tests/target/fn.rs",
93     "src/tools/rustfmt/tests/target/fn_args_layout-vertical.rs",
94     "src/tools/rustfmt/tests/target/issue-4689/one.rs",
95     "src/tools/rustfmt/tests/target/issue-4689/two.rs",
96     "src/tools/rustfmt/tests/target/paths.rs",
97     "src/tools/rustfmt/tests/target/structs.rs",
98     "tests/codegen-units/item-collection/non-generic-closures.rs",
99     "tests/debuginfo/recursive-enum.rs",
100     "tests/pretty/closure-reform-pretty.rs",
101     "tests/run-make/reproducible-build-2/reproducible-build.rs",
102     "tests/run-make/reproducible-build/reproducible-build.rs",
103     "tests/ui/auxiliary/typeid-intrinsic-aux1.rs",
104     "tests/ui/auxiliary/typeid-intrinsic-aux2.rs",
105     "tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs",
106     "tests/ui/lifetimes/auxiliary/lifetime_bound_will_change_warning_lib.rs",
107     "tests/ui/lifetimes/bare-trait-object-borrowck.rs",
108     "tests/ui/lifetimes/bare-trait-object.rs",
109     "tests/ui/parser/bounds-obj-parens.rs",
110 
111     // Obsolete box syntax
112     "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rs",
113 
114     // Invalid unparenthesized range pattern inside slice pattern: `[1..]`
115     "tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs",
116 
117     // Various extensions to Rust syntax made up by rust-analyzer
118     "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0012_type_item_where_clause.rs",
119     "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rs",
120     "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rs",
121     "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0131_existential_type.rs",
122     "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rs",
123     "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0179_use_tree_abs_star.rs",
124     "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rs",
125     "src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0015_use_tree.rs",
126     "src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0029_range_forms.rs",
127     "src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs",
128     "src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0055_dot_dot_dot.rs",
129     "src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0068_item_modifiers.rs",
130     "src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0031_block_inner_attrs.rs",
131     "src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0038_endless_inclusive_range.rs",
132     "src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0045_ambiguous_trait_object.rs",
133     "src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0046_mutable_const_item.rs",
134 
135     // Placeholder syntax for "throw expressions"
136     "compiler/rustc_errors/src/translation.rs",
137     "src/tools/clippy/tests/ui/needless_return.rs",
138     "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0204_yeet_expr.rs",
139     "tests/pretty/yeet-expr.rs",
140     "tests/ui/try-trait/yeet-for-option.rs",
141     "tests/ui/try-trait/yeet-for-result.rs",
142 
143     // Edition 2015 code using identifiers that are now keywords
144     // TODO: some of these we should probably parse
145     "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_try_macro_fallback.rs",
146     "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_try_macro_rules.rs",
147     "src/tools/rustfmt/tests/source/configs/indent_style/block_call.rs",
148     "src/tools/rustfmt/tests/source/configs/use_try_shorthand/false.rs",
149     "src/tools/rustfmt/tests/source/configs/use_try_shorthand/true.rs",
150     "src/tools/rustfmt/tests/source/issue_1306.rs",
151     "src/tools/rustfmt/tests/source/try-conversion.rs",
152     "src/tools/rustfmt/tests/target/configs/indent_style/block_call.rs",
153     "src/tools/rustfmt/tests/target/configs/use_try_shorthand/false.rs",
154     "src/tools/rustfmt/tests/target/issue-1681.rs",
155     "src/tools/rustfmt/tests/target/issue_1306.rs",
156     "tests/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs",
157     "tests/ui/editions/edition-keywords-2015-2015.rs",
158     "tests/ui/editions/edition-keywords-2015-2018.rs",
159     "tests/ui/lint/lint_pre_expansion_extern_module_aux.rs",
160     "tests/ui/macros/macro-comma-support-rpass.rs",
161     "tests/ui/macros/try-macro.rs",
162     "tests/ui/parser/extern-crate-async.rs",
163     "tests/ui/try-block/try-is-identifier-edition2015.rs",
164 
165     // Excessive nesting
166     "tests/ui/issues/issue-74564-if-expr-stack-overflow.rs",
167 
168     // Testing tools on invalid syntax
169     "src/tools/rustfmt/tests/coverage/target/comments.rs",
170     "src/tools/rustfmt/tests/parser/issue-4126/invalid.rs",
171     "src/tools/rustfmt/tests/parser/issue_4418.rs",
172     "src/tools/rustfmt/tests/parser/unclosed-delims/issue_4466.rs",
173     "src/tools/rustfmt/tests/source/configs/disable_all_formatting/true.rs",
174     "src/tools/rustfmt/tests/source/configs/spaces_around_ranges/false.rs",
175     "src/tools/rustfmt/tests/source/configs/spaces_around_ranges/true.rs",
176     "src/tools/rustfmt/tests/source/type.rs",
177     "src/tools/rustfmt/tests/target/configs/spaces_around_ranges/false.rs",
178     "src/tools/rustfmt/tests/target/configs/spaces_around_ranges/true.rs",
179     "src/tools/rustfmt/tests/target/type.rs",
180     "tests/run-make/translation/test.rs",
181     "tests/ui/generics/issue-94432-garbage-ice.rs",
182 
183     // Generated file containing a top-level expression, used with `include!`
184     "compiler/rustc_codegen_gcc/src/intrinsic/archs.rs",
185 
186     // Clippy lint lists represented as expressions
187     "src/tools/clippy/clippy_lints/src/lib.deprecated.rs",
188 
189     // Not actually test cases
190     "tests/ui/lint/expansion-time-include.rs",
191     "tests/ui/macros/auxiliary/macro-comma-support.rs",
192     "tests/ui/macros/auxiliary/macro-include-items-expr.rs",
193     "tests/ui/macros/include-single-expr-helper.rs",
194     "tests/ui/macros/include-single-expr-helper-1.rs",
195     "tests/ui/parser/issues/auxiliary/issue-21146-inc.rs",
196 ];
197 
198 #[rustfmt::skip]
199 static EXCLUDE_DIRS: &[&str] = &[
200     // Inputs that intentionally do not parse
201     "src/tools/rust-analyzer/crates/parser/test_data/parser/err",
202     "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err",
203 
204     // Inputs that lex but do not necessarily parse
205     "src/tools/rust-analyzer/crates/parser/test_data/lexer",
206 
207     // Inputs that used to crash rust-analyzer, but aren't necessarily supposed to parse
208     "src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures",
209     "src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures",
210 ];
211 
212 // Directories in which a .stderr implies the corresponding .rs is not expected
213 // to work.
214 static UI_TEST_DIRS: &[&str] = &["tests/ui", "tests/rustdoc-ui"];
215 
for_each_rust_file(for_each: impl Fn(&Path) + Sync + Send)216 pub fn for_each_rust_file(for_each: impl Fn(&Path) + Sync + Send) {
217     let mut rs_files = BTreeSet::new();
218 
219     let repo_dir = Path::new("tests/rust");
220     for entry in WalkDir::new(repo_dir)
221         .into_iter()
222         .filter_entry(base_dir_filter)
223     {
224         let entry = entry.unwrap();
225         if !entry.file_type().is_dir() {
226             rs_files.insert(entry.into_path());
227         }
228     }
229 
230     for ui_test_dir in UI_TEST_DIRS {
231         for entry in WalkDir::new(repo_dir.join(ui_test_dir)) {
232             let mut path = entry.unwrap().into_path();
233             if path.extension() == Some(OsStr::new("stderr")) {
234                 loop {
235                     rs_files.remove(&path.with_extension("rs"));
236                     path = path.with_extension("");
237                     if path.extension().is_none() {
238                         break;
239                     }
240                 }
241             }
242         }
243     }
244 
245     rs_files.par_iter().map(PathBuf::as_path).for_each(for_each);
246 }
247 
base_dir_filter(entry: &DirEntry) -> bool248 pub fn base_dir_filter(entry: &DirEntry) -> bool {
249     let path = entry.path();
250 
251     let mut path_string = path.to_string_lossy();
252     if cfg!(windows) {
253         path_string = path_string.replace('\\', "/").into();
254     }
255     let path_string = if path_string == "tests/rust" {
256         return true;
257     } else if let Some(path) = path_string.strip_prefix("tests/rust/") {
258         path
259     } else {
260         panic!("unexpected path in Rust dist: {}", path_string);
261     };
262 
263     if path.is_dir() {
264         return !EXCLUDE_DIRS.contains(&path_string);
265     }
266 
267     if path.extension() != Some(OsStr::new("rs")) {
268         return false;
269     }
270 
271     !EXCLUDE_FILES.contains(&path_string)
272 }
273 
274 #[allow(dead_code)]
edition(path: &Path) -> &'static str275 pub fn edition(path: &Path) -> &'static str {
276     if path.ends_with("dyn-2015-no-warnings-without-lints.rs") {
277         "2015"
278     } else {
279         "2018"
280     }
281 }
282 
clone_rust()283 pub fn clone_rust() {
284     let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
285         Err(_) => true,
286         Ok(contents) => contents.trim() != REVISION,
287     };
288     if needs_clone {
289         download_and_unpack().unwrap();
290     }
291 
292     let mut missing = String::new();
293     let test_src = Path::new("tests/rust");
294 
295     let mut exclude_files_set = BTreeSet::new();
296     for exclude in EXCLUDE_FILES {
297         if !exclude_files_set.insert(exclude) {
298             panic!("duplicate path in EXCLUDE_FILES: {}", exclude);
299         }
300         for dir in EXCLUDE_DIRS {
301             if Path::new(exclude).starts_with(dir) {
302                 panic!("excluded file {} is inside an excluded dir", exclude);
303             }
304         }
305         if !test_src.join(exclude).is_file() {
306             missing += "\ntests/rust/";
307             missing += exclude;
308         }
309     }
310 
311     let mut exclude_dirs_set = BTreeSet::new();
312     for exclude in EXCLUDE_DIRS {
313         if !exclude_dirs_set.insert(exclude) {
314             panic!("duplicate path in EXCLUDE_DIRS: {}", exclude);
315         }
316         if !test_src.join(exclude).is_dir() {
317             missing += "\ntests/rust/";
318             missing += exclude;
319             missing += "/";
320         }
321     }
322 
323     if !missing.is_empty() {
324         panic!("excluded test file does not exist:{}\n", missing);
325     }
326 }
327 
download_and_unpack() -> Result<()>328 fn download_and_unpack() -> Result<()> {
329     let url = format!(
330         "https://github.com/rust-lang/rust/archive/{}.tar.gz",
331         REVISION
332     );
333     let response = reqwest::blocking::get(url)?.error_for_status()?;
334     let progress = Progress::new(response);
335     let decoder = GzDecoder::new(progress);
336     let mut archive = Archive::new(decoder);
337     let prefix = format!("rust-{}", REVISION);
338 
339     let tests_rust = Path::new("tests/rust");
340     if tests_rust.exists() {
341         fs::remove_dir_all(tests_rust)?;
342     }
343 
344     for entry in archive.entries()? {
345         let mut entry = entry?;
346         let path = entry.path()?;
347         if path == Path::new("pax_global_header") {
348             continue;
349         }
350         let relative = path.strip_prefix(&prefix)?;
351         let out = tests_rust.join(relative);
352         entry.unpack(&out)?;
353     }
354 
355     fs::write("tests/rust/COMMIT", REVISION)?;
356     Ok(())
357 }
358