new lint: source_item_ordering

This commit is contained in:
decryphe 2024-08-29 17:58:40 +02:00
parent 15ad8245b2
commit f7ab2c9908
32 changed files with 2257 additions and 1 deletions

View File

@ -5331,6 +5331,7 @@ Released 2018-09-13
[`almost_complete_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range
[`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped
[`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
[`arbitrary_source_item_ordering`]: https://rust-lang.github.io/rust-clippy/master/index.html#arbitrary_source_item_ordering
[`arc_with_non_send_sync`]: https://rust-lang.github.io/rust-clippy/master/index.html#arc_with_non_send_sync
[`arithmetic_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects
[`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions
@ -6208,12 +6209,14 @@ Released 2018-09-13
[`max-trait-bounds`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-trait-bounds
[`min-ident-chars-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#min-ident-chars-threshold
[`missing-docs-in-crate-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#missing-docs-in-crate-items
[`module-item-order-groupings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#module-item-order-groupings
[`msrv`]: https://doc.rust-lang.org/clippy/lint_configuration.html#msrv
[`pass-by-value-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pass-by-value-size-limit
[`pub-underscore-fields-behavior`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pub-underscore-fields-behavior
[`semicolon-inside-block-ignore-singleline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-inside-block-ignore-singleline
[`semicolon-outside-block-ignore-multiline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-outside-block-ignore-multiline
[`single-char-binding-names-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#single-char-binding-names-threshold
[`source-item-ordering`]: https://doc.rust-lang.org/clippy/lint_configuration.html#source-item-ordering
[`stack-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#stack-size-threshold
[`standard-macro-braces`]: https://doc.rust-lang.org/clippy/lint_configuration.html#standard-macro-braces
[`struct-field-name-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#struct-field-name-threshold
@ -6221,6 +6224,7 @@ Released 2018-09-13
[`too-large-for-stack`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-large-for-stack
[`too-many-arguments-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-many-arguments-threshold
[`too-many-lines-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-many-lines-threshold
[`trait-assoc-item-kinds-order`]: https://doc.rust-lang.org/clippy/lint_configuration.html#trait-assoc-item-kinds-order
[`trivial-copy-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#trivial-copy-size-limit
[`type-complexity-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#type-complexity-threshold
[`unnecessary-box-size`]: https://doc.rust-lang.org/clippy/lint_configuration.html#unnecessary-box-size

View File

@ -666,6 +666,16 @@ crate. For example, `pub(crate)` items.
* [`missing_docs_in_private_items`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items)
## `module-item-order-groupings`
The named groupings of different source item kinds within modules.
**Default Value:** `[["modules", ["extern_crate", "mod", "foreign_mod"]], ["use", ["use"]], ["macros", ["macro"]], ["global_asm", ["global_asm"]], ["UPPER_SNAKE_CASE", ["static", "const"]], ["PascalCase", ["ty_alias", "enum", "struct", "union", "trait", "trait_alias", "impl"]], ["lower_snake_case", ["fn"]]]`
---
**Affected lints:**
* [`arbitrary_source_item_ordering`](https://rust-lang.github.io/rust-clippy/master/index.html#arbitrary_source_item_ordering)
## `msrv`
The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml`
@ -784,6 +794,16 @@ The maximum number of single char bindings a scope may have
* [`many_single_char_names`](https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names)
## `source-item-ordering`
Which kind of elements should be ordered internally, possible values being `enum`, `impl`, `module`, `struct`, `trait`.
**Default Value:** `["enum", "impl", "module", "struct", "trait"]`
---
**Affected lints:**
* [`arbitrary_source_item_ordering`](https://rust-lang.github.io/rust-clippy/master/index.html#arbitrary_source_item_ordering)
## `stack-size-threshold`
The maximum allowed stack size for functions in bytes
@ -863,6 +883,16 @@ The maximum number of lines a function or method can have
* [`too_many_lines`](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines)
## `trait-assoc-item-kinds-order`
The order of associated items in traits.
**Default Value:** `["const", "type", "fn"]`
---
**Affected lints:**
* [`arbitrary_source_item_ordering`](https://rust-lang.github.io/rust-clippy/master/index.html#arbitrary_source_item_ordering)
## `trivial-copy-size-limit`
The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
reference. By default there is no limit

View File

@ -1,6 +1,10 @@
use crate::ClippyConfiguration;
use crate::msrvs::Msrv;
use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename};
use crate::types::{
DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename, SourceItemOrdering,
SourceItemOrderingCategory, SourceItemOrderingModuleItemGroupings, SourceItemOrderingModuleItemKind,
SourceItemOrderingTraitAssocItemKind, SourceItemOrderingTraitAssocItemKinds,
};
use rustc_errors::Applicability;
use rustc_session::Session;
use rustc_span::edit_distance::edit_distance;
@ -47,6 +51,29 @@
const DEFAULT_ALLOWED_PREFIXES: &[&str] = &["to", "as", "into", "from", "try_into", "try_from"];
const DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS: &[&str] =
&["core::convert::From", "core::convert::TryFrom", "core::str::FromStr"];
const DEFAULT_MODULE_ITEM_ORDERING_GROUPS: &[(&str, &[SourceItemOrderingModuleItemKind])] = {
#[allow(clippy::enum_glob_use)] // Very local glob use for legibility.
use SourceItemOrderingModuleItemKind::*;
&[
("modules", &[ExternCrate, Mod, ForeignMod]),
("use", &[Use]),
("macros", &[Macro]),
("global_asm", &[GlobalAsm]),
("UPPER_SNAKE_CASE", &[Static, Const]),
("PascalCase", &[TyAlias, Enum, Struct, Union, Trait, TraitAlias, Impl]),
("lower_snake_case", &[Fn]),
]
};
const DEFAULT_TRAIT_ASSOC_ITEM_KINDS_ORDER: &[SourceItemOrderingTraitAssocItemKind] = {
#[allow(clippy::enum_glob_use)] // Very local glob use for legibility.
use SourceItemOrderingTraitAssocItemKind::*;
&[Const, Type, Fn]
};
const DEFAULT_SOURCE_ITEM_ORDERING: &[SourceItemOrderingCategory] = {
#[allow(clippy::enum_glob_use)] // Very local glob use for legibility.
use SourceItemOrderingCategory::*;
&[Enum, Impl, Module, Struct, Trait]
};
/// Conf with parse errors
#[derive(Default)]
@ -533,6 +560,9 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
/// crate. For example, `pub(crate)` items.
#[lints(missing_docs_in_private_items)]
missing_docs_in_crate_items: bool = false,
/// The named groupings of different source item kinds within modules.
#[lints(arbitrary_source_item_ordering)]
module_item_order_groupings: SourceItemOrderingModuleItemGroupings = DEFAULT_MODULE_ITEM_ORDERING_GROUPS.into(),
/// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml`
#[default_text = "current version"]
#[lints(
@ -612,6 +642,9 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
/// The maximum number of single char bindings a scope may have
#[lints(many_single_char_names)]
single_char_binding_names_threshold: u64 = 4,
/// Which kind of elements should be ordered internally, possible values being `enum`, `impl`, `module`, `struct`, `trait`.
#[lints(arbitrary_source_item_ordering)]
source_item_ordering: SourceItemOrdering = DEFAULT_SOURCE_ITEM_ORDERING.into(),
/// The maximum allowed stack size for functions in bytes
#[lints(large_stack_frames)]
stack_size_threshold: u64 = 512_000,
@ -641,6 +674,9 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
/// The maximum number of lines a function or method can have
#[lints(too_many_lines)]
too_many_lines_threshold: u64 = 100,
/// The order of associated items in traits.
#[lints(arbitrary_source_item_ordering)]
trait_assoc_item_kinds_order: SourceItemOrderingTraitAssocItemKinds = DEFAULT_TRAIT_ASSOC_ITEM_KINDS_ORDER.into(),
/// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
/// reference. By default there is no limit
#[default_text = "target_pointer_width * 2"]

View File

@ -1,5 +1,6 @@
use serde::de::{self, Deserializer, Visitor};
use serde::{Deserialize, Serialize, ser};
use std::collections::HashMap;
use std::fmt;
#[derive(Debug, Deserialize)]
@ -102,6 +103,306 @@ fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
}
}
/// Represents the item categories that can be ordered by the source ordering lint.
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum SourceItemOrderingCategory {
Enum,
Impl,
Module,
Struct,
Trait,
}
/// Represents which item categories are enabled for ordering.
///
/// The [`Deserialize`] implementation checks that there are no duplicates in
/// the user configuration.
pub struct SourceItemOrdering(Vec<SourceItemOrderingCategory>);
impl SourceItemOrdering {
pub fn contains(&self, category: &SourceItemOrderingCategory) -> bool {
self.0.contains(category)
}
}
impl<T> From<T> for SourceItemOrdering
where
T: Into<Vec<SourceItemOrderingCategory>>,
{
fn from(value: T) -> Self {
Self(value.into())
}
}
impl core::fmt::Debug for SourceItemOrdering {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl<'de> Deserialize<'de> for SourceItemOrdering {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let items = Vec::<SourceItemOrderingCategory>::deserialize(deserializer)?;
let mut items_set = std::collections::HashSet::new();
for item in &items {
if items_set.contains(item) {
return Err(de::Error::custom(format!(
"The category \"{item:?}\" was enabled more than once in the source ordering configuration."
)));
}
items_set.insert(item);
}
Ok(Self(items))
}
}
impl Serialize for SourceItemOrdering {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
self.0.serialize(serializer)
}
}
/// Represents the items that can occur within a module.
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum SourceItemOrderingModuleItemKind {
ExternCrate,
Mod,
ForeignMod,
Use,
Macro,
GlobalAsm,
Static,
Const,
TyAlias,
Enum,
Struct,
Union,
Trait,
TraitAlias,
Impl,
Fn,
}
impl SourceItemOrderingModuleItemKind {
pub fn all_variants() -> Vec<Self> {
#[allow(clippy::enum_glob_use)] // Very local glob use for legibility.
use SourceItemOrderingModuleItemKind::*;
vec![
ExternCrate,
Mod,
ForeignMod,
Use,
Macro,
GlobalAsm,
Static,
Const,
TyAlias,
Enum,
Struct,
Union,
Trait,
TraitAlias,
Impl,
Fn,
]
}
}
/// Represents the configured ordering of items within a module.
///
/// The [`Deserialize`] implementation checks that no item kinds have been
/// omitted and that there are no duplicates in the user configuration.
#[derive(Clone)]
pub struct SourceItemOrderingModuleItemGroupings {
groups: Vec<(String, Vec<SourceItemOrderingModuleItemKind>)>,
lut: HashMap<SourceItemOrderingModuleItemKind, usize>,
}
impl SourceItemOrderingModuleItemGroupings {
fn build_lut(
groups: &[(String, Vec<SourceItemOrderingModuleItemKind>)],
) -> HashMap<SourceItemOrderingModuleItemKind, usize> {
let mut lut = HashMap::new();
for (group_index, (_, items)) in groups.iter().enumerate() {
for item in items {
lut.insert(item.clone(), group_index);
}
}
lut
}
pub fn module_level_order_of(&self, item: &SourceItemOrderingModuleItemKind) -> Option<usize> {
self.lut.get(item).copied()
}
}
impl From<&[(&str, &[SourceItemOrderingModuleItemKind])]> for SourceItemOrderingModuleItemGroupings {
fn from(value: &[(&str, &[SourceItemOrderingModuleItemKind])]) -> Self {
let groups: Vec<(String, Vec<SourceItemOrderingModuleItemKind>)> =
value.iter().map(|item| (item.0.to_string(), item.1.to_vec())).collect();
let lut = Self::build_lut(&groups);
Self { groups, lut }
}
}
impl core::fmt::Debug for SourceItemOrderingModuleItemGroupings {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.groups.fmt(f)
}
}
impl<'de> Deserialize<'de> for SourceItemOrderingModuleItemGroupings {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let groups = Vec::<(String, Vec<SourceItemOrderingModuleItemKind>)>::deserialize(deserializer)?;
let items_total: usize = groups.iter().map(|(_, v)| v.len()).sum();
let lut = Self::build_lut(&groups);
let mut expected_items = SourceItemOrderingModuleItemKind::all_variants();
for item in lut.keys() {
expected_items.retain(|i| i != item);
}
let all_items = SourceItemOrderingModuleItemKind::all_variants();
if expected_items.is_empty() && items_total == all_items.len() {
let Some(use_group_index) = lut.get(&SourceItemOrderingModuleItemKind::Use) else {
return Err(de::Error::custom("Error in internal LUT."));
};
let Some((_, use_group_items)) = groups.get(*use_group_index) else {
return Err(de::Error::custom("Error in internal LUT."));
};
if use_group_items.len() > 1 {
return Err(de::Error::custom(
"The group containing the \"use\" item kind may not contain any other item kinds. \
The \"use\" items will (generally) be sorted by rustfmt already. \
Therefore it makes no sense to implement linting rules that may conflict with rustfmt.",
));
}
Ok(Self { groups, lut })
} else if items_total != all_items.len() {
Err(de::Error::custom(format!(
"Some module item kinds were configured more than once, or were missing, in the source ordering configuration. \
The module item kinds are: {all_items:?}"
)))
} else {
Err(de::Error::custom(format!(
"Not all module item kinds were part of the configured source ordering rule. \
All item kinds must be provided in the config, otherwise the required source ordering would remain ambiguous. \
The module item kinds are: {all_items:?}"
)))
}
}
}
impl Serialize for SourceItemOrderingModuleItemGroupings {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
self.groups.serialize(serializer)
}
}
/// Represents all kinds of trait associated items.
#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum SourceItemOrderingTraitAssocItemKind {
Const,
Fn,
Type,
}
impl SourceItemOrderingTraitAssocItemKind {
pub fn all_variants() -> Vec<Self> {
#[allow(clippy::enum_glob_use)] // Very local glob use for legibility.
use SourceItemOrderingTraitAssocItemKind::*;
vec![Const, Fn, Type]
}
}
/// Represents the order in which associated trait items should be ordered.
///
/// The reason to wrap a `Vec` in a newtype is to be able to implement
/// [`Deserialize`]. Implementing `Deserialize` allows for implementing checks
/// on configuration completeness at the time of loading the clippy config,
/// letting the user know if there's any issues with the config (e.g. not
/// listing all item kinds that should be sorted).
#[derive(Clone)]
pub struct SourceItemOrderingTraitAssocItemKinds(Vec<SourceItemOrderingTraitAssocItemKind>);
impl SourceItemOrderingTraitAssocItemKinds {
pub fn index_of(&self, item: &SourceItemOrderingTraitAssocItemKind) -> Option<usize> {
self.0.iter().position(|i| i == item)
}
}
impl<T> From<T> for SourceItemOrderingTraitAssocItemKinds
where
T: Into<Vec<SourceItemOrderingTraitAssocItemKind>>,
{
fn from(value: T) -> Self {
Self(value.into())
}
}
impl core::fmt::Debug for SourceItemOrderingTraitAssocItemKinds {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl<'de> Deserialize<'de> for SourceItemOrderingTraitAssocItemKinds {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let items = Vec::<SourceItemOrderingTraitAssocItemKind>::deserialize(deserializer)?;
let mut expected_items = SourceItemOrderingTraitAssocItemKind::all_variants();
for item in &items {
expected_items.retain(|i| i != item);
}
let all_items = SourceItemOrderingTraitAssocItemKind::all_variants();
if expected_items.is_empty() && items.len() == all_items.len() {
Ok(Self(items))
} else if items.len() != all_items.len() {
Err(de::Error::custom(format!(
"Some trait associated item kinds were configured more than once, or were missing, in the source ordering configuration. \
The trait associated item kinds are: {all_items:?}",
)))
} else {
Err(de::Error::custom(format!(
"Not all trait associated item kinds were part of the configured source ordering rule. \
All item kinds must be provided in the config, otherwise the required source ordering would remain ambiguous. \
The trait associated item kinds are: {all_items:?}"
)))
}
}
}
impl Serialize for SourceItemOrderingTraitAssocItemKinds {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
self.0.serialize(serializer)
}
}
// these impls are never actually called but are used by the various config options that default to
// empty lists
macro_rules! unimplemented_serialize {

View File

@ -0,0 +1,531 @@
use clippy_config::Conf;
use clippy_config::types::{
SourceItemOrderingCategory, SourceItemOrderingModuleItemGroupings, SourceItemOrderingModuleItemKind,
SourceItemOrderingTraitAssocItemKind, SourceItemOrderingTraitAssocItemKinds,
};
use clippy_utils::diagnostics::span_lint_and_note;
use rustc_hir::{
AssocItemKind, FieldDef, HirId, ImplItemRef, IsAuto, Item, ItemKind, Mod, QPath, TraitItemRef, TyKind, UseKind,
Variant, VariantData,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::impl_lint_pass;
declare_clippy_lint! {
/// ### What it does
///
/// Confirms that items are sorted in source files as per configuration.
///
/// ### Why restrict this?
///
/// Keeping a consistent ordering throughout the codebase helps with working
/// as a team, and possibly improves maintainability of the codebase. The
/// idea is that by defining a consistent and enforceable rule for how
/// source files are structured, less time will be wasted during reviews on
/// a topic that is (under most circumstances) not relevant to the logic
/// implemented in the code. Sometimes this will be referred to as
/// "bikeshedding".
///
/// ### Default Ordering and Configuration
///
/// As there is no generally applicable rule, and each project may have
/// different requirements, the lint can be configured with high
/// granularity. The configuration is split into two stages:
///
/// 1. Which item kinds that should have an internal order enforced.
/// 2. Individual ordering rules per item kind.
///
/// The item kinds that can be linted are:
/// - Module (with customized groupings, alphabetical within)
/// - Trait (with customized order of associated items, alphabetical within)
/// - Enum, Impl, Struct (purely alphabetical)
///
/// #### Module Item Order
///
/// Due to the large variation of items within modules, the ordering can be
/// configured on a very granular level. Item kinds can be grouped together
/// arbitrarily, items within groups will be ordered alphabetically. The
/// following table shows the default groupings:
///
/// | Group | Item Kinds |
/// |--------------------|----------------------|
/// | `modules` | "mod", "foreign_mod" |
/// | `use` | "use" |
/// | `macros` | "macro" |
/// | `global_asm` | "global_asm" |
/// | `UPPER_SNAKE_CASE` | "static", "const" |
/// | `PascalCase` | "ty_alias", "opaque_ty", "enum", "struct", "union", "trait", "trait_alias", "impl" |
/// | `lower_snake_case` | "fn" |
///
/// All item kinds must be accounted for to create an enforceable linting
/// rule set.
///
/// ### Known Problems
///
/// #### Performance Impact
///
/// Keep in mind, that ordering source code alphabetically can lead to
/// reduced performance in cases where the most commonly used enum variant
/// isn't the first entry anymore, and similar optimizations that can reduce
/// branch misses, cache locality and such. Either don't use this lint if
/// that's relevant, or disable the lint in modules or items specifically
/// where it matters. Other solutions can be to use profile guided
/// optimization (PGO), post-link optimization (e.g. using BOLT for LLVM),
/// or other advanced optimization methods. A good starting point to dig
/// into optimization is [cargo-pgo][cargo-pgo].
///
/// #### Lints on a Contains basis
///
/// The lint can be disabled only on a "contains" basis, but not per element
/// within a "container", e.g. the lint works per-module, per-struct,
/// per-enum, etc. but not for "don't order this particular enum variant".
///
/// #### Module documentation
///
/// Module level rustdoc comments are not part of the resulting syntax tree
/// and as such cannot be linted from within `check_mod`. Instead, the
/// `rustdoc::missing_documentation` lint may be used.
///
/// #### Module Tests
///
/// This lint does not implement detection of module tests (or other feature
/// dependent elements for that matter). To lint the location of mod tests,
/// the lint `items_after_test_module` can be used instead.
///
/// ### Example
///
/// ```no_run
/// trait TraitUnordered {
/// const A: bool;
/// const C: bool;
/// const B: bool;
///
/// type SomeType;
///
/// fn a();
/// fn c();
/// fn b();
/// }
/// ```
///
/// Use instead:
/// ```no_run
/// trait TraitOrdered {
/// const A: bool;
/// const B: bool;
/// const C: bool;
///
/// type SomeType;
///
/// fn a();
/// fn b();
/// fn c();
/// }
/// ```
///
/// [cargo-pgo]: https://github.com/Kobzol/cargo-pgo/blob/main/README.md
///
#[clippy::version = "1.82.0"]
pub ARBITRARY_SOURCE_ITEM_ORDERING,
restriction,
"arbitrary source item ordering"
}
impl_lint_pass!(ArbitrarySourceItemOrdering => [ARBITRARY_SOURCE_ITEM_ORDERING]);
#[derive(Debug)]
#[allow(clippy::struct_excessive_bools)] // Bools are cached feature flags.
pub struct ArbitrarySourceItemOrdering {
assoc_types_order: SourceItemOrderingTraitAssocItemKinds,
enable_ordering_for_enum: bool,
enable_ordering_for_impl: bool,
enable_ordering_for_module: bool,
enable_ordering_for_struct: bool,
enable_ordering_for_trait: bool,
module_item_order_groupings: SourceItemOrderingModuleItemGroupings,
}
impl ArbitrarySourceItemOrdering {
pub fn new(conf: &'static Conf) -> Self {
#[allow(clippy::enum_glob_use)] // Very local glob use for legibility.
use SourceItemOrderingCategory::*;
Self {
assoc_types_order: conf.trait_assoc_item_kinds_order.clone(),
enable_ordering_for_enum: conf.source_item_ordering.contains(&Enum),
enable_ordering_for_impl: conf.source_item_ordering.contains(&Impl),
enable_ordering_for_module: conf.source_item_ordering.contains(&Module),
enable_ordering_for_struct: conf.source_item_ordering.contains(&Struct),
enable_ordering_for_trait: conf.source_item_ordering.contains(&Trait),
module_item_order_groupings: conf.module_item_order_groupings.clone(),
}
}
/// Produces a linting warning for incorrectly ordered impl items.
fn lint_impl_item<T: LintContext>(&self, cx: &T, item: &ImplItemRef, before_item: &ImplItemRef) {
span_lint_and_note(
cx,
ARBITRARY_SOURCE_ITEM_ORDERING,
item.span,
format!(
"incorrect ordering of impl items (defined order: {:?})",
self.assoc_types_order
),
Some(before_item.span),
format!("should be placed before `{}`", before_item.ident.as_str(),),
);
}
/// Produces a linting warning for incorrectly ordered item members.
fn lint_member_name<T: LintContext>(
cx: &T,
ident: &rustc_span::symbol::Ident,
before_ident: &rustc_span::symbol::Ident,
) {
span_lint_and_note(
cx,
ARBITRARY_SOURCE_ITEM_ORDERING,
ident.span,
"incorrect ordering of items (must be alphabetically ordered)",
Some(before_ident.span),
format!("should be placed before `{}`", before_ident.as_str(),),
);
}
fn lint_member_item<T: LintContext>(cx: &T, item: &Item<'_>, before_item: &Item<'_>) {
let span = if item.ident.as_str().is_empty() {
&item.span
} else {
&item.ident.span
};
let (before_span, note) = if before_item.ident.as_str().is_empty() {
(
&before_item.span,
"should be placed before the following item".to_owned(),
)
} else {
(
&before_item.ident.span,
format!("should be placed before `{}`", before_item.ident.as_str(),),
)
};
// This catches false positives where generated code gets linted.
if span == before_span {
return;
}
span_lint_and_note(
cx,
ARBITRARY_SOURCE_ITEM_ORDERING,
*span,
"incorrect ordering of items (must be alphabetically ordered)",
Some(*before_span),
note,
);
}
/// Produces a linting warning for incorrectly ordered trait items.
fn lint_trait_item<T: LintContext>(&self, cx: &T, item: &TraitItemRef, before_item: &TraitItemRef) {
span_lint_and_note(
cx,
ARBITRARY_SOURCE_ITEM_ORDERING,
item.span,
format!(
"incorrect ordering of trait items (defined order: {:?})",
self.assoc_types_order
),
Some(before_item.span),
format!("should be placed before `{}`", before_item.ident.as_str(),),
);
}
}
impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
match &item.kind {
ItemKind::Enum(enum_def, _generics) if self.enable_ordering_for_enum => {
let mut cur_v: Option<&Variant<'_>> = None;
for variant in enum_def.variants {
if in_external_macro(cx.sess(), variant.span) {
continue;
}
if let Some(cur_v) = cur_v {
if cur_v.ident.name.as_str() > variant.ident.name.as_str() && cur_v.span != variant.span {
Self::lint_member_name(cx, &variant.ident, &cur_v.ident);
}
}
cur_v = Some(variant);
}
},
ItemKind::Struct(VariantData::Struct { fields, .. }, _generics) if self.enable_ordering_for_struct => {
let mut cur_f: Option<&FieldDef<'_>> = None;
for field in *fields {
if in_external_macro(cx.sess(), field.span) {
continue;
}
if let Some(cur_f) = cur_f {
if cur_f.ident.name.as_str() > field.ident.name.as_str() && cur_f.span != field.span {
Self::lint_member_name(cx, &field.ident, &cur_f.ident);
}
}
cur_f = Some(field);
}
},
ItemKind::Trait(is_auto, _safety, _generics, _generic_bounds, item_ref)
if self.enable_ordering_for_trait && *is_auto == IsAuto::No =>
{
let mut cur_t: Option<&TraitItemRef> = None;
for item in *item_ref {
if in_external_macro(cx.sess(), item.span) {
continue;
}
if let Some(cur_t) = cur_t {
let cur_t_kind = convert_assoc_item_kind(cur_t.kind);
let cur_t_kind_index = self.assoc_types_order.index_of(&cur_t_kind);
let item_kind = convert_assoc_item_kind(item.kind);
let item_kind_index = self.assoc_types_order.index_of(&item_kind);
if cur_t_kind == item_kind && cur_t.ident.name.as_str() > item.ident.name.as_str() {
Self::lint_member_name(cx, &item.ident, &cur_t.ident);
} else if cur_t_kind_index > item_kind_index {
self.lint_trait_item(cx, item, cur_t);
}
}
cur_t = Some(item);
}
},
ItemKind::Impl(trait_impl) if self.enable_ordering_for_impl => {
let mut cur_t: Option<&ImplItemRef> = None;
for item in trait_impl.items {
if in_external_macro(cx.sess(), item.span) {
continue;
}
if let Some(cur_t) = cur_t {
let cur_t_kind = convert_assoc_item_kind(cur_t.kind);
let cur_t_kind_index = self.assoc_types_order.index_of(&cur_t_kind);
let item_kind = convert_assoc_item_kind(item.kind);
let item_kind_index = self.assoc_types_order.index_of(&item_kind);
if cur_t_kind == item_kind && cur_t.ident.name.as_str() > item.ident.name.as_str() {
Self::lint_member_name(cx, &item.ident, &cur_t.ident);
} else if cur_t_kind_index > item_kind_index {
self.lint_impl_item(cx, item, cur_t);
}
}
cur_t = Some(item);
}
},
_ => {}, // Catch-all for `ItemKinds` that don't have fields.
}
}
fn check_mod(&mut self, cx: &LateContext<'tcx>, module: &'tcx Mod<'tcx>, _: HirId) {
struct CurItem<'a> {
item: &'a Item<'a>,
order: usize,
name: String,
}
let mut cur_t: Option<CurItem<'_>> = None;
if !self.enable_ordering_for_module {
return;
}
let items = module.item_ids.iter().map(|&id| cx.tcx.hir().item(id));
// Iterates over the items within a module.
//
// As of 2023-05-09, the Rust compiler will hold the entries in the same
// order as they appear in the source code, which is convenient for us,
// as no sorting by source map/line of code has to be applied.
//
for item in items {
if in_external_macro(cx.sess(), item.span) {
continue;
}
// The following exceptions (skipping with `continue;`) may not be
// complete, edge cases have not been explored further than what
// appears in the existing code base.
if item.ident.name == rustc_span::symbol::kw::Empty {
if let ItemKind::Impl(_) = item.kind {
// Sorting trait impls for unnamed types makes no sense.
if get_item_name(item).is_empty() {
continue;
}
} else if let ItemKind::ForeignMod { .. } = item.kind {
continue;
} else if let ItemKind::GlobalAsm(_) = item.kind {
continue;
} else if let ItemKind::Use(path, use_kind) = item.kind {
if path.segments.is_empty() {
// Use statements that contain braces get caught here.
// They will still be linted internally.
continue;
} else if path.segments.len() >= 2
&& (path.segments[0].ident.name == rustc_span::sym::std
|| path.segments[0].ident.name == rustc_span::sym::core)
&& path.segments[1].ident.name == rustc_span::sym::prelude
{
// Filters the autogenerated prelude use statement.
// e.g. `use std::prelude::rustc_2021`
} else if use_kind == UseKind::Glob {
// Filters glob kinds of uses.
// e.g. `use std::sync::*`
} else {
// This can be used for debugging.
// println!("Unknown autogenerated use statement: {:?}", item);
}
continue;
}
}
if item.ident.name.as_str().starts_with('_') {
// Filters out unnamed macro-like impls for various derives,
// e.g. serde::Serialize or num_derive::FromPrimitive.
continue;
}
if item.ident.name == rustc_span::sym::std && item.span.is_dummy() {
if let ItemKind::ExternCrate(None) = item.kind {
// Filters the auto-included Rust standard library.
continue;
}
println!("Unknown item: {item:?}");
}
let item_kind = convert_module_item_kind(&item.kind);
let module_level_order = self
.module_item_order_groupings
.module_level_order_of(&item_kind)
.unwrap_or_default();
if let Some(cur_t) = cur_t.as_ref() {
use std::cmp::Ordering; // Better legibility.
match module_level_order.cmp(&cur_t.order) {
Ordering::Less => {
Self::lint_member_item(cx, item, cur_t.item);
},
Ordering::Equal if item_kind == SourceItemOrderingModuleItemKind::Use => {
// Skip ordering use statements, as these should be ordered by rustfmt.
},
Ordering::Equal if cur_t.name > get_item_name(item) => {
Self::lint_member_item(cx, item, cur_t.item);
},
Ordering::Equal | Ordering::Greater => {
// Nothing to do in this case, they're already in the right order.
},
}
}
// Makes a note of the current item for comparison with the next.
cur_t = Some(CurItem {
order: module_level_order,
item,
name: get_item_name(item),
});
}
}
}
/// Converts a [`rustc_hir::AssocItemKind`] to a
/// [`SourceItemOrderingTraitAssocItemKind`].
///
/// This is implemented here because `rustc_hir` is not a dependency of
/// `clippy_config`.
fn convert_assoc_item_kind(value: AssocItemKind) -> SourceItemOrderingTraitAssocItemKind {
#[allow(clippy::enum_glob_use)] // Very local glob use for legibility.
use SourceItemOrderingTraitAssocItemKind::*;
match value {
AssocItemKind::Const { .. } => Const,
AssocItemKind::Type { .. } => Type,
AssocItemKind::Fn { .. } => Fn,
}
}
/// Converts a [`rustc_hir::ItemKind`] to a
/// [`SourceItemOrderingModuleItemKind`].
///
/// This is implemented here because `rustc_hir` is not a dependency of
/// `clippy_config`.
fn convert_module_item_kind(value: &ItemKind<'_>) -> SourceItemOrderingModuleItemKind {
#[allow(clippy::enum_glob_use)] // Very local glob use for legibility.
use SourceItemOrderingModuleItemKind::*;
match value {
ItemKind::ExternCrate(..) => ExternCrate,
ItemKind::Use(..) => Use,
ItemKind::Static(..) => Static,
ItemKind::Const(..) => Const,
ItemKind::Fn(..) => Fn,
ItemKind::Macro(..) => Macro,
ItemKind::Mod(..) => Mod,
ItemKind::ForeignMod { .. } => ForeignMod,
ItemKind::GlobalAsm(..) => GlobalAsm,
ItemKind::TyAlias(..) => TyAlias,
ItemKind::Enum(..) => Enum,
ItemKind::Struct(..) => Struct,
ItemKind::Union(..) => Union,
ItemKind::Trait(..) => Trait,
ItemKind::TraitAlias(..) => TraitAlias,
ItemKind::Impl(..) => Impl,
}
}
/// Gets the item name for sorting purposes, which in the general case is
/// `item.ident.name`.
///
/// For trait impls, the name used for sorting will be the written path of
/// `item.self_ty` plus the written path of `item.of_trait`, joined with
/// exclamation marks. Exclamation marks are used because they are the first
/// printable ASCII character.
///
/// Trait impls generated using a derive-macro will have their path rewritten,
/// such that for example `Default` is `$crate::default::Default`, and
/// `std::clone::Clone` is `$crate::clone::Clone`. This behaviour is described
/// further in the [Rust Reference, Paths Chapter][rust_ref].
///
/// [rust_ref]: https://doc.rust-lang.org/reference/paths.html#crate-1
fn get_item_name(item: &Item<'_>) -> String {
match item.kind {
ItemKind::Impl(im) => {
if let TyKind::Path(path) = im.self_ty.kind {
match path {
QPath::Resolved(_, path) => {
let segs = path.segments.iter();
let mut segs: Vec<String> = segs.map(|s| s.ident.name.as_str().to_owned()).collect();
if let Some(of_trait) = im.of_trait {
let mut trait_segs: Vec<String> = of_trait
.path
.segments
.iter()
.map(|s| s.ident.name.as_str().to_owned())
.collect();
segs.append(&mut trait_segs);
}
segs.push(String::new());
segs.join("!!")
},
QPath::TypeRelative(_, _path_seg) => {
// This case doesn't exist in the clippy tests codebase.
String::new()
},
QPath::LangItem(_, _) => String::new(),
}
} else {
// Impls for anything that isn't a named type can be skipped.
String::new()
}
},
_ => item.ident.name.as_str().to_owned(),
}
}

View File

@ -36,6 +36,7 @@
crate::absolute_paths::ABSOLUTE_PATHS_INFO,
crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO,
crate::approx_const::APPROX_CONSTANT_INFO,
crate::arbitrary_source_item_ordering::ARBITRARY_SOURCE_ITEM_ORDERING_INFO,
crate::arc_with_non_send_sync::ARC_WITH_NON_SEND_SYNC_INFO,
crate::as_conversions::AS_CONVERSIONS_INFO,
crate::asm_syntax::INLINE_ASM_X86_ATT_SYNTAX_INFO,

View File

@ -72,6 +72,7 @@
mod absolute_paths;
mod almost_complete_range;
mod approx_const;
mod arbitrary_source_item_ordering;
mod arc_with_non_send_sync;
mod as_conversions;
mod asm_syntax;
@ -949,5 +950,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
store.register_late_pass(move |_| Box::new(unused_trait_names::UnusedTraitNames::new(conf)));
store.register_late_pass(|_| Box::new(manual_ignore_case_cmp::ManualIgnoreCaseCmp));
store.register_late_pass(|_| Box::new(unnecessary_literal_bound::UnnecessaryLiteralBound));
store.register_late_pass(move |_| Box::new(arbitrary_source_item_ordering::ArbitrarySourceItemOrdering::new(conf)));
// add lints here, do not remove this comment, it's used in `new_lint`
}

View File

@ -0,0 +1 @@
trait-assoc-item-kinds-order = ["fn", "type", "const", "type"]

View File

@ -0,0 +1 @@
trait-assoc-item-kinds-order = ["const", "type"]

View File

@ -0,0 +1 @@
source-item-ordering = ["enum", "impl", "module", "struct", "trait", "struct"]

View File

@ -0,0 +1,12 @@
trait-assoc-item-kinds-order = ["const", "type", "fn"]
source-item-ordering = ["enum", "impl", "module", "struct", "trait"]
module-item-order-groupings = [
["modules", ["extern_crate", "mod", "foreign_mod"]],
["use", ["use"]],
["macros", ["macro"]],
["global_asm", ["global_asm"]],
["UPPER_SNAKE_CASE", ["static", "const"]],
["PascalCase", ["ty_alias", "enum", "struct", "union", "trait", "trait_alias", "impl"]],
["lower_snake_case", ["fn"]]
]

View File

@ -0,0 +1 @@
source-item-ordering = ["enum"]

View File

@ -0,0 +1 @@
source-item-ordering = ["impl"]

View File

@ -0,0 +1 @@
source-item-ordering = ["trait"]

View File

@ -0,0 +1,8 @@
error: error reading Clippy's configuration file: Some trait associated item kinds were configured more than once, or were missing, in the source ordering configuration. The trait associated item kinds are: [Const, Fn, Type]
--> $DIR/tests/ui-toml/arbitrary_source_item_ordering/bad_conf_1/clippy.toml:1:32
|
LL | trait-assoc-item-kinds-order = ["fn", "type", "const", "type"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View File

@ -0,0 +1,8 @@
error: error reading Clippy's configuration file: Some trait associated item kinds were configured more than once, or were missing, in the source ordering configuration. The trait associated item kinds are: [Const, Fn, Type]
--> $DIR/tests/ui-toml/arbitrary_source_item_ordering/bad_conf_2/clippy.toml:1:32
|
LL | trait-assoc-item-kinds-order = ["const", "type"]
| ^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View File

@ -0,0 +1,8 @@
error: error reading Clippy's configuration file: The category "Struct" was enabled more than once in the source ordering configuration.
--> $DIR/tests/ui-toml/arbitrary_source_item_ordering/bad_conf_3/clippy.toml:1:24
|
LL | source-item-ordering = ["enum", "impl", "module", "struct", "trait", "struct"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View File

@ -0,0 +1,186 @@
//@aux-build:../../ui/auxiliary/proc_macros.rs
//@revisions: default default_exp bad_conf_1 bad_conf_2 bad_conf_3
//@[default] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/arbitrary_source_item_ordering/default
//@[default_exp] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/arbitrary_source_item_ordering/default_exp
//@[bad_conf_1] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/arbitrary_source_item_ordering/bad_conf_1
//@[bad_conf_2] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/arbitrary_source_item_ordering/bad_conf_2
//@[bad_conf_3] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/arbitrary_source_item_ordering/bad_conf_3
#![allow(dead_code)]
#![warn(clippy::arbitrary_source_item_ordering)]
/// This module gets linted before clippy gives up.
mod i_am_just_right {
const AFTER: i8 = 0;
const BEFORE: i8 = 0;
}
/// Since the upper module passes linting, the lint now recurses into this module.
mod this_is_in_the_wrong_position {
const A: i8 = 1;
const C: i8 = 0;
}
// Use statements should not be linted internally - this is normally auto-sorted using rustfmt.
use std::rc::{Rc, Weak};
use std::sync::{Arc, Barrier, RwLock};
const SNAKE_CASE: &str = "zzzzzzzz";
const ZIS_SHOULD_BE_EVEN_EARLIER: () = ();
const ZIS_SHOULD_BE_REALLY_EARLY: () = ();
trait BasicEmptyTrait {}
trait CloneSelf {
fn clone_self(&self) -> Self;
}
enum EnumOrdered {
A,
B,
C,
}
enum EnumUnordered {
A,
B,
C,
}
#[allow(clippy::arbitrary_source_item_ordering)]
enum EnumUnorderedAllowed {
A,
B,
C,
}
struct StructOrdered {
a: bool,
b: bool,
c: bool,
}
impl BasicEmptyTrait for StructOrdered {}
impl CloneSelf for StructOrdered {
fn clone_self(&self) -> Self {
Self {
a: true,
b: true,
c: true,
}
}
}
impl Default for StructOrdered {
fn default() -> Self {
Self {
a: true,
b: true,
c: true,
}
}
}
impl std::clone::Clone for StructOrdered {
fn clone(&self) -> Self {
Self {
a: true,
b: true,
c: true,
}
}
}
#[derive(Clone, Default)]
struct StructUnordered {
a: bool,
b: bool,
c: bool,
d: bool,
}
impl TraitUnordered for StructUnordered {
const A: bool = false;
const B: bool = false;
const C: bool = false;
type SomeType = ();
fn a() {}
fn b() {}
fn c() {}
}
impl TraitUnorderedItemKinds for StructUnordered {
const A: bool = false;
const B: bool = false;
const C: bool = false;
type SomeType = ();
fn a() {}
fn b() {}
fn c() {}
}
struct StructUnorderedGeneric<T> {
_1: std::marker::PhantomData<T>,
a: bool,
b: bool,
c: bool,
d: bool,
}
trait TraitOrdered {
const A: bool;
const B: bool;
const C: bool;
type SomeType;
fn a();
fn b();
fn c();
}
trait TraitUnordered {
const A: bool;
const B: bool;
const C: bool;
type SomeType;
fn a();
fn b();
fn c();
}
trait TraitUnorderedItemKinds {
const A: bool;
const B: bool;
const C: bool;
type SomeType;
fn a();
fn b();
fn c();
}
#[derive(std::clone::Clone, Default)]
struct ZisShouldBeBeforeZeMainFn;
fn main() {
// test code goes here
}
#[cfg(test)]
mod test {
const B: i8 = 1;
const A: i8 = 0;
}

View File

@ -0,0 +1,174 @@
//@aux-build:../../ui/auxiliary/proc_macros.rs
//@revisions: var_1
//@[var_1] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/arbitrary_source_item_ordering/var_1
#![allow(dead_code)]
#![warn(clippy::arbitrary_source_item_ordering)]
/// This module gets linted before clippy gives up.
mod i_am_just_right {
const AFTER: i8 = 0;
const BEFORE: i8 = 0;
}
/// Since the upper module passes linting, the lint now recurses into this module.
mod this_is_in_the_wrong_position {
const A: i8 = 1;
const C: i8 = 0;
}
// Use statements should not be linted internally - this is normally auto-sorted using rustfmt.
use std::rc::{Rc, Weak};
use std::sync::{Arc, Barrier, RwLock};
const SNAKE_CASE: &str = "zzzzzzzz";
const ZIS_SHOULD_BE_EVEN_EARLIER: () = ();
const ZIS_SHOULD_BE_REALLY_EARLY: () = ();
trait BasicEmptyTrait {}
trait CloneSelf {
fn clone_self(&self) -> Self;
}
enum EnumOrdered {
A,
B,
C,
}
enum EnumUnordered {
A,
B,
C,
}
#[allow(clippy::arbitrary_source_item_ordering)]
enum EnumUnorderedAllowed {
A,
B,
C,
}
struct StructOrdered {
a: bool,
b: bool,
c: bool,
}
impl BasicEmptyTrait for StructOrdered {}
impl CloneSelf for StructOrdered {
fn clone_self(&self) -> Self {
Self {
a: true,
b: true,
c: true,
}
}
}
impl Default for StructOrdered {
fn default() -> Self {
Self {
a: true,
b: true,
c: true,
}
}
}
impl std::clone::Clone for StructOrdered {
fn clone(&self) -> Self {
Self {
a: true,
b: true,
c: true,
}
}
}
#[derive(Clone, Default)]
struct StructUnordered {
a: bool,
b: bool,
c: bool,
d: bool,
}
impl TraitUnordered for StructUnordered {
fn a() {}
fn b() {}
fn c() {}
type SomeType = ();
const A: bool = false;
const B: bool = false;
const C: bool = false;
}
impl TraitUnorderedItemKinds for StructUnordered {
fn a() {}
type SomeType = ();
const A: bool = false;
}
struct StructUnorderedGeneric<T> {
_1: std::marker::PhantomData<T>,
a: bool,
b: bool,
c: bool,
d: bool,
}
trait TraitOrdered {
fn a();
fn b();
fn c();
type SomeType;
const A: bool;
const B: bool;
const C: bool;
}
trait TraitUnordered {
fn a();
fn b();
fn c();
type SomeType;
const A: bool;
const B: bool;
const C: bool;
}
trait TraitUnorderedItemKinds {
fn a();
type SomeType;
const A: bool;
}
#[derive(std::clone::Clone, Default)]
struct ZisShouldBeBeforeZeMainFn;
fn main() {
// test code goes here
}
#[cfg(test)]
mod test {
const B: i8 = 1;
const A: i8 = 0;
}

View File

@ -0,0 +1,226 @@
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:21:14
|
LL | use std::rc::Weak;
| ^^^^
|
note: should be placed before `SNAKE_CASE`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:19:7
|
LL | const SNAKE_CASE: &str = "zzzzzzzz";
| ^^^^^^^^^^
= note: `-D clippy::arbitrary-source-item-ordering` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::arbitrary_source_item_ordering)]`
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:64:1
|
LL | / impl CloneSelf for StructOrdered {
LL | | fn clone_self(&self) -> Self {
LL | | Self {
LL | | a: true,
... |
LL | | }
LL | | }
| |_^
|
note: should be placed before the following item
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:54:1
|
LL | / impl Default for StructOrdered {
LL | | fn default() -> Self {
LL | | Self {
LL | | a: true,
... |
LL | | }
LL | | }
| |_^
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:136:7
|
LL | const ZIS_SHOULD_BE_REALLY_EARLY: () = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: should be placed before `TraitUnorderedItemKinds`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:124:7
|
LL | trait TraitUnorderedItemKinds {
| ^^^^^^^^^^^^^^^^^^^^^^^
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:151:1
|
LL | impl BasicEmptyTrait for StructOrdered {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: should be placed before the following item
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:138:1
|
LL | / impl TraitUnordered for StructUnordered {
LL | | const A: bool = false;
LL | | const C: bool = false;
LL | | const B: bool = false;
... |
LL | | fn b() {}
LL | | }
| |_^
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:170:5
|
LL | mod this_is_in_the_wrong_position {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: should be placed before `main`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:165:4
|
LL | fn main() {
| ^^^^
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:178:7
|
LL | const ZIS_SHOULD_BE_EVEN_EARLIER: () = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: should be placed before `ZisShouldBeBeforeZeMainFn`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:176:8
|
LL | struct ZisShouldBeBeforeZeMainFn;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:12:11
|
LL | const AFTER: i8 = 0;
| ^^^^^
|
note: should be placed before `BEFORE`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:10:11
|
LL | const BEFORE: i8 = 0;
| ^^^^^^
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:38:5
|
LL | B,
| ^
|
note: should be placed before `C`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:37:5
|
LL | C,
| ^
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:88:5
|
LL | b: bool,
| ^
|
note: should be placed before `c`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:87:5
|
LL | c: bool,
| ^
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:96:5
|
LL | b: bool,
| ^
|
note: should be placed before `c`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:95:5
|
LL | c: bool,
| ^
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:115:11
|
LL | const B: bool;
| ^
|
note: should be placed before `C`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:114:11
|
LL | const C: bool;
| ^
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:121:8
|
LL | fn b();
| ^
|
note: should be placed before `c`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:120:8
|
LL | fn c();
| ^
error: incorrect ordering of trait items (defined order: [Const, Type, Fn])
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:127:5
|
LL | const A: bool;
| ^^^^^^^^^^^^^^
|
note: should be placed before `SomeType`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:125:5
|
LL | type SomeType;
| ^^^^^^^^^^^^^^
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:141:11
|
LL | const B: bool = false;
| ^
|
note: should be placed before `C`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:140:11
|
LL | const C: bool = false;
| ^
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:147:8
|
LL | fn b() {}
| ^
|
note: should be placed before `c`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:146:8
|
LL | fn c() {}
| ^
error: incorrect ordering of impl items (defined order: [Const, Type, Fn])
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:156:5
|
LL | const A: bool = false;
| ^^^^^^^^^^^^^^^^^^^^^^
|
note: should be placed before `SomeType`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:154:5
|
LL | type SomeType = ();
| ^^^^^^^^^^^^^^^^^^^
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:172:11
|
LL | const A: i8 = 1;
| ^
|
note: should be placed before `C`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:11
|
LL | const C: i8 = 0;
| ^
error: aborting due to 17 previous errors

View File

@ -0,0 +1,185 @@
//@aux-build:../../ui/auxiliary/proc_macros.rs
//@revisions: default
//@[default] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/arbitrary_source_item_ordering/default
#![allow(dead_code)]
#![warn(clippy::arbitrary_source_item_ordering)]
/// This module gets linted before clippy gives up.
mod i_am_just_right {
const BEFORE: i8 = 0;
const AFTER: i8 = 0;
}
// Use statements should not be linted internally - this is normally auto-sorted using rustfmt.
use std::rc::Rc;
use std::sync::{Arc, Barrier, RwLock};
const SNAKE_CASE: &str = "zzzzzzzz";
use std::rc::Weak;
trait BasicEmptyTrait {}
trait CloneSelf {
fn clone_self(&self) -> Self;
}
enum EnumOrdered {
A,
B,
C,
}
enum EnumUnordered {
A,
C,
B,
}
#[allow(clippy::arbitrary_source_item_ordering)]
enum EnumUnorderedAllowed {
A,
C,
B,
}
struct StructOrdered {
a: bool,
b: bool,
c: bool,
}
impl Default for StructOrdered {
fn default() -> Self {
Self {
a: true,
b: true,
c: true,
}
}
}
impl CloneSelf for StructOrdered {
fn clone_self(&self) -> Self {
Self {
a: true,
b: true,
c: true,
}
}
}
impl std::clone::Clone for StructOrdered {
fn clone(&self) -> Self {
Self {
a: true,
b: true,
c: true,
}
}
}
#[derive(Default, Clone)]
struct StructUnordered {
a: bool,
c: bool,
b: bool,
d: bool,
}
struct StructUnorderedGeneric<T> {
_1: std::marker::PhantomData<T>,
a: bool,
c: bool,
b: bool,
d: bool,
}
trait TraitOrdered {
const A: bool;
const B: bool;
const C: bool;
type SomeType;
fn a();
fn b();
fn c();
}
trait TraitUnordered {
const A: bool;
const C: bool;
const B: bool;
type SomeType;
fn a();
fn c();
fn b();
}
trait TraitUnorderedItemKinds {
type SomeType;
const A: bool;
const B: bool;
const C: bool;
fn a();
fn b();
fn c();
}
const ZIS_SHOULD_BE_REALLY_EARLY: () = ();
impl TraitUnordered for StructUnordered {
const A: bool = false;
const C: bool = false;
const B: bool = false;
type SomeType = ();
fn a() {}
fn c() {}
fn b() {}
}
// Trait impls should be located just after the type they implement it for.
impl BasicEmptyTrait for StructOrdered {}
impl TraitUnorderedItemKinds for StructUnordered {
type SomeType = ();
const A: bool = false;
const B: bool = false;
const C: bool = false;
fn a() {}
fn b() {}
fn c() {}
}
fn main() {
// test code goes here
}
/// Note that the linting pass is stopped before recursing into this module.
mod this_is_in_the_wrong_position {
const C: i8 = 0;
const A: i8 = 1;
}
#[derive(Default, std::clone::Clone)]
struct ZisShouldBeBeforeZeMainFn;
const ZIS_SHOULD_BE_EVEN_EARLIER: () = ();
#[cfg(test)]
mod test {
const B: i8 = 1;
const A: i8 = 0;
}

View File

@ -0,0 +1,174 @@
//@aux-build:../../ui/auxiliary/proc_macros.rs
//@revisions: var_1
//@[var_1] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/arbitrary_source_item_ordering/var_1
#![allow(dead_code)]
#![warn(clippy::arbitrary_source_item_ordering)]
/// This module gets linted before clippy gives up.
mod i_am_just_right {
const AFTER: i8 = 0;
const BEFORE: i8 = 0;
}
/// Since the upper module passes linting, the lint now recurses into this module.
mod this_is_in_the_wrong_position {
const A: i8 = 1;
const C: i8 = 0;
}
// Use statements should not be linted internally - this is normally auto-sorted using rustfmt.
use std::rc::{Rc, Weak};
use std::sync::{Arc, Barrier, RwLock};
const SNAKE_CASE: &str = "zzzzzzzz";
const ZIS_SHOULD_BE_EVEN_EARLIER: () = ();
const ZIS_SHOULD_BE_REALLY_EARLY: () = ();
trait BasicEmptyTrait {}
trait CloneSelf {
fn clone_self(&self) -> Self;
}
enum EnumOrdered {
A,
B,
C,
}
enum EnumUnordered {
A,
B,
C,
}
#[allow(clippy::arbitrary_source_item_ordering)]
enum EnumUnorderedAllowed {
A,
B,
C,
}
struct StructOrdered {
a: bool,
b: bool,
c: bool,
}
impl BasicEmptyTrait for StructOrdered {}
impl CloneSelf for StructOrdered {
fn clone_self(&self) -> Self {
Self {
a: true,
b: true,
c: true,
}
}
}
impl Default for StructOrdered {
fn default() -> Self {
Self {
a: true,
b: true,
c: true,
}
}
}
impl std::clone::Clone for StructOrdered {
fn clone(&self) -> Self {
Self {
a: true,
b: true,
c: true,
}
}
}
#[derive(Clone, Default)]
struct StructUnordered {
a: bool,
b: bool,
c: bool,
d: bool,
}
impl TraitUnordered for StructUnordered {
fn a() {}
fn c() {}
fn b() {}
type SomeType = ();
const A: bool = false;
const C: bool = false;
const B: bool = false;
}
impl TraitUnorderedItemKinds for StructUnordered {
const A: bool = false;
type SomeType = ();
fn a() {}
}
struct StructUnorderedGeneric<T> {
_1: std::marker::PhantomData<T>,
a: bool,
b: bool,
c: bool,
d: bool,
}
trait TraitOrdered {
fn a();
fn b();
fn c();
type SomeType;
const A: bool;
const B: bool;
const C: bool;
}
trait TraitUnordered {
fn a();
fn c();
fn b();
type SomeType;
const A: bool;
const C: bool;
const B: bool;
}
trait TraitUnorderedItemKinds {
const A: bool;
type SomeType;
fn a();
}
#[derive(std::clone::Clone, Default)]
struct ZisShouldBeBeforeZeMainFn;
fn main() {
// test code goes here
}
#[cfg(test)]
mod test {
const B: i8 = 1;
const A: i8 = 0;
}

View File

@ -0,0 +1,100 @@
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:105:8
|
LL | fn b() {}
| ^
|
note: should be placed before `c`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:104:8
|
LL | fn c() {}
| ^
= note: `-D clippy::arbitrary-source-item-ordering` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::arbitrary_source_item_ordering)]`
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:111:11
|
LL | const B: bool = false;
| ^
|
note: should be placed before `C`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:110:11
|
LL | const C: bool = false;
| ^
error: incorrect ordering of impl items (defined order: [Fn, Type, Const])
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:117:5
|
LL | type SomeType = ();
| ^^^^^^^^^^^^^^^^^^^
|
note: should be placed before `A`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:115:5
|
LL | const A: bool = false;
| ^^^^^^^^^^^^^^^^^^^^^^
error: incorrect ordering of impl items (defined order: [Fn, Type, Const])
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:119:5
|
LL | fn a() {}
| ^^^^^^^^^
|
note: should be placed before `SomeType`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:117:5
|
LL | type SomeType = ();
| ^^^^^^^^^^^^^^^^^^^
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:145:8
|
LL | fn b();
| ^
|
note: should be placed before `c`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:144:8
|
LL | fn c();
| ^
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:151:11
|
LL | const B: bool;
| ^
|
note: should be placed before `C`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:150:11
|
LL | const C: bool;
| ^
error: incorrect ordering of trait items (defined order: [Fn, Type, Const])
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:157:5
|
LL | type SomeType;
| ^^^^^^^^^^^^^^
|
note: should be placed before `A`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:155:5
|
LL | const A: bool;
| ^^^^^^^^^^^^^^
error: incorrect ordering of trait items (defined order: [Fn, Type, Const])
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:159:5
|
LL | fn a();
| ^^^^^^^
|
note: should be placed before `SomeType`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:157:5
|
LL | type SomeType;
| ^^^^^^^^^^^^^^
error: aborting due to 8 previous errors

View File

@ -0,0 +1,16 @@
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_enum.rs:22:5
|
LL | A,
| ^
|
note: should be placed before `B`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_enum.rs:21:5
|
LL | B,
| ^
= note: `-D clippy::arbitrary-source-item-ordering` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::arbitrary_source_item_ordering)]`
error: aborting due to 1 previous error

View File

@ -0,0 +1,43 @@
//@aux-build:../../ui/auxiliary/proc_macros.rs
//@revisions: only_enum
//@[only_enum] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/arbitrary_source_item_ordering/only_enum
#![allow(dead_code)]
#![warn(clippy::arbitrary_source_item_ordering)]
fn main() {}
struct StructUnordered {
b: bool,
a: bool,
}
enum EnumOrdered {
A,
B,
}
enum EnumUnordered {
B,
A,
}
trait TraitUnordered {
const B: bool;
const A: bool;
type SomeType;
fn b();
fn a();
}
trait TraitUnorderedItemKinds {
type SomeType;
const A: bool;
fn a();
}
const ZIS_SHOULD_BE_AT_THE_TOP: () = ();

View File

@ -0,0 +1,40 @@
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_impl.rs:43:8
|
LL | fn a() {}
| ^
|
note: should be placed before `b`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_impl.rs:42:8
|
LL | fn b() {}
| ^
= note: `-D clippy::arbitrary-source-item-ordering` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::arbitrary_source_item_ordering)]`
error: incorrect ordering of impl items (defined order: [Const, Type, Fn])
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_impl.rs:45:5
|
LL | type SomeType = i8;
| ^^^^^^^^^^^^^^^^^^^
|
note: should be placed before `a`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_impl.rs:43:5
|
LL | fn a() {}
| ^^^^^^^^^
error: incorrect ordering of impl items (defined order: [Const, Type, Fn])
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_impl.rs:47:5
|
LL | const A: bool = true;
| ^^^^^^^^^^^^^^^^^^^^^
|
note: should be placed before `SomeType`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_impl.rs:45:5
|
LL | type SomeType = i8;
| ^^^^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors

View File

@ -0,0 +1,67 @@
//@aux-build:../../ui/auxiliary/proc_macros.rs
//@revisions: only_impl
//@[only_impl] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/arbitrary_source_item_ordering/only_impl
#![allow(dead_code)]
#![warn(clippy::arbitrary_source_item_ordering)]
fn main() {}
struct StructUnordered {
b: bool,
a: bool,
}
struct BasicStruct {}
trait BasicTrait {
const A: bool;
type SomeType;
fn b();
fn a();
}
enum EnumUnordered {
B,
A,
}
trait TraitUnordered {
const B: bool;
const A: bool;
type SomeType;
fn b();
fn a();
}
impl BasicTrait for StructUnordered {
fn b() {}
fn a() {}
type SomeType = i8;
const A: bool = true;
}
trait TraitUnorderedItemKinds {
type SomeType;
const A: bool;
fn a();
}
const ZIS_SHOULD_BE_AT_THE_TOP: () = ();
impl BasicTrait for BasicStruct {
const A: bool = true;
type SomeType = i8;
fn a() {}
fn b() {}
}

View File

@ -0,0 +1,40 @@
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.rs:32:11
|
LL | const A: bool;
| ^
|
note: should be placed before `B`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.rs:31:11
|
LL | const B: bool;
| ^
= note: `-D clippy::arbitrary-source-item-ordering` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::arbitrary_source_item_ordering)]`
error: incorrect ordering of items (must be alphabetically ordered)
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.rs:37:8
|
LL | fn a();
| ^
|
note: should be placed before `b`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.rs:36:8
|
LL | fn b();
| ^
error: incorrect ordering of trait items (defined order: [Const, Type, Fn])
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.rs:43:5
|
LL | const A: bool;
| ^^^^^^^^^^^^^^
|
note: should be placed before `SomeType`
--> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.rs:41:5
|
LL | type SomeType;
| ^^^^^^^^^^^^^^
error: aborting due to 3 previous errors

View File

@ -0,0 +1,48 @@
//@aux-build:../../ui/auxiliary/proc_macros.rs
//@revisions: only_trait
//@[only_trait] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/arbitrary_source_item_ordering/only_trait
#![allow(dead_code)]
#![warn(clippy::arbitrary_source_item_ordering)]
fn main() {}
struct StructUnordered {
b: bool,
a: bool,
}
trait TraitOrdered {
const A: bool;
const B: bool;
type SomeType;
fn a();
fn b();
}
enum EnumUnordered {
B,
A,
}
trait TraitUnordered {
const B: bool;
const A: bool;
type SomeType;
fn b();
fn a();
}
trait TraitUnorderedItemKinds {
type SomeType;
const A: bool;
fn a();
}
const ZIS_SHOULD_BE_AT_THE_TOP: () = ();

View File

@ -0,0 +1 @@
trait-assoc-item-kinds-order = ["fn", "type", "const"]

View File

@ -54,12 +54,14 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
max-trait-bounds
min-ident-chars-threshold
missing-docs-in-crate-items
module-item-order-groupings
msrv
pass-by-value-size-limit
pub-underscore-fields-behavior
semicolon-inside-block-ignore-singleline
semicolon-outside-block-ignore-multiline
single-char-binding-names-threshold
source-item-ordering
stack-size-threshold
standard-macro-braces
struct-field-name-threshold
@ -68,6 +70,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
too-large-for-stack
too-many-arguments-threshold
too-many-lines-threshold
trait-assoc-item-kinds-order
trivial-copy-size-limit
type-complexity-threshold
unnecessary-box-size
@ -138,12 +141,14 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
max-trait-bounds
min-ident-chars-threshold
missing-docs-in-crate-items
module-item-order-groupings
msrv
pass-by-value-size-limit
pub-underscore-fields-behavior
semicolon-inside-block-ignore-singleline
semicolon-outside-block-ignore-multiline
single-char-binding-names-threshold
source-item-ordering
stack-size-threshold
standard-macro-braces
struct-field-name-threshold
@ -152,6 +157,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
too-large-for-stack
too-many-arguments-threshold
too-many-lines-threshold
trait-assoc-item-kinds-order
trivial-copy-size-limit
type-complexity-threshold
unnecessary-box-size
@ -222,12 +228,14 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
max-trait-bounds
min-ident-chars-threshold
missing-docs-in-crate-items
module-item-order-groupings
msrv
pass-by-value-size-limit
pub-underscore-fields-behavior
semicolon-inside-block-ignore-singleline
semicolon-outside-block-ignore-multiline
single-char-binding-names-threshold
source-item-ordering
stack-size-threshold
standard-macro-braces
struct-field-name-threshold
@ -236,6 +244,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
too-large-for-stack
too-many-arguments-threshold
too-many-lines-threshold
trait-assoc-item-kinds-order
trivial-copy-size-limit
type-complexity-threshold
unnecessary-box-size