Auto merge of #13376 - decryphe:source-ordering, r=llogiq

new lint: `source_item_ordering`

changelog: [`source_item_ordering`]: Introduced a new restriction lint that checks the ordering of items in Modules, Enums, Structs, Impls and Traits.

From the written documentation:

> 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 "bike-shedding".
>
> 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), or other advanced optimization methods.

I tried to build it as configurable as possible, as such a highly opinionated lint should be adjustable to personal opinions.

I'm open to any input and will be available both here and on the zulip for communication. In the meantime I'll be testing this lint against my own code-bases, which I've (manually) kept ordered with the default config, to see how well it works in practice.

And lastly, a big thanks to the community for making clippy the best linter there is!
This commit is contained in:
bors 2024-11-02 11:03:30 +00:00
commit 5c6fe68c00
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