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:
- Which item kinds that should have an internal order enforced.
- Individual ordering rules per item kind.
The item kinds that can be linted are:
- Module (with customized groupings, alphabetical within - configurable)
- 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” |
The groups’ names are arbitrary and can be changed to suit the
conventions that should be enforced for a specific project.
All item kinds must be accounted for to create an enforceable linting
rule set. Following are some example configurations that may be useful.
Example: module inclusions and use statements to be at the top
module-item-order-groupings = [
[ "modules", [ "extern_crate", "mod", "foreign_mod" ], ],
[ "use", [ "use", ], ],
[ "everything_else", [ "macro", "global_asm", "static", "const", "ty_alias", "enum", "struct", "union", "trait", "trait_alias", "impl", "fn", ], ],
]
Example: only consts and statics should be alphabetically ordered
It is also possible to configure a selection of module item groups that
should be ordered alphabetically. This may be useful if for example
statics and consts should be ordered, but the rest should be left open.
module-items-ordered-within-groupings = ["UPPER_SNAKE_CASE"]
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.
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
trait TraitUnordered {
const A: bool;
const C: bool;
const B: bool;
type SomeType;
fn a();
fn c();
fn b();
}
Use instead:
trait TraitOrdered {
const A: bool;
const B: bool;
const C: bool;
type SomeType;
fn a();
fn b();
fn c();
}
Configuration
-
module-item-order-groupings
: The named groupings of different source item kinds within modules.
(default: [["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"]]]
)
-
module-items-ordered-within-groupings
: Whether the items within module groups should be ordered alphabetically or not.
This option can be configured to “all”, “none”, or a list of specific grouping names that should be checked
(e.g. only “enums”).
(default: "none"
)
-
source-item-ordering
: Which kind of elements should be ordered internally, possible values being enum
, impl
, module
, struct
, trait
.
(default: ["enum", "impl", "module", "struct", "trait"]
)
-
trait-assoc-item-kinds-order
: The order of associated items in traits.
(default: ["const", "type", "fn"]
)