| 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 std::fs; |
| 9 | use std::path::Path; |
| 10 | use tar::Archive; |
| 11 | use walkdir::DirEntry; |
| 12 | |
| 13 | const REVISION: &str = "98ad6a5519651af36e246c0335c964dd52c554ba" ; |
| 14 | |
| 15 | #[rustfmt::skip] |
| 16 | static EXCLUDE_FILES: &[&str] = &[ |
| 17 | // TODO: impl ~const T {} |
| 18 | // https://github.com/dtolnay/syn/issues/1051 |
| 19 | "src/test/ui/rfc-2632-const-trait-impl/syntax.rs" , |
| 20 | |
| 21 | // Compile-fail expr parameter in const generic position: f::<1 + 2>() |
| 22 | "src/test/ui/const-generics/early/closing-args-token.rs" , |
| 23 | "src/test/ui/const-generics/early/const-expression-parameter.rs" , |
| 24 | |
| 25 | // Need at least one trait in impl Trait, no such type as impl 'static |
| 26 | "src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs" , |
| 27 | |
| 28 | // Deprecated anonymous parameter syntax in traits |
| 29 | "src/test/ui/issues/issue-13105.rs" , |
| 30 | "src/test/ui/issues/issue-13775.rs" , |
| 31 | "src/test/ui/issues/issue-34074.rs" , |
| 32 | "src/test/ui/proc-macro/trait-fn-args-2015.rs" , |
| 33 | "src/tools/rustfmt/tests/source/trait.rs" , |
| 34 | "src/tools/rustfmt/tests/target/trait.rs" , |
| 35 | |
| 36 | // Various extensions to Rust syntax made up by rust-analyzer |
| 37 | "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0012_type_item_where_clause.rs" , |
| 38 | "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0040_crate_keyword_vis.rs" , |
| 39 | "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0131_existential_type.rs" , |
| 40 | "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0179_use_tree_abs_star.rs" , |
| 41 | "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rs" , |
| 42 | "src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0015_use_tree.rs" , |
| 43 | "src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0029_range_forms.rs" , |
| 44 | "src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs" , |
| 45 | "src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0055_dot_dot_dot.rs" , |
| 46 | "src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0068_item_modifiers.rs" , |
| 47 | "src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0031_block_inner_attrs.rs" , |
| 48 | "src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0045_ambiguous_trait_object.rs" , |
| 49 | "src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0046_mutable_const_item.rs" , |
| 50 | |
| 51 | // Placeholder syntax for "throw expressions" |
| 52 | "src/test/pretty/yeet-expr.rs" , |
| 53 | "src/test/ui/try-trait/yeet-for-option.rs" , |
| 54 | "src/test/ui/try-trait/yeet-for-result.rs" , |
| 55 | |
| 56 | // Excessive nesting |
| 57 | "src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs" , |
| 58 | |
| 59 | // Testing tools on invalid syntax |
| 60 | "src/test/run-make/translation/test.rs" , |
| 61 | "src/test/ui/generics/issue-94432-garbage-ice.rs" , |
| 62 | "src/tools/rustfmt/tests/coverage/target/comments.rs" , |
| 63 | "src/tools/rustfmt/tests/parser/issue-4126/invalid.rs" , |
| 64 | "src/tools/rustfmt/tests/parser/issue_4418.rs" , |
| 65 | "src/tools/rustfmt/tests/parser/unclosed-delims/issue_4466.rs" , |
| 66 | "src/tools/rustfmt/tests/source/configs/disable_all_formatting/true.rs" , |
| 67 | "src/tools/rustfmt/tests/source/configs/spaces_around_ranges/false.rs" , |
| 68 | "src/tools/rustfmt/tests/source/configs/spaces_around_ranges/true.rs" , |
| 69 | "src/tools/rustfmt/tests/source/type.rs" , |
| 70 | "src/tools/rustfmt/tests/target/configs/spaces_around_ranges/false.rs" , |
| 71 | "src/tools/rustfmt/tests/target/configs/spaces_around_ranges/true.rs" , |
| 72 | "src/tools/rustfmt/tests/target/type.rs" , |
| 73 | |
| 74 | // Generated file containing a top-level expression, used with `include!` |
| 75 | "compiler/rustc_codegen_gcc/src/intrinsic/archs.rs" , |
| 76 | |
| 77 | // Clippy lint lists represented as expressions |
| 78 | "src/tools/clippy/clippy_lints/src/lib.deprecated.rs" , |
| 79 | "src/tools/clippy/clippy_lints/src/lib.register_all.rs" , |
| 80 | "src/tools/clippy/clippy_lints/src/lib.register_cargo.rs" , |
| 81 | "src/tools/clippy/clippy_lints/src/lib.register_complexity.rs" , |
| 82 | "src/tools/clippy/clippy_lints/src/lib.register_correctness.rs" , |
| 83 | "src/tools/clippy/clippy_lints/src/lib.register_internal.rs" , |
| 84 | "src/tools/clippy/clippy_lints/src/lib.register_lints.rs" , |
| 85 | "src/tools/clippy/clippy_lints/src/lib.register_nursery.rs" , |
| 86 | "src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs" , |
| 87 | "src/tools/clippy/clippy_lints/src/lib.register_perf.rs" , |
| 88 | "src/tools/clippy/clippy_lints/src/lib.register_restriction.rs" , |
| 89 | "src/tools/clippy/clippy_lints/src/lib.register_style.rs" , |
| 90 | "src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs" , |
| 91 | |
| 92 | // Not actually test cases |
| 93 | "src/test/ui/lint/expansion-time-include.rs" , |
| 94 | "src/test/ui/macros/auxiliary/macro-comma-support.rs" , |
| 95 | "src/test/ui/macros/auxiliary/macro-include-items-expr.rs" , |
| 96 | "src/test/ui/macros/include-single-expr-helper.rs" , |
| 97 | "src/test/ui/macros/include-single-expr-helper-1.rs" , |
| 98 | "src/test/ui/parser/issues/auxiliary/issue-21146-inc.rs" , |
| 99 | ]; |
| 100 | |
| 101 | #[rustfmt::skip] |
| 102 | static EXCLUDE_DIRS: &[&str] = &[ |
| 103 | // Inputs that intentionally do not parse |
| 104 | "src/tools/rust-analyzer/crates/parser/test_data/parser/err" , |
| 105 | "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err" , |
| 106 | |
| 107 | // Inputs that lex but do not necessarily parse |
| 108 | "src/tools/rust-analyzer/crates/parser/test_data/lexer" , |
| 109 | |
| 110 | // Inputs that used to crash rust-analyzer, but aren't necessarily supposed to parse |
| 111 | "src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures" , |
| 112 | "src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures" , |
| 113 | ]; |
| 114 | |
| 115 | pub fn base_dir_filter(entry: &DirEntry) -> bool { |
| 116 | let path = entry.path(); |
| 117 | |
| 118 | let mut path_string = path.to_string_lossy(); |
| 119 | if cfg!(windows) { |
| 120 | path_string = path_string.replace(' \\' , "/" ).into(); |
| 121 | } |
| 122 | let path_string = if path_string == "tests/rust" { |
| 123 | return true; |
| 124 | } else if let Some(path) = path_string.strip_prefix("tests/rust/" ) { |
| 125 | path |
| 126 | } else { |
| 127 | panic!("unexpected path in Rust dist: {}" , path_string); |
| 128 | }; |
| 129 | |
| 130 | if path.is_dir() { |
| 131 | return !EXCLUDE_DIRS.contains(&path_string); |
| 132 | } |
| 133 | |
| 134 | if path.extension().map_or(true, |e| e != "rs" ) { |
| 135 | return false; |
| 136 | } |
| 137 | |
| 138 | if path_string.starts_with("src/test/ui" ) || path_string.starts_with("src/test/rustdoc-ui" ) { |
| 139 | let stderr_path = path.with_extension("stderr" ); |
| 140 | if stderr_path.exists() { |
| 141 | // Expected to fail in some way |
| 142 | return false; |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | !EXCLUDE_FILES.contains(&path_string) |
| 147 | } |
| 148 | |
| 149 | #[allow (dead_code)] |
| 150 | pub fn edition(path: &Path) -> &'static str { |
| 151 | if path.ends_with("dyn-2015-no-warnings-without-lints.rs" ) { |
| 152 | "2015" |
| 153 | } else { |
| 154 | "2018" |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | pub fn clone_rust() { |
| 159 | let needs_clone = match fs::read_to_string("tests/rust/COMMIT" ) { |
| 160 | Err(_) => true, |
| 161 | Ok(contents) => contents.trim() != REVISION, |
| 162 | }; |
| 163 | if needs_clone { |
| 164 | download_and_unpack().unwrap(); |
| 165 | } |
| 166 | let mut missing = String::new(); |
| 167 | let test_src = Path::new("tests/rust" ); |
| 168 | for exclude in EXCLUDE_FILES { |
| 169 | if !test_src.join(exclude).is_file() { |
| 170 | missing += " \ntests/rust/" ; |
| 171 | missing += exclude; |
| 172 | } |
| 173 | } |
| 174 | for exclude in EXCLUDE_DIRS { |
| 175 | if !test_src.join(exclude).is_dir() { |
| 176 | missing += " \ntests/rust/" ; |
| 177 | missing += exclude; |
| 178 | missing += "/" ; |
| 179 | } |
| 180 | } |
| 181 | if !missing.is_empty() { |
| 182 | panic!("excluded test file does not exist:{} \n" , missing); |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | fn download_and_unpack() -> Result<()> { |
| 187 | let url = format!( |
| 188 | "https://github.com/rust-lang/rust/archive/{}.tar.gz" , |
| 189 | REVISION |
| 190 | ); |
| 191 | let response = reqwest::blocking::get(url)?.error_for_status()?; |
| 192 | let progress = Progress::new(response); |
| 193 | let decoder = GzDecoder::new(progress); |
| 194 | let mut archive = Archive::new(decoder); |
| 195 | let prefix = format!("rust-{}" , REVISION); |
| 196 | |
| 197 | let tests_rust = Path::new("tests/rust" ); |
| 198 | if tests_rust.exists() { |
| 199 | fs::remove_dir_all(tests_rust)?; |
| 200 | } |
| 201 | |
| 202 | for entry in archive.entries()? { |
| 203 | let mut entry = entry?; |
| 204 | let path = entry.path()?; |
| 205 | if path == Path::new("pax_global_header" ) { |
| 206 | continue; |
| 207 | } |
| 208 | let relative = path.strip_prefix(&prefix)?; |
| 209 | let out = tests_rust.join(relative); |
| 210 | entry.unpack(&out)?; |
| 211 | } |
| 212 | |
| 213 | fs::write("tests/rust/COMMIT" , REVISION)?; |
| 214 | Ok(()) |
| 215 | } |
| 216 | |