Skip to content

Commit

Permalink
Add fixed_path_existence test
Browse files Browse the repository at this point in the history
  • Loading branch information
smoelius committed May 19, 2022
1 parent ea96091 commit 3e92ded
Show file tree
Hide file tree
Showing 33 changed files with 875 additions and 102 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,13 @@ if_chain = "1.0"
itertools = "0.10.1"
quote = "1.0"
serde = { version = "1.0.125", features = ["derive"] }
serde_json = "1.0"
syn = { version = "1.0", features = ["full"] }
futures = "0.3"
parking_lot = "0.11.2"
tokio = { version = "1", features = ["io-util"] }
rustc-semver = "1.1"
walkdir = "2.3"

[build-dependencies]
rustc_tools_util = { version = "0.2", path = "rustc_tools_util" }
Expand Down
3 changes: 3 additions & 0 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
{
if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
store.register_late_pass(|| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new()));
}

if std::env::var("DISABLE_STANDARD_LINTS").eq(&Ok("1".to_string())) {
return;
}
}
Expand Down
225 changes: 194 additions & 31 deletions tests/dogfood.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,43 +25,206 @@ fn dogfood_clippy() {
}
}

#[test]
#[ignore]
#[cfg(feature = "internal")]
fn run_metadata_collection_lint() {
use std::fs::File;
use std::time::SystemTime;

// Setup for validation
let metadata_output_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("util/gh-pages/lints.json");
let start_time = SystemTime::now();

// Run collection as is
std::env::set_var("ENABLE_METADATA_COLLECTION", "1");
run_clippy_for_package("clippy_lints", &["-A", "unfulfilled_lint_expectations"]);

// Check if cargo caching got in the way
if let Ok(file) = File::open(metadata_output_path) {
if let Ok(metadata) = file.metadata() {
if let Ok(last_modification) = metadata.modified() {
if last_modification > start_time {
// The output file has been modified. Most likely by a hungry
// metadata collection monster. So We'll return.
return;
#[cfg(all(test, feature = "internal"))]
mod internal {
use super::run_clippy_for_package;
use if_chain::if_chain;
use serde::Deserialize;
use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs::{read_to_string, File};
use std::io::BufReader;
use std::path::PathBuf;
use walkdir::WalkDir;

static UI_TEST_PATH: std::lazy::SyncLazy<PathBuf> =
std::lazy::SyncLazy::new(|| PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/ui"));

static METADATA_OUTPUT_PATH: std::lazy::SyncLazy<PathBuf> =
std::lazy::SyncLazy::new(|| PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("util/gh-pages/lints.json"));

#[derive(Debug, Deserialize)]
pub struct LintMetadata {
id: String,
applicability: Option<ApplicabilityInfo>,
}

#[derive(Debug, Deserialize)]
struct ApplicabilityInfo {
applicability: Option<String>,
}

const MACHINE_APPLICABLE: &str = "MachineApplicable";

const KNOWN_EXCEPTIONS: [&str; 33] = [
"assign_ops2.stderr",
"cast_size_32bit.stderr",
"char_lit_as_u8.stderr",
"cmp_owned/without_suggestion.stderr",
"dbg_macro.stderr",
"deref_addrof_double_trigger.stderr",
"doc/unbalanced_ticks.stderr",
"eprint_with_newline.stderr",
"explicit_counter_loop.stderr",
"iter_skip_next_unfixable.stderr",
"let_and_return.stderr",
"literals.stderr",
"map_flatten.stderr",
"map_unwrap_or.stderr",
"match_bool.stderr",
"mem_replace_macro.stderr",
"needless_arbitrary_self_type_unfixable.stderr",
"needless_borrow_pat.stderr",
"needless_for_each_unfixable.stderr",
"nonminimal_bool.stderr",
"print_literal.stderr",
"print_with_newline.stderr",
"redundant_static_lifetimes_multiple.stderr",
"result_map_unit_fn_unfixable.stderr",
"search_is_some.stderr",
"string_add.stderr",
"toplevel_ref_arg_non_rustfix.stderr",
"unit_arg.stderr",
"unnecessary_clone.stderr",
"unnecessary_lazy_eval_unfixable.stderr",
"write_literal_2.stderr",
"write_literal.stderr",
"write_with_newline.stderr",
];

#[test]
fn known_exceptions_accuracy() {
for filename in KNOWN_EXCEPTIONS {
let stderr_path = UI_TEST_PATH.join(filename);
assert!(
stderr_path.exists(),
"`{}` does not exists",
stderr_path.strip_prefix(env!("CARGO_MANIFEST_DIR")).unwrap().display()
);
let fixed_path = stderr_path.with_extension("fixed");
assert!(
!fixed_path.exists(),
"`{}` exists",
fixed_path.strip_prefix(env!("CARGO_MANIFEST_DIR")).unwrap().display()
);
}
}

#[test]
fn fixed_path_existence() {
collect_metadata(false);

let lints = read_metadata();

let mut lint_map = HashMap::new();
for lint in lints {
lint_map.insert(lint.id, lint.applicability.and_then(|app| app.applicability));
}

for entry in WalkDir::new(&*UI_TEST_PATH) {
let entry = entry.unwrap();

if KNOWN_EXCEPTIONS.contains(&&*entry.path().strip_prefix(&*UI_TEST_PATH).unwrap().to_string_lossy()) {
continue;
}

if entry.path().extension() != Some(OsStr::new("stderr")) {
continue;
};

let stderr_path = entry.path();

let stderr_contents = read_to_string(stderr_path).unwrap();

let lint_ids = stderr_contents.lines().filter_map(|line| {
const PREFIX: &str = "`-D clippy::";
const SUFFIX: &str = "`";
if_chain! {
if let Some(start) = line.find(PREFIX).map(|n| n + PREFIX.len());
if let Some(end) = line[start..].find(SUFFIX);
then {
Some(line[start..][..end].replace('-', "_"))
} else {
None
}
}
});

let mach_app_lint_ids = lint_ids
.filter(|id| {
lint_map
.get(id)
.unwrap()
.as_ref()
.map_or(false, |s| s == MACHINE_APPLICABLE)
})
.collect::<Vec<_>>();

if !mach_app_lint_ids.is_empty() {
let fixed_path = stderr_path.with_extension("fixed");
assert!(
fixed_path.exists(),
"`{}` does not exist though `{}` mentions the following `{}` lints: {:#?}",
fixed_path.strip_prefix(env!("CARGO_MANIFEST_DIR")).unwrap().display(),
stderr_path.strip_prefix(env!("CARGO_MANIFEST_DIR")).unwrap().display(),
MACHINE_APPLICABLE,
mach_app_lint_ids
);
}
}
}

// Force cargo to invalidate the caches
filetime::set_file_mtime(
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("clippy_lints/src/lib.rs"),
filetime::FileTime::now(),
)
.unwrap();
#[test]
#[ignore]
fn run_metadata_collection_lint() {
collect_metadata(true);
}

fn collect_metadata(disable_standard_lints: bool) {
use std::time::SystemTime;

// Setup for validation
let start_time = SystemTime::now();

// Running the collection again
run_clippy_for_package("clippy_lints", &["-A", "unfulfilled_lint_expectations"]);
// Run collection as is
std::env::set_var("ENABLE_METADATA_COLLECTION", "1");
let args: &[&str] = if disable_standard_lints {
std::env::set_var("DISABLE_STANDARD_LINTS", "1");
&["-A", "unfulfilled_lint_expectations"]
} else {
&[]
};
run_clippy_for_package("clippy_lints", args);

// Check if cargo caching got in the way
if let Ok(file) = File::open(&*METADATA_OUTPUT_PATH) {
if let Ok(metadata) = file.metadata() {
if let Ok(last_modification) = metadata.modified() {
if last_modification > start_time {
// The output file has been modified. Most likely by a hungry
// metadata collection monster. So We'll return.
return;
}
}
}
}

// Force cargo to invalidate the caches
filetime::set_file_mtime(
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("clippy_lints/src/lib.rs"),
filetime::FileTime::now(),
)
.unwrap();

// Running the collection again
run_clippy_for_package("clippy_lints", args);
}

fn read_metadata() -> Vec<LintMetadata> {
let file = File::open(&*METADATA_OUTPUT_PATH).unwrap();
let reader = BufReader::new(file);
serde_json::from_reader(reader).unwrap()
}
}

fn run_clippy_for_package(project: &str, args: &[&str]) {
Expand Down
7 changes: 7 additions & 0 deletions tests/ui/crashes/ice-8250.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// run-rustfix
fn _f(s: &str) -> Option<()> {
let _ = s[1..].split('.').next()?;
Some(())
}

fn main() {}
1 change: 1 addition & 0 deletions tests/ui/crashes/ice-8250.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// run-rustfix
fn _f(s: &str) -> Option<()> {
let _ = s[1..].splitn(2, '.').next()?;
Some(())
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/crashes/ice-8250.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: unnecessary use of `splitn`
--> $DIR/ice-8250.rs:2:13
--> $DIR/ice-8250.rs:3:13
|
LL | let _ = s[1..].splitn(2, '.').next()?;
| ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s[1..].split('.')`
Expand Down
9 changes: 9 additions & 0 deletions tests/ui/crashes/ice-8821.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// run-rustfix
#![warn(clippy::let_unit_value)]

fn f() {}
static FN: fn() = f;

fn main() {
FN();
}
1 change: 1 addition & 0 deletions tests/ui/crashes/ice-8821.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// run-rustfix
#![warn(clippy::let_unit_value)]

fn f() {}
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/crashes/ice-8821.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: this let-binding has unit value
--> $DIR/ice-8821.rs:7:5
--> $DIR/ice-8821.rs:8:5
|
LL | let _: () = FN();
| ^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `FN();`
Expand Down
Loading

0 comments on commit 3e92ded

Please sign in to comment.