Skip to content
Draft
  •  
  •  
  •  
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::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 @@ -522,7 +522,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::{self as ast, HasAttrs, *};
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 rustc_abi::VariantIdx;
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
5 changes: 2 additions & 3 deletions src/driver.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
#![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)]
// and on rustc internal lints
#![warn(rust_2018_idioms, unused_lifetimes, 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
129 changes: 129 additions & 0 deletions tests/lint-attributes-organization.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
//! 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;
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.to_str().unwrap());
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()
.map(|l| l.split_once("//").map_or(l, |(b, _)| b).trim())
.flat_map(|l| l.split_whitespace().map(|s| s.strip_suffix(',').unwrap_or(s)))
.collect::<Vec<_>>();
for (&a, &b) in lint_names.iter().zip(lint_names.iter().skip(1)) {
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 (error, expected) in errors.into_iter().zip(expected) {
assert_eq!(&error, expected);
}
}
6 changes: 3 additions & 3 deletions tests/ui-toml/disallowed_profiles_methods/main.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#![warn(clippy::disallowed_methods)]
#![allow(
unused,
clippy::no_effect,
clippy::needless_borrow,
clippy::vec_init_then_push,
clippy::unnecessary_literal_unwrap
clippy::no_effect,
clippy::unnecessary_literal_unwrap,
clippy::vec_init_then_push
)]

fn default_violation() {
Expand Down
22 changes: 2 additions & 20 deletions tests/ui/methods.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,7 @@
//@aux-build:option_helpers.rs

#![allow(
clippy::disallowed_names,
clippy::default_trait_access,
clippy::let_underscore_untyped,
clippy::missing_docs_in_private_items,
clippy::missing_safety_doc,
clippy::non_ascii_literal,
clippy::new_without_default,
clippy::needless_pass_by_value,
clippy::needless_lifetimes,
clippy::elidable_lifetime_names,
clippy::print_stdout,
clippy::must_use_candidate,
clippy::use_self,
clippy::useless_format,
clippy::wrong_self_convention,
clippy::unused_async,
clippy::unused_self,
clippy::useless_vec
)]
#![warn(clippy::filter_next, clippy::new_ret_no_self)]
#![expect(clippy::disallowed_names, clippy::useless_vec)]

#[macro_use]
extern crate option_helpers;
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/methods.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: methods called `new` usually return `Self`
--> tests/ui/methods.rs:102:5
--> tests/ui/methods.rs:84:5
|
LL | / fn new() -> i32 {
LL | |
Expand All @@ -11,7 +11,7 @@ LL | | }
= help: to override `-D warnings` add `#[allow(clippy::new_ret_no_self)]`

error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead
--> tests/ui/methods.rs:124:13
--> tests/ui/methods.rs:106:13
|
LL | let _ = v.iter().filter(|&x| {
| _____________^
Expand All @@ -25,7 +25,7 @@ LL | | ).next();
= help: to override `-D warnings` add `#[allow(clippy::filter_next)]`

error: called `filter(..).next_back()` on an `DoubleEndedIterator`. This is more succinctly expressed by calling `.rfind(..)` instead
--> tests/ui/methods.rs:143:13
--> tests/ui/methods.rs:125:13
|
LL | let _ = v.iter().filter(|&x| {
| _____________^
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/methods_fixable.fixed
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![warn(clippy::filter_next)]
#![allow(clippy::useless_vec)]
#![expect(clippy::useless_vec)]

/// Checks implementation of `FILTER_NEXT` lint.
fn main() {
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/methods_fixable.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![warn(clippy::filter_next)]
#![allow(clippy::useless_vec)]
#![expect(clippy::useless_vec)]

/// Checks implementation of `FILTER_NEXT` lint.
fn main() {
Expand Down
Loading