Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions clippy_config/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#![feature(rustc_private)]
#![warn(
rust_2018_idioms,
trivial_casts,
trivial_numeric_casts,
rust_2018_idioms,
unused_lifetimes,
unused_qualifications
)]
#![allow(clippy::must_use_candidate, clippy::missing_panics_doc)]
#![expect(clippy::must_use_candidate)]

extern crate rustc_data_structures;
extern crate rustc_errors;
Expand Down
4 changes: 2 additions & 2 deletions clippy_dev/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
rustc_private
)]
#![warn(
rust_2018_idioms,
trivial_casts,
trivial_numeric_casts,
rust_2018_idioms,
unused_lifetimes,
unused_qualifications
)]
#![allow(clippy::case_sensitive_file_extension_comparisons, clippy::missing_panics_doc)]
#![expect(clippy::missing_panics_doc)]

extern crate rustc_arena;
extern crate rustc_data_structures;
Expand Down
2 changes: 0 additions & 2 deletions clippy_lints/src/doc/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![allow(clippy::lint_without_lint_pass)]

use clippy_config::Conf;
use clippy_utils::attrs::is_doc_hidden;
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_then};
Expand Down
8 changes: 2 additions & 6 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,11 @@
#![feature(stmt_expr_attributes)]
#![feature(unwrap_infallible)]
#![recursion_limit = "512"]
#![allow(
clippy::missing_docs_in_private_items,
clippy::must_use_candidate,
clippy::literal_string_with_formatting_args
)]
#![expect(clippy::literal_string_with_formatting_args, clippy::must_use_candidate)]
#![warn(
rust_2018_idioms,
trivial_casts,
trivial_numeric_casts,
rust_2018_idioms,
unused_lifetimes,
unused_qualifications,
rustc::internal
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/operators/const_comparisons.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![allow(clippy::match_same_arms)]
#![expect(clippy::match_same_arms)]

use std::cmp::Ordering;

Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/suspicious_operation_groupings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ fn ident_difference_expr_with_base_location(
// then we should be able to change this function to do the correct traversal,
// without needing to change the rest of the code.

#![allow(clippy::enum_glob_use)]
#[allow(clippy::enum_glob_use)]
use ExprKind::*;

match (
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/unnested_or_patterns.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
#![allow(clippy::enum_glob_use, clippy::wildcard_imports)]

use clippy_config::Conf;
use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_maybe_qself, eq_pat, eq_path};
Expand Down
9 changes: 3 additions & 6 deletions clippy_lints_internal/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
#![feature(rustc_private)]
#![allow(
clippy::missing_docs_in_private_items,
clippy::must_use_candidate,
#![expect(
clippy::missing_clippy_version_attribute, // None of these lints need a version.
clippy::symbol_as_str
)]
#![warn(
rust_2018_idioms,
trivial_casts,
trivial_numeric_casts,
rust_2018_idioms,
unused_lifetimes,
unused_qualifications,
rustc::internal
)]
// Disable this rustc lint for now, as it was also done in rustc
#![allow(rustc::potential_query_instability)]
// None of these lints need a version.
#![allow(clippy::missing_clippy_version_attribute)]

extern crate rustc_ast;
extern crate rustc_attr_parsing;
Expand Down
2 changes: 1 addition & 1 deletion clippy_utils/src/ast_utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//!
//! - The `eq_foobar` functions test for semantic equality but ignores `NodeId`s and `Span`s.

#![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
#![allow(clippy::enum_glob_use, clippy::wildcard_imports)]

use crate::{both, over};
use rustc_ast::attr::data_structures::CfgEntry;
Expand Down
4 changes: 2 additions & 2 deletions clippy_utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
#![feature(rustc_private)]
#![feature(unwrap_infallible)]
#![recursion_limit = "512"]
#![allow(clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::must_use_candidate)]
#![expect(clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::must_use_candidate)]
#![warn(
rust_2018_idioms,
trivial_casts,
trivial_numeric_casts,
rust_2018_idioms,
unused_lifetimes,
unused_qualifications,
rustc::internal
Expand Down
2 changes: 1 addition & 1 deletion clippy_utils/src/macros.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![allow(clippy::similar_names)] // `expr` and `expn`
#![expect(clippy::similar_names)] // `expr` and `expn`

use std::cell::Cell;
use std::sync::{Arc, OnceLock};
Expand Down
2 changes: 1 addition & 1 deletion clippy_utils/src/source.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Utils for extracting, inspecting or transforming source code

#![allow(clippy::module_name_repetitions)]
#![expect(clippy::module_name_repetitions)]

use std::sync::Arc;

Expand Down
2 changes: 1 addition & 1 deletion clippy_utils/src/sym.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![allow(non_upper_case_globals)]
#![expect(non_upper_case_globals)]

use rustc_span::symbol::PREDEFINED_SYMBOLS_COUNT;

Expand Down
2 changes: 1 addition & 1 deletion clippy_utils/src/ty/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Util methods for [`rustc_middle::ty`]

#![allow(clippy::module_name_repetitions)]
#![expect(clippy::module_name_repetitions)]

use core::ops::ControlFlow;
use itertools::Itertools as _;
Expand Down
10 changes: 4 additions & 6 deletions lintcheck/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,15 @@

#![feature(iter_collect_into)]
#![warn(
rust_2018_idioms,
trivial_casts,
trivial_numeric_casts,
rust_2018_idioms,
unused_lifetimes,
unused_qualifications
)]
#![allow(
clippy::collapsible_else_if,
clippy::needless_borrows_for_generic_args,
clippy::module_name_repetitions,
clippy::literal_string_with_formatting_args
#![expect(
clippy::literal_string_with_formatting_args,
clippy::needless_borrows_for_generic_args
)]

mod config;
Expand Down
9 changes: 5 additions & 4 deletions src/driver.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#![feature(rustc_private)]
// warn on lints, that are included in `rust-lang/rust`s bootstrap
#![warn(rust_2018_idioms, unused_lifetimes)]
// warn on rustc internal lints
#![warn(rustc::internal)]
#![warn(
// warn on lints, that are included in `rust-lang/rust`s bootstrap
rust_2018_idioms, unused_lifetimes,
// and on rustc internal lints
rustc::internal)]

// FIXME: switch to something more ergonomic here, once available.
// (Currently there is no way to opt into sysroot crates without `extern crate`.)
Expand Down
130 changes: 130 additions & 0 deletions tests/lint-attributes-organization.rs
Comment thread
ada4a marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
//! This test checks that Clippy files (source and tests):
//!
//! - only have one top-level lint attribute of each kind (`allow`/`deny`/`expect`/`forbid`/`warn`)
//! - put unqualified lint names before the qualified ones
//! - use alphabetical order inside each qualification
//!
//! This test is disabled when ran as part of the compiler test suite, to prevent
//! changes from being difficult to make there. Incorrect organizations will be
//! fixed during the merge process.
//!
//! This test may eventually be replaced by a restriction lint which imposes
//! constraints on attributes. Right now, this regex-based one does the job
//! on Clippy test files. It only checks top-level beginning-of-the-line attributes,
//! so that it won't trigger on a `#![cfg_attr(…, warn(…))]` which can legitimately be
//! used in addition to another `#![warn(…)]` attribute.

use regex::Regex;
use std::collections::HashSet;
use std::{fs, iter};
use test_utils::IS_RUSTC_TEST_SUITE;
use walkdir::{DirEntry, WalkDir};

mod test_utils;

const SKIPPED_FILES: [&str; 7] = [
"./tests/lint-attributes-organization.rs", // this file, for the sanity checks
"./tests/ui/blanket_clippy_restriction_lints.rs", // separate lines are better
"./tests/ui/deprecated.rs", // generated
"./tests/ui/duplicated_attributes.rs", // obviously
"./tests/ui/rename.rs", // generated
"./tests/ui/unknown_clippy_lints.rs", // separate lines are better
"./target/", // generated files
];

#[test]
fn lint_attribute_organization() {
if IS_RUSTC_TEST_SUITE {
return;
}
let attribute_regex = attribute_regex();
let mut problem_found = false;
for path in WalkDir::new(".")
.into_iter()
.flatten()
.map(DirEntry::into_path)
.filter(|p| {
p.extension().is_some_and(|ext| ext == "rs") && !SKIPPED_FILES.iter().any(|&skipped| p.starts_with(skipped))
})
{
for diag in error_for_content(&fs::read_to_string(&path).unwrap(), &attribute_regex) {
eprintln!("ERROR: {}: {diag}", path.display());
problem_found = true;
}
}
assert!(
!problem_found,
"some lint attributes do not meet the attributes organization requirements"
);
}

fn attribute_regex() -> Regex {
Regex::new(r"(?ms)^#!\[(allow|deny|expect|forbid|warn)\((.+?)\)\]").unwrap()
}

// Check if file content contains only ordered lint names in top-level inner attributes, and
// also that every attribute is present only once.
fn error_for_content(content: &str, attribute_regex: &Regex) -> Vec<String> {
let mut diags = vec![];
let mut attributes = HashSet::new();
for cap in attribute_regex.captures_iter(content) {
let attribute = &cap[1];
if !attributes.insert(attribute.to_owned()) {
diags.push(format!("duplicate top-level `#![{attribute}]` attribute"));
}
let lint_names = cap[2]
.lines()
// Split off any trailing comments
.map(|l| l.split_once("//").map_or(l, |(b, _)| b).trim())
Comment thread
samueltardieu marked this conversation as resolved.
.flat_map(|l| l.split_whitespace().map(|s| s.strip_suffix(',').unwrap_or(s)))
.collect::<Vec<_>>();
for [a, b] in lint_names.array_windows() {
if a.contains("::") && !b.contains("::") {
diags.push(format!(
"qualified lint names (`{a}`) must come after unqualified ones (`{b}`)"
));
} else if !a.contains("::") && b.contains("::") {
} else if a > b {
diags.push(format!("lint names must be ordered: `{b}` must come before `{a}`"));
}
}
}
diags
}

#[test]
fn internal_sanity_check() {
let attribute_regex = attribute_regex();
check_errors(
"
#![allow(
clippy::def, // Comment
clippy::abc
)]
#![allow(clippy::zyx, unknown)]",
vec![
"lint names must be ordered: `clippy::abc` must come before `clippy::def`",
"duplicate top-level `#![allow]` attribute",
"qualified lint names (`clippy::zyx`) must come after unqualified ones (`unknown`)",
],
&attribute_regex,
);
check_errors(
"#![warn(before, after)]",
vec!["lint names must be ordered: `after` must come before `before`"],
&attribute_regex,
);
check_errors(
"#![deny(clippy::abc, clippy::def, clippy::zyx)]",
vec![],
&attribute_regex,
);
}

fn check_errors(content: &str, expected: Vec<&str>, attribute_regex: &Regex) {
let errors = error_for_content(content, attribute_regex);
assert_eq!(errors.len(), expected.len());
for (i, (error, expected)) in iter::zip(errors, expected).enumerate() {
assert_eq!(&error, expected, "the {}-th error differs from the expectation", i + 1);
}
}
4 changes: 2 additions & 2 deletions tests/ui/assert_is_empty.fixed
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![warn(clippy::assert_is_empty)]
#![allow(clippy::useless_vec)]
#![allow(clippy::const_is_empty, clippy::needless_ifs)]
#![expect(clippy::needless_ifs, clippy::useless_vec)]
#![allow(clippy::const_is_empty)]

fn main() {
let vec = vec![1, 2, 3];
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/assert_is_empty.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![warn(clippy::assert_is_empty)]
#![allow(clippy::useless_vec)]
#![allow(clippy::const_is_empty, clippy::needless_ifs)]
#![expect(clippy::needless_ifs, clippy::useless_vec)]
#![allow(clippy::const_is_empty)]

fn main() {
let vec = vec![1, 2, 3];
Expand Down
1 change: 0 additions & 1 deletion tests/ui/block_scrutinee.1.fixed
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//@ edition: 2021
#![warn(clippy::block_scrutinee)]
#![allow(clippy::blocks_in_conditions)]
#![allow(clippy::let_and_return)]

fn my_function() -> Option<i32> {
Some(1)
Expand Down
1 change: 0 additions & 1 deletion tests/ui/block_scrutinee.2.fixed
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//@ edition: 2021
#![warn(clippy::block_scrutinee)]
#![allow(clippy::blocks_in_conditions)]
#![allow(clippy::let_and_return)]

fn my_function() -> Option<i32> {
Some(1)
Expand Down
1 change: 0 additions & 1 deletion tests/ui/block_scrutinee.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//@ edition: 2021
#![warn(clippy::block_scrutinee)]
#![allow(clippy::blocks_in_conditions)]
#![allow(clippy::let_and_return)]

fn my_function() -> Option<i32> {
Some(1)
Expand Down
8 changes: 4 additions & 4 deletions tests/ui/block_scrutinee.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: this scrutinee is wrapped in a block
--> tests/ui/block_scrutinee.rs:11:22
--> tests/ui/block_scrutinee.rs:10:22
|
LL | if let Some(x) = { my_function() } {
| ^^^^^^^^^^^^^^^^^
Expand All @@ -20,7 +20,7 @@ LL ~ if let Some(x) = res {
|

error: this scrutinee is wrapped in a block
--> tests/ui/block_scrutinee.rs:16:11
--> tests/ui/block_scrutinee.rs:15:11
|
LL | match { my_function() } {
| ^^^^^^^^^^^^^^^^^
Expand All @@ -39,7 +39,7 @@ LL ~ match res {
|

error: this scrutinee is wrapped in a block
--> tests/ui/block_scrutinee.rs:24:25
--> tests/ui/block_scrutinee.rs:23:25
|
LL | while let Some(x) = { v.pop() } {
| ^^^^^^^^^^^
Expand All @@ -58,7 +58,7 @@ LL ~ while let Some(x) = res {
|

error: this scrutinee is wrapped in a block
--> tests/ui/block_scrutinee.rs:41:22
--> tests/ui/block_scrutinee.rs:40:22
|
LL | if let Some(x) = {
| ______________________^
Expand Down
Loading