diff options
author | Jeremy Banks <_@jeremy.ca> | 2019-05-11 10:52:18 -0400 |
---|---|---|
committer | Jeremy Banks <_@jeremy.ca> | 2019-05-11 11:07:51 -0400 |
commit | c41add741dbe4a97fb04d5236ba91f87ca567b4e (patch) | |
tree | 5bc1079fa5173d1a4ece44f78119cc99f64f1e85 | |
parent | 320efb2ae98e815be196609d7ba600a78cf6727f (diff) | |
download | remain-c41add741dbe4a97fb04d5236ba91f87ca567b4e.tar.gz |
Add support for sorting named struct fields.
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | README.md | 18 | ||||
-rw-r--r-- | src/check.rs | 17 | ||||
-rw-r--r-- | src/emit.rs | 5 | ||||
-rw-r--r-- | src/lib.rs | 6 | ||||
-rw-r--r-- | src/parse.rs | 14 | ||||
-rw-r--r-- | tests/stable.rs | 10 | ||||
-rw-r--r-- | tests/ui/struct.rs | 11 | ||||
-rw-r--r-- | tests/ui/struct.stderr | 5 | ||||
-rw-r--r-- | tests/ui/unsupported.rs | 6 | ||||
-rw-r--r-- | tests/ui/unsupported.stderr | 12 | ||||
-rw-r--r-- | tests/unstable.rs | 9 |
12 files changed, 102 insertions, 13 deletions
@@ -4,7 +4,7 @@ version = "0.1.2" # remember to update number in readme for major versions authors = ["David Tolnay <dtolnay@gmail.com>"] edition = "2018" license = "MIT OR Apache-2.0" -description = "Compile-time checks that an enum or match is written in sorted order." +description = "Compile-time checks that an enum, struct, or match is written in sorted order." repository = "https://github.com/dtolnay/remain" documentation = "https://docs.rs/remain" readme = "README.md" @@ -16,8 +16,8 @@ remain = "0.1" ## Syntax -Place a `#[remain::sorted]` attribute on enums, on match-expressions, or on -let-statements whose value is a match-expression. +Place a `#[remain::sorted]` attribute on enums, on named structs, on +match-expressions, or on let-statements whose value is a match-expression. Alternatively, import as `use remain::sorted;` and use `#[sorted]` as the attribute. @@ -37,6 +37,16 @@ pub enum Error { SpawnVcpu(io::Error), } +#[remain::sorted] +#[derive(Debug)] +pub enum Registers { + ax: u16, + cx: u16, + di: u16, + si: u16, + sp: u16, +} + impl Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use self::Error::*; @@ -57,7 +67,7 @@ impl Display for Error { } ``` -If an enum variant or match arm is inserted out of order, +If an enum variant, struct field, or match arm is inserted out of order, ```diff NetDeviceNew(virtio::NetError), @@ -78,7 +88,7 @@ error: AaaUhOh should sort before BlockSignal ## Compiler support -The attribute on enums is supported on any rustc version 1.31+. +The attribute on enums and structs is supported on any rustc version 1.31+. Rust does not yet have stable support for user-defined attributes within a function body, so the attribute on match-expressions and let-statements requires diff --git a/src/check.rs b/src/check.rs index 281c052..1b50442 100644 --- a/src/check.rs +++ b/src/check.rs @@ -1,5 +1,5 @@ use syn::{Arm, Ident, Result, Variant}; -use syn::{Error, Pat, PatIdent}; +use syn::{Error, Field, Fields, Pat, PatIdent}; use crate::compare::Path; use crate::format; @@ -8,6 +8,13 @@ use crate::parse::Input::{self, *}; pub fn sorted(input: Input) -> Result<()> { let paths = match input { Enum(item) => collect_paths(item.variants)?, + Struct(item) => { + if let Fields::Named(fields) = item.fields { + collect_paths(fields.named)? + } else { + unreachable!("must be named field") + } + } Match(expr) | Let(expr) => collect_paths(expr.arms)?, }; @@ -44,6 +51,14 @@ impl IntoPath for Variant { } } +impl IntoPath for Field { + fn into_path(self) -> Result<Path> { + Ok(Path { + segments: vec![self.ident.expect("must be named field")], + }) + } +} + impl IntoPath for Arm { fn into_path(self) -> Result<Path> { // Sort by just the first pat. diff --git a/src/emit.rs b/src/emit.rs index b98ad1d..d1ddda8 100644 --- a/src/emit.rs +++ b/src/emit.rs @@ -7,6 +7,7 @@ use syn::Error; pub enum Kind { Enum, Match, + Struct, Let, } @@ -21,7 +22,7 @@ pub fn emit(err: Error, kind: Kind, original: TokenStream) -> TokenStream { let original = proc_macro2::TokenStream::from(original); let expanded = match kind { - Kind::Enum | Kind::Let => quote!(#err #original), + Kind::Enum | Kind::Let | Kind::Struct => quote!(#err #original), Kind::Match => quote!({ #err #original }), }; @@ -32,7 +33,7 @@ pub fn emit(err: Error, kind: Kind, original: TokenStream) -> TokenStream { // https://github.com/rust-lang/rust/issues/43081 fn probably_has_spans(kind: Kind) -> bool { match kind { - Kind::Enum => true, + Kind::Enum | Kind::Struct => true, Kind::Match | Kind::Let => false, } } @@ -4,8 +4,8 @@ //! //! # Syntax //! -//! Place a `#[remain::sorted]` attribute on enums, on match-expressions, or on -//! let-statements whose value is a match-expression. +//! Place a `#[remain::sorted]` attribute on enums, on named structs, on +//! match-expressions, or on let-statements whose value is a match-expression. //! //! Alternatively, import as `use remain::sorted;` and use `#[sorted]` as the //! attribute. @@ -76,7 +76,7 @@ //! # fn main() {} //! ``` //! -//! If an enum variant or match arm is inserted out of order, +//! If an enum variant, struct field, or match arm is inserted out of order,\ //! //! ```diff //! NetDeviceNew(virtio::NetError), diff --git a/src/parse.rs b/src/parse.rs index 77fd4bc..98b8c86 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -1,6 +1,6 @@ use proc_macro2::Span; use syn::parse::{Parse, ParseStream}; -use syn::{Attribute, Error, Expr, Result, Stmt, Token, Visibility}; +use syn::{Attribute, Error, Expr, Fields, Result, Stmt, Token, Visibility}; use crate::emit::Kind; @@ -15,6 +15,7 @@ impl Parse for Nothing { pub enum Input { Enum(syn::ItemEnum), Match(syn::ExprMatch), + Struct(syn::ItemStruct), Let(syn::ExprMatch), } @@ -23,6 +24,7 @@ impl Input { match self { Input::Enum(_) => Kind::Enum, Input::Match(_) => Kind::Match, + Input::Struct(_) => Kind::Struct, Input::Let(_) => Kind::Let, } } @@ -61,6 +63,14 @@ impl Parse for Input { if ahead.peek(Token![enum]) { return input.parse().map(Input::Enum); } + if ahead.peek(Token![struct]) { + let input = input.parse().map(Input::Struct)?; + if let Input::Struct(ref item) = input { + if let Fields::Named(_) = item.fields { + return Ok(input); + } + } + } Err(unexpected()) } @@ -68,6 +78,6 @@ impl Parse for Input { fn unexpected() -> Error { let span = Span::call_site(); - let msg = "expected enum or match expression"; + let msg = "expected enum, named struct, or match expression"; Error::new(span, msg) } diff --git a/tests/stable.rs b/tests/stable.rs index 1bf49f4..a3b6a7b 100644 --- a/tests/stable.rs +++ b/tests/stable.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + #[remain::sorted] pub enum TestEnum { A, @@ -6,6 +8,14 @@ pub enum TestEnum { D, } +#[remain::sorted] +pub struct TestStruct { + a: usize, + b: usize, + c: usize, + d: usize, +} + #[test] #[remain::check] fn test_match() { diff --git a/tests/ui/struct.rs b/tests/ui/struct.rs new file mode 100644 index 0000000..5f2cd41 --- /dev/null +++ b/tests/ui/struct.rs @@ -0,0 +1,11 @@ +use remain::sorted; + +#[sorted] +struct TestStruct { + d: usize, + c: usize, + a: usize, + b: usize, +} + +fn main() {} diff --git a/tests/ui/struct.stderr b/tests/ui/struct.stderr new file mode 100644 index 0000000..2ead15b --- /dev/null +++ b/tests/ui/struct.stderr @@ -0,0 +1,5 @@ +error: c should sort before d + --> $DIR/struct.rs:6:5 + | +6 | c: usize, + | ^ diff --git a/tests/ui/unsupported.rs b/tests/ui/unsupported.rs index b11c974..dbda20c 100644 --- a/tests/ui/unsupported.rs +++ b/tests/ui/unsupported.rs @@ -8,3 +8,9 @@ fn main() { _ => {} } } + +#[remain::sorted] +struct TestUnnamedStruct(usize, usize, usize, usize); + +#[remain::sorted] +struct TestUnitStruct; diff --git a/tests/ui/unsupported.stderr b/tests/ui/unsupported.stderr index e471e1e..2e0d70f 100644 --- a/tests/ui/unsupported.stderr +++ b/tests/ui/unsupported.stderr @@ -3,3 +3,15 @@ error: unsupported by #[remain::sorted] | 7 | 0..=20 => {} | ^^^^^^ + +error: expected enum, named struct, or match expression + --> $DIR/unsupported.rs:12:1 + | +12 | #[remain::sorted] + | ^^^^^^^^^^^^^^^^^ + +error: expected enum, named struct, or match expression + --> $DIR/unsupported.rs:15:1 + | +15 | #[remain::sorted] + | ^^^^^^^^^^^^^^^^^ diff --git a/tests/unstable.rs b/tests/unstable.rs index 827c59b..78dbd08 100644 --- a/tests/unstable.rs +++ b/tests/unstable.rs @@ -1,3 +1,4 @@ +#![allow(dead_code)] #![cfg(not(remain_stable_testing))] #![feature(proc_macro_hygiene, stmt_expr_attributes)] @@ -9,6 +10,14 @@ pub enum TestEnum { D, } +#[remain::sorted] +pub struct TestStruct { + a: usize, + b: usize, + c: usize, + d: usize, +} + #[test] fn test_match() { let value = TestEnum::A; |