Skip to content

Commit 5c6fe68

Browse files
committed
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!
2 parents e8b78e2 + f7ab2c9 commit 5c6fe68

32 files changed

+2257
-1
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -5331,6 +5331,7 @@ Released 2018-09-13
53315331
[`almost_complete_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range
53325332
[`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped
53335333
[`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
5334+
[`arbitrary_source_item_ordering`]: https://rust-lang.github.io/rust-clippy/master/index.html#arbitrary_source_item_ordering
53345335
[`arc_with_non_send_sync`]: https://rust-lang.github.io/rust-clippy/master/index.html#arc_with_non_send_sync
53355336
[`arithmetic_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects
53365337
[`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions
@@ -6208,19 +6209,22 @@ Released 2018-09-13
62086209
[`max-trait-bounds`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-trait-bounds
62096210
[`min-ident-chars-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#min-ident-chars-threshold
62106211
[`missing-docs-in-crate-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#missing-docs-in-crate-items
6212+
[`module-item-order-groupings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#module-item-order-groupings
62116213
[`msrv`]: https://doc.rust-lang.org/clippy/lint_configuration.html#msrv
62126214
[`pass-by-value-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pass-by-value-size-limit
62136215
[`pub-underscore-fields-behavior`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pub-underscore-fields-behavior
62146216
[`semicolon-inside-block-ignore-singleline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-inside-block-ignore-singleline
62156217
[`semicolon-outside-block-ignore-multiline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-outside-block-ignore-multiline
62166218
[`single-char-binding-names-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#single-char-binding-names-threshold
6219+
[`source-item-ordering`]: https://doc.rust-lang.org/clippy/lint_configuration.html#source-item-ordering
62176220
[`stack-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#stack-size-threshold
62186221
[`standard-macro-braces`]: https://doc.rust-lang.org/clippy/lint_configuration.html#standard-macro-braces
62196222
[`struct-field-name-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#struct-field-name-threshold
62206223
[`suppress-restriction-lint-in-const`]: https://doc.rust-lang.org/clippy/lint_configuration.html#suppress-restriction-lint-in-const
62216224
[`too-large-for-stack`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-large-for-stack
62226225
[`too-many-arguments-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-many-arguments-threshold
62236226
[`too-many-lines-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-many-lines-threshold
6227+
[`trait-assoc-item-kinds-order`]: https://doc.rust-lang.org/clippy/lint_configuration.html#trait-assoc-item-kinds-order
62246228
[`trivial-copy-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#trivial-copy-size-limit
62256229
[`type-complexity-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#type-complexity-threshold
62266230
[`unnecessary-box-size`]: https://doc.rust-lang.org/clippy/lint_configuration.html#unnecessary-box-size

book/src/lint_configuration.md

+30
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,16 @@ crate. For example, `pub(crate)` items.
666666
* [`missing_docs_in_private_items`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items)
667667

668668

669+
## `module-item-order-groupings`
670+
The named groupings of different source item kinds within modules.
671+
672+
**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"]]]`
673+
674+
---
675+
**Affected lints:**
676+
* [`arbitrary_source_item_ordering`](https://rust-lang.github.io/rust-clippy/master/index.html#arbitrary_source_item_ordering)
677+
678+
669679
## `msrv`
670680
The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml`
671681

@@ -784,6 +794,16 @@ The maximum number of single char bindings a scope may have
784794
* [`many_single_char_names`](https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names)
785795

786796

797+
## `source-item-ordering`
798+
Which kind of elements should be ordered internally, possible values being `enum`, `impl`, `module`, `struct`, `trait`.
799+
800+
**Default Value:** `["enum", "impl", "module", "struct", "trait"]`
801+
802+
---
803+
**Affected lints:**
804+
* [`arbitrary_source_item_ordering`](https://rust-lang.github.io/rust-clippy/master/index.html#arbitrary_source_item_ordering)
805+
806+
787807
## `stack-size-threshold`
788808
The maximum allowed stack size for functions in bytes
789809

@@ -863,6 +883,16 @@ The maximum number of lines a function or method can have
863883
* [`too_many_lines`](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines)
864884

865885

886+
## `trait-assoc-item-kinds-order`
887+
The order of associated items in traits.
888+
889+
**Default Value:** `["const", "type", "fn"]`
890+
891+
---
892+
**Affected lints:**
893+
* [`arbitrary_source_item_ordering`](https://rust-lang.github.io/rust-clippy/master/index.html#arbitrary_source_item_ordering)
894+
895+
866896
## `trivial-copy-size-limit`
867897
The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
868898
reference. By default there is no limit

clippy_config/src/conf.rs

+37-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
use crate::ClippyConfiguration;
22
use crate::msrvs::Msrv;
3-
use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename};
3+
use crate::types::{
4+
DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename, SourceItemOrdering,
5+
SourceItemOrderingCategory, SourceItemOrderingModuleItemGroupings, SourceItemOrderingModuleItemKind,
6+
SourceItemOrderingTraitAssocItemKind, SourceItemOrderingTraitAssocItemKinds,
7+
};
48
use rustc_errors::Applicability;
59
use rustc_session::Session;
610
use rustc_span::edit_distance::edit_distance;
@@ -47,6 +51,29 @@ const DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS: &[&str] = &["i", "j", "x", "y", "z
4751
const DEFAULT_ALLOWED_PREFIXES: &[&str] = &["to", "as", "into", "from", "try_into", "try_from"];
4852
const DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS: &[&str] =
4953
&["core::convert::From", "core::convert::TryFrom", "core::str::FromStr"];
54+
const DEFAULT_MODULE_ITEM_ORDERING_GROUPS: &[(&str, &[SourceItemOrderingModuleItemKind])] = {
55+
#[allow(clippy::enum_glob_use)] // Very local glob use for legibility.
56+
use SourceItemOrderingModuleItemKind::*;
57+
&[
58+
("modules", &[ExternCrate, Mod, ForeignMod]),
59+
("use", &[Use]),
60+
("macros", &[Macro]),
61+
("global_asm", &[GlobalAsm]),
62+
("UPPER_SNAKE_CASE", &[Static, Const]),
63+
("PascalCase", &[TyAlias, Enum, Struct, Union, Trait, TraitAlias, Impl]),
64+
("lower_snake_case", &[Fn]),
65+
]
66+
};
67+
const DEFAULT_TRAIT_ASSOC_ITEM_KINDS_ORDER: &[SourceItemOrderingTraitAssocItemKind] = {
68+
#[allow(clippy::enum_glob_use)] // Very local glob use for legibility.
69+
use SourceItemOrderingTraitAssocItemKind::*;
70+
&[Const, Type, Fn]
71+
};
72+
const DEFAULT_SOURCE_ITEM_ORDERING: &[SourceItemOrderingCategory] = {
73+
#[allow(clippy::enum_glob_use)] // Very local glob use for legibility.
74+
use SourceItemOrderingCategory::*;
75+
&[Enum, Impl, Module, Struct, Trait]
76+
};
5077

5178
/// Conf with parse errors
5279
#[derive(Default)]
@@ -533,6 +560,9 @@ define_Conf! {
533560
/// crate. For example, `pub(crate)` items.
534561
#[lints(missing_docs_in_private_items)]
535562
missing_docs_in_crate_items: bool = false,
563+
/// The named groupings of different source item kinds within modules.
564+
#[lints(arbitrary_source_item_ordering)]
565+
module_item_order_groupings: SourceItemOrderingModuleItemGroupings = DEFAULT_MODULE_ITEM_ORDERING_GROUPS.into(),
536566
/// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml`
537567
#[default_text = "current version"]
538568
#[lints(
@@ -612,6 +642,9 @@ define_Conf! {
612642
/// The maximum number of single char bindings a scope may have
613643
#[lints(many_single_char_names)]
614644
single_char_binding_names_threshold: u64 = 4,
645+
/// Which kind of elements should be ordered internally, possible values being `enum`, `impl`, `module`, `struct`, `trait`.
646+
#[lints(arbitrary_source_item_ordering)]
647+
source_item_ordering: SourceItemOrdering = DEFAULT_SOURCE_ITEM_ORDERING.into(),
615648
/// The maximum allowed stack size for functions in bytes
616649
#[lints(large_stack_frames)]
617650
stack_size_threshold: u64 = 512_000,
@@ -641,6 +674,9 @@ define_Conf! {
641674
/// The maximum number of lines a function or method can have
642675
#[lints(too_many_lines)]
643676
too_many_lines_threshold: u64 = 100,
677+
/// The order of associated items in traits.
678+
#[lints(arbitrary_source_item_ordering)]
679+
trait_assoc_item_kinds_order: SourceItemOrderingTraitAssocItemKinds = DEFAULT_TRAIT_ASSOC_ITEM_KINDS_ORDER.into(),
644680
/// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
645681
/// reference. By default there is no limit
646682
#[default_text = "target_pointer_width * 2"]

0 commit comments

Comments
 (0)