aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChih-Hung Hsieh <chh@google.com>2020-02-27 10:42:41 -0800
committerChih-Hung Hsieh <chh@google.com>2020-03-05 14:32:21 -0800
commit3095d1536defaeecd3bda0e10483589a2ebc1428 (patch)
treeb234233124fbd257ac9a953c924c18ac97ffd996 /src
parent8ed7a370bef4647c82fe5b22b0696ddc715b706b (diff)
downloadremain-3095d1536defaeecd3bda0e10483589a2ebc1428.tar.gz
* Old remain-0.1.3 uses libsyn-0.15.42 * New remain-0.2.1 uses libsyn-1.0.7 * Fill back missing NOTICE,LICENSE,METADATA,MODULE_LICENSE_* files Bug: 143477201 Bug: 150877376 Test: make Change-Id: Ie33535733e26210ca2ca19ec3fd00f5649faa4db
Diffstat (limited to 'src')
-rw-r--r--src/check.rs83
-rw-r--r--src/compare.rs45
-rw-r--r--src/emit.rs39
-rw-r--r--src/format.rs27
-rw-r--r--src/lib.rs176
-rw-r--r--src/parse.rs80
-rw-r--r--src/visit.rs77
7 files changed, 0 insertions, 527 deletions
diff --git a/src/check.rs b/src/check.rs
deleted file mode 100644
index 0995078..0000000
--- a/src/check.rs
+++ /dev/null
@@ -1,83 +0,0 @@
-use syn::{Arm, Ident, Result, Variant};
-use syn::{Error, Field, Pat, PatIdent};
-
-use crate::compare::Path;
-use crate::format;
-use crate::parse::Input::{self, *};
-
-pub fn sorted(input: Input) -> Result<()> {
- let paths = match input {
- Enum(item) => collect_paths(item.variants)?,
- Struct(fields) => collect_paths(fields.named)?,
- Match(expr) | Let(expr) => collect_paths(expr.arms)?,
- };
-
- for i in 1..paths.len() {
- let cur = &paths[i];
- if *cur < paths[i - 1] {
- let lesser = cur;
- let correct_pos = paths[..i - 1].binary_search(cur).unwrap_err();
- let greater = &paths[correct_pos];
- return Err(format::error(lesser, greater));
- }
- }
-
- Ok(())
-}
-
-fn collect_paths<I>(iter: I) -> Result<Vec<Path>>
-where
- I: IntoIterator,
- I::Item: IntoPath,
-{
- iter.into_iter().map(IntoPath::into_path).collect()
-}
-
-trait IntoPath {
- fn into_path(self) -> Result<Path>;
-}
-
-impl IntoPath for Variant {
- fn into_path(self) -> Result<Path> {
- Ok(Path {
- segments: vec![self.ident],
- })
- }
-}
-
-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.
- let pat = self.pats.into_iter().next().expect("at least one pat");
-
- let segments = match pat {
- Pat::Wild(pat) => vec![Ident::from(pat.underscore_token)],
- Pat::Path(pat) => idents_of_path(pat.path),
- Pat::Struct(pat) => idents_of_path(pat.path),
- Pat::TupleStruct(pat) => idents_of_path(pat.path),
- Pat::Ident(ref pat) if is_just_ident(pat) => vec![pat.ident.clone()],
- other => {
- let msg = "unsupported by #[remain::sorted]";
- return Err(Error::new_spanned(other, msg));
- }
- };
-
- Ok(Path { segments })
- }
-}
-
-fn idents_of_path(path: syn::Path) -> Vec<Ident> {
- path.segments.into_iter().map(|seg| seg.ident).collect()
-}
-
-fn is_just_ident(pat: &PatIdent) -> bool {
- pat.by_ref.is_none() && pat.mutability.is_none() && pat.subpat.is_none()
-}
diff --git a/src/compare.rs b/src/compare.rs
deleted file mode 100644
index 59f997d..0000000
--- a/src/compare.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-use proc_macro2::Ident;
-use std::cmp::Ordering;
-
-#[derive(PartialEq, Eq)]
-pub struct Path {
- pub segments: Vec<Ident>,
-}
-
-impl PartialOrd for Path {
- fn partial_cmp(&self, other: &Path) -> Option<Ordering> {
- Some(self.cmp(other))
- }
-}
-
-impl Ord for Path {
- fn cmp(&self, other: &Path) -> Ordering {
- // Lexicographic ordering across path segments.
- for (lhs, rhs) in self.segments.iter().zip(&other.segments) {
- match cmp(&lhs.to_string(), &rhs.to_string()) {
- Ordering::Equal => {}
- non_eq => return non_eq,
- }
- }
-
- self.segments.len().cmp(&other.segments.len())
- }
-}
-
-// TODO: more intelligent comparison
-// for example to handle numeric cases like E9 < E10.
-fn cmp(lhs: &str, rhs: &str) -> Ordering {
- // Sort `_` last.
- match (lhs == "_", rhs == "_") {
- (true, true) => return Ordering::Equal,
- (true, false) => return Ordering::Greater,
- (false, true) => return Ordering::Less,
- (false, false) => {}
- }
-
- let lhs = lhs.to_ascii_lowercase();
- let rhs = rhs.to_ascii_lowercase();
-
- // For now: asciibetical ordering.
- lhs.cmp(&rhs)
-}
diff --git a/src/emit.rs b/src/emit.rs
deleted file mode 100644
index d1ddda8..0000000
--- a/src/emit.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-use proc_macro::TokenStream;
-use proc_macro2::Span;
-use quote::quote;
-use syn::Error;
-
-#[derive(Copy, Clone)]
-pub enum Kind {
- Enum,
- Match,
- Struct,
- Let,
-}
-
-pub fn emit(err: Error, kind: Kind, original: TokenStream) -> TokenStream {
- let mut err = err;
- if !probably_has_spans(kind) {
- // Otherwise the error is printed without any line number.
- err = Error::new(Span::call_site(), &err.to_string());
- }
-
- let err = err.to_compile_error();
- let original = proc_macro2::TokenStream::from(original);
-
- let expanded = match kind {
- Kind::Enum | Kind::Let | Kind::Struct => quote!(#err #original),
- Kind::Match => quote!({ #err #original }),
- };
-
- TokenStream::from(expanded)
-}
-
-// Rustc is so bad at spans.
-// https://github.com/rust-lang/rust/issues/43081
-fn probably_has_spans(kind: Kind) -> bool {
- match kind {
- Kind::Enum | Kind::Struct => true,
- Kind::Match | Kind::Let => false,
- }
-}
diff --git a/src/format.rs b/src/format.rs
deleted file mode 100644
index 5832643..0000000
--- a/src/format.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-use proc_macro2::TokenStream;
-use quote::TokenStreamExt;
-use std::fmt::{self, Display};
-use syn::Error;
-
-use crate::compare::Path;
-
-impl Display for Path {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- for (i, segment) in self.segments.iter().enumerate() {
- if i > 0 {
- formatter.write_str("::")?;
- }
- segment.fmt(formatter)?;
- }
- Ok(())
- }
-}
-
-pub fn error(lesser: &Path, greater: &Path) -> Error {
- let mut spans = TokenStream::new();
- spans.append_all(&lesser.segments);
-
- let msg = format!("{} should sort before {}", lesser, greater);
-
- Error::new_spanned(spans, msg)
-}
diff --git a/src/lib.rs b/src/lib.rs
deleted file mode 100644
index 967143e..0000000
--- a/src/lib.rs
+++ /dev/null
@@ -1,176 +0,0 @@
-//! This crate provides an attribute macro to check at compile time that the
-//! variants of an enum or the arms of a match expression are written in sorted
-//! order.
-//!
-//! # Syntax
-//!
-//! Place a `#[remain::sorted]` attribute on enums, structs, match-expressions,
-//! or let-statements whose value is a match-expression.
-//!
-//! Alternatively, import as `use remain::sorted;` and use `#[sorted]` as the
-//! attribute.
-//!
-//! ```
-//! # use std::error::Error as StdError;
-//! # use std::fmt::{self, Display};
-//! # use std::io;
-//! #
-//! #[remain::sorted]
-//! #[derive(Debug)]
-//! pub enum Error {
-//! BlockSignal(signal::Error),
-//! CreateCrasClient(libcras::Error),
-//! CreateEventFd(sys_util::Error),
-//! CreateSignalFd(sys_util::SignalFdError),
-//! CreateSocket(io::Error),
-//! DetectImageType(qcow::Error),
-//! DeviceJail(io_jail::Error),
-//! NetDeviceNew(virtio::NetError),
-//! SpawnVcpu(io::Error),
-//! }
-//!
-//! impl Display for Error {
-//! # #[remain::check]
-//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-//! use self::Error::*;
-//!
-//! #[remain::sorted]
-//! match self {
-//! BlockSignal(e) => write!(f, "failed to block signal: {}", e),
-//! CreateCrasClient(e) => write!(f, "failed to create cras client: {}", e),
-//! CreateEventFd(e) => write!(f, "failed to create eventfd: {}", e),
-//! CreateSignalFd(e) => write!(f, "failed to create signalfd: {}", e),
-//! CreateSocket(e) => write!(f, "failed to create socket: {}", e),
-//! DetectImageType(e) => write!(f, "failed to detect disk image type: {}", e),
-//! DeviceJail(e) => write!(f, "failed to jail device: {}", e),
-//! NetDeviceNew(e) => write!(f, "failed to set up virtio networking: {}", e),
-//! SpawnVcpu(e) => write!(f, "failed to spawn VCPU thread: {}", e),
-//! }
-//! }
-//! }
-//! #
-//! # mod signal {
-//! # pub use std::io::Error;
-//! # }
-//! #
-//! # mod libcras {
-//! # pub use std::io::Error;
-//! # }
-//! #
-//! # mod sys_util {
-//! # pub use std::io::{Error, Error as SignalFdError};
-//! # }
-//! #
-//! # mod qcow {
-//! # pub use std::io::Error;
-//! # }
-//! #
-//! # mod io_jail {
-//! # pub use std::io::Error;
-//! # }
-//! #
-//! # mod virtio {
-//! # pub use std::io::Error as NetError;
-//! # }
-//! #
-//! # fn main() {}
-//! ```
-//!
-//! If an enum variant, struct field, or match arm is inserted out of order,\
-//!
-//! ```diff
-//! NetDeviceNew(virtio::NetError),
-//! SpawnVcpu(io::Error),
-//! + AaaUhOh(Box<dyn StdError>),
-//! }
-//! ```
-//!
-//! then the macro produces a compile error.
-//!
-//! ```console
-//! error: AaaUhOh should sort before BlockSignal
-//! --> tests/stable.rs:49:5
-//! |
-//! 49 | AaaUhOh(Box<dyn StdError>),
-//! | ^^^^^^^
-//! ```
-//!
-//! # Compiler support
-//!
-//! The attribute on enums 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 a nightly compiler and the following two features enabled:
-//!
-//! ```
-//! # const IGNORE: &str = stringify! {
-//! #![feature(proc_macro_hygiene, stmt_expr_attributes)]
-//! # };
-//! ```
-//!
-//! As a stable alternative, this crate provides a function-level attribute
-//! called `#[remain::check]` which makes match-expression and let-statement
-//! attributes work on any rustc version 1.31+. Place this attribute on any
-//! function containing `#[sorted]` to make them work on a stable compiler.
-//!
-//! ```
-//! # use std::fmt::{self, Display};
-//! #
-//! # enum Error {}
-//! #
-//! impl Display for Error {
-//! #[remain::check]
-//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-//! use self::Error::*;
-//!
-//! #[sorted]
-//! match self {
-//! /* ... */
-//! # _ => unimplemented!(),
-//! }
-//! }
-//! }
-//! #
-//! # fn main() {}
-//! ```
-
-extern crate proc_macro;
-
-mod check;
-mod compare;
-mod emit;
-mod format;
-mod parse;
-mod visit;
-
-use proc_macro::TokenStream;
-use quote::quote;
-use syn::{parse_macro_input, ItemFn};
-
-use crate::emit::emit;
-use crate::parse::{Input, Nothing};
-
-#[proc_macro_attribute]
-pub fn sorted(args: TokenStream, input: TokenStream) -> TokenStream {
- let original = input.clone();
-
- let _ = parse_macro_input!(args as Nothing);
- let input = parse_macro_input!(input as Input);
- let kind = input.kind();
-
- match check::sorted(input) {
- Ok(()) => original,
- Err(err) => emit(err, kind, original),
- }
-}
-
-#[proc_macro_attribute]
-pub fn check(args: TokenStream, input: TokenStream) -> TokenStream {
- let _ = parse_macro_input!(args as Nothing);
- let mut input = parse_macro_input!(input as ItemFn);
-
- visit::check(&mut input);
-
- TokenStream::from(quote!(#input))
-}
diff --git a/src/parse.rs b/src/parse.rs
deleted file mode 100644
index 97bd9f8..0000000
--- a/src/parse.rs
+++ /dev/null
@@ -1,80 +0,0 @@
-use proc_macro2::Span;
-use syn::parse::{Parse, ParseStream};
-use syn::{Attribute, Error, Expr, Fields, Result, Stmt, Token, Visibility};
-
-use crate::emit::Kind;
-
-pub struct Nothing;
-
-impl Parse for Nothing {
- fn parse(_input: ParseStream) -> Result<Self> {
- Ok(Nothing)
- }
-}
-
-pub enum Input {
- Enum(syn::ItemEnum),
- Match(syn::ExprMatch),
- Struct(syn::FieldsNamed),
- Let(syn::ExprMatch),
-}
-
-impl Input {
- pub fn kind(&self) -> Kind {
- match self {
- Input::Enum(_) => Kind::Enum,
- Input::Match(_) => Kind::Match,
- Input::Struct(_) => Kind::Struct,
- Input::Let(_) => Kind::Let,
- }
- }
-}
-
-impl Parse for Input {
- fn parse(input: ParseStream) -> Result<Self> {
- let _ = input.call(Attribute::parse_outer)?;
-
- if input.peek(Token![match]) {
- let expr = match input.parse()? {
- Expr::Match(expr) => expr,
- _ => unreachable!("expected match"),
- };
- return Ok(Input::Match(expr));
- }
-
- if input.peek(Token![let]) {
- let stmt = match input.parse()? {
- Stmt::Local(stmt) => stmt,
- _ => unreachable!("expected let"),
- };
- let init = match stmt.init {
- Some((_, init)) => *init,
- None => return Err(unexpected()),
- };
- let expr = match init {
- Expr::Match(expr) => expr,
- _ => return Err(unexpected()),
- };
- return Ok(Input::Let(expr));
- }
-
- let ahead = input.fork();
- let _: Visibility = ahead.parse()?;
- if ahead.peek(Token![enum]) {
- return input.parse().map(Input::Enum);
- } else if ahead.peek(Token![struct]) {
- let input: syn::ItemStruct = input.parse()?;
- if let Fields::Named(fields) = input.fields {
- return Ok(Input::Struct(fields));
- }
- }
-
- Err(unexpected())
- }
-}
-
-fn unexpected() -> Error {
- let span = Span::call_site();
- let msg = "expected enum, struct, or match expression";
- Error::new(span, msg)
-}
diff --git a/src/visit.rs b/src/visit.rs
deleted file mode 100644
index f681aa9..0000000
--- a/src/visit.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-use quote::quote;
-use syn::visit_mut::{self, VisitMut};
-use syn::{parse_quote, Attribute, Expr, ExprMatch, ItemFn, Local};
-
-use crate::parse::Input;
-
-pub fn check(input: &mut ItemFn) {
- Checker.visit_item_fn_mut(input);
-}
-
-struct Checker;
-
-impl VisitMut for Checker {
- fn visit_expr_mut(&mut self, expr: &mut Expr) {
- visit_mut::visit_expr_mut(self, expr);
-
- let expr_match = match expr {
- Expr::Match(expr) => expr,
- _ => return,
- };
-
- if !take_sorted_attr(&mut expr_match.attrs) {
- return;
- }
-
- let input = expr_match.clone();
- check_and_insert_error(input, expr);
- }
-
- fn visit_local_mut(&mut self, local: &mut Local) {
- visit_mut::visit_local_mut(self, local);
-
- let init = match &local.init {
- Some((_, init)) => init,
- None => return,
- };
-
- let expr_match = match init.as_ref() {
- Expr::Match(expr) => expr,
- _ => return,
- };
-
- if !take_sorted_attr(&mut local.attrs) {
- return;
- }
-
- let input = expr_match.clone();
- let expr = local.init.as_mut().unwrap().1.as_mut();
- check_and_insert_error(input, expr);
- }
-}
-
-fn take_sorted_attr(attrs: &mut Vec<Attribute>) -> bool {
- for i in 0..attrs.len() {
- let path = &attrs[i].path;
- let path = quote!(#path).to_string();
- if path == "sorted" || path == "remain :: sorted" {
- attrs.remove(i);
- return true;
- }
- }
-
- false
-}
-
-fn check_and_insert_error(input: ExprMatch, out: &mut Expr) {
- let original = quote!(#input);
- let input = Input::Match(input);
-
- if let Err(err) = crate::check::sorted(input) {
- let err = err.to_compile_error();
- *out = parse_quote!({
- #err
- #original
- });
- }
-}