// When we checked enum definitions for sortedness, it was sufficient to compare
// a single identifier (the name of the variant) for each variant. Match
// expressions are different in that each arm may have a pattern that consists
// of more than just one identifier.
//
// Ensure that patterns consisting of a path are correctly tested for
// sortedness. These patterns will be of type Pat::Path, Pat::TupleStruct, or
// Pat::Struct.
//
//
// Resources:
//
// - The syn::Pat syntax tree which forms the left hand side of a match arm:
// https://docs.rs/syn/1.0/syn/enum.Pat.html
use sorted::sorted;
use std::fmt::{self, Display};
use std::io;
#[sorted]
pub enum Error {
Fmt(fmt::Error),
Io(io::Error),
}
impl Display for Error {
#[sorted::check]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
#[sorted]
match self {
Error::Io(e) => write!(f, "{}", e),
Error::Fmt(e) => write!(f, "{}", e),
}
}
}
fn main() {}
好嘛,提示都沒了。
error: Error::Fmt should sort before Error::Io
--> tests/06-pattern-path.rs:33:13
|
33 | Error::Fmt(e) => write!(f, "{}", e),
| ^^^^^^^^^^
可以看到,不論是span
還是ident
都是全路徑的。
因此我們需要把path
的segments
全部進行拼接。
但是之前已經說明,sorted
已經完結了,是因為在上一題已經做了解答
impl syn::visit_mut::VisitMut for MatchVisitor {
fn visit_expr_match_mut(&mut self, i: &mut syn::ExprMatch) {
let mut target_idx: isize = -1;
for (idx, attr) in i.attrs.iter().enumerate() {
if path_to_string(&attr.path) == "sorted" {
target_idx = idx as isize;
break;
}
}
if target_idx != -1 {
i.attrs.remove(target_idx as usize);
let mut match_arm_names: Vec<(String, &dyn quote::ToTokens)> = Vec::new();
for arm in i.arms.iter() {
// 全路徑解析
match &arm.pat {
syn::Pat::Path(p) => {
match_arm_names.push((path_to_string(&p.path), &p.path));
}
syn::Pat::TupleStruct(p) => {
match_arm_names.push((path_to_string(&p.path), &p.path));
}
syn::Pat::Struct(p) => {
match_arm_names.push((path_to_string(&p.path), &p.path));
}
syn::Pat::Ident(p) => {
match_arm_names.push((p.ident.to_string(), &p.ident));
}
syn::Pat::Wild(p) => {
match_arm_names.push(("_".to_string(), &p.underscore_token));
}
_ => {
self.err = std::option::Option::Some(syn::Error::new_spanned(
&arm.pat,
"unsupported by #[sorted]",
));
return;
}
}
}
if let Some(e) = check_order(match_arm_names) {
self.err = std::option::Option::Some(e);
return;
}
}
syn::visit_mut::visit_expr_match_mut(self, i)
}
}
// 全路徑拼接
fn path_to_string(path: &syn::Path) -> String {
path.segments
.iter()
.map(|s| s.ident.to_string())
.collect::<Vec<String>>()
.join("::")
}
不過仔細核對錯誤,我們能更加的深刻的理解
// 因為做了path_to_string,所以這裡提示才會全路徑
error: Error::Fmt should sort before Error::Io
--> tests/06-pattern-path.rs:33:13
| // 因為使用的&p.path,所以span才會剛好
33 | Error::Fmt(e) => write!(f, "{}", e),
| ^^^^^^^^^^
瞎貓碰上死耗子
本作品採用《CC 協議》,轉載必須註明作者和本文連結