1use syn::{Expr, Item, Local, Pat, Stmt, UseTree};
2
3#[derive(#[automatically_derived]
impl ::core::fmt::Debug for UseGroup {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
UseGroup::Std => "Std",
UseGroup::External => "External",
UseGroup::CrateLocal => "CrateLocal",
})
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for UseGroup {
#[inline]
fn clone(&self) -> UseGroup { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for UseGroup { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for UseGroup {
#[inline]
fn eq(&self, other: &UseGroup) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for UseGroup {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq)]
8pub enum UseGroup {
9 Std,
10 External,
11 CrateLocal,
12}
13
14pub fn classify_use(item: &syn::ItemUse) -> UseGroup {
15 let root_ident = use_tree_root_ident(&item.tree);
16 match root_ident.as_deref() {
17 Some("std" | "alloc" | "core") => UseGroup::Std,
18 Some("crate" | "super" | "self") => UseGroup::CrateLocal,
19 _ => UseGroup::External,
20 }
21}
22
23fn use_tree_root_ident(tree: &UseTree) -> Option<String> {
24 match tree {
25 UseTree::Path(path) => Some(path.ident.to_string()),
26 UseTree::Name(name) => Some(name.ident.to_string()),
27 UseTree::Rename(rename) => Some(rename.ident.to_string()),
28 UseTree::Glob(_) => None,
29 UseTree::Group(group) => group.items.first().and_then(use_tree_root_ident),
30 }
31}
32
33#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ItemKind {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
ItemKind::Use => "Use",
ItemKind::ExternCrate => "ExternCrate",
ItemKind::Const => "Const",
ItemKind::Static => "Static",
ItemKind::TypeAlias => "TypeAlias",
ItemKind::Definition => "Definition",
ItemKind::Other => "Other",
})
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for ItemKind {
#[inline]
fn clone(&self) -> ItemKind { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for ItemKind { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for ItemKind {
#[inline]
fn eq(&self, other: &ItemKind) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ItemKind {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq)]
38enum ItemKind {
39 Use,
40 ExternCrate,
41 Const,
42 Static,
43 TypeAlias,
44 Definition,
45 Other,
46}
47
48fn classify_item_kind(item: &Item) -> ItemKind {
49 match item {
50 Item::Use(_) => ItemKind::Use,
51 Item::ExternCrate(_) => ItemKind::ExternCrate,
52 Item::Const(_) => ItemKind::Const,
53 Item::Static(_) => ItemKind::Static,
54 Item::Type(_) => ItemKind::TypeAlias,
55 Item::Fn(_)
56 | Item::Struct(_)
57 | Item::Enum(_)
58 | Item::Union(_)
59 | Item::Trait(_)
60 | Item::TraitAlias(_)
61 | Item::Impl(_)
62 | Item::Mod(_)
63 | Item::Macro(_) => ItemKind::Definition,
64 _ => ItemKind::Other,
65 }
66}
67
68pub fn should_blank_between_items(prev: &Item, next: &Item) -> bool {
69 let pk = classify_item_kind(prev);
70 let nk = classify_item_kind(next);
71
72 match (pk, nk) {
74 (ItemKind::Use, ItemKind::Use) => {
75 let prev_group = classify_use(match prev {
76 Item::Use(u) => u,
77 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
78 });
79 let next_group = classify_use(match next {
80 Item::Use(u) => u,
81 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
82 });
83 prev_group != next_group
84 }
85 (ItemKind::ExternCrate, ItemKind::ExternCrate) => false,
86 (ItemKind::Const, ItemKind::Const) => false,
87 (ItemKind::Static, ItemKind::Static) => false,
88 (ItemKind::TypeAlias, ItemKind::TypeAlias) => false,
89 _ => true,
90 }
91}
92
93#[derive(#[automatically_derived]
impl ::core::fmt::Debug for StmtWeight {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
StmtWeight::Light => "Light",
StmtWeight::Binding => "Binding",
StmtWeight::Medium => "Medium",
StmtWeight::Heavy => "Heavy",
StmtWeight::Item => "Item",
})
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for StmtWeight {
#[inline]
fn clone(&self) -> StmtWeight { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for StmtWeight { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for StmtWeight {
#[inline]
fn eq(&self, other: &StmtWeight) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for StmtWeight {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq)]
98enum StmtWeight {
99 Light,
100 Binding,
101 Medium,
102 Heavy,
103 Item,
104}
105
106fn expr_is_heavy(expr: &Expr) -> bool {
107 match expr {
108 Expr::If(_)
109 | Expr::Match(_)
110 | Expr::ForLoop(_)
111 | Expr::While(_)
112 | Expr::Loop(_)
113 | Expr::Block(_)
114 | Expr::Unsafe(_)
115 | Expr::TryBlock(_) => true,
116 Expr::Closure(c) => #[allow(non_exhaustive_omitted_patterns)] match *c.body {
Expr::Block(_) => true,
_ => false,
}matches!(*c.body, Expr::Block(_)),
117 Expr::Assign(a) => expr_is_heavy(&a.right),
118 _ => false,
119 }
120}
121
122fn pat_contains_mut(pat: &Pat) -> bool {
123 match pat {
124 Pat::Ident(p) => p.mutability.is_some(),
125 Pat::Reference(p) => p.mutability.is_some() || pat_contains_mut(&p.pat),
126 Pat::Struct(p) => p.fields.iter().any(|f| pat_contains_mut(&f.pat)),
127 Pat::Tuple(p) => p.elems.iter().any(pat_contains_mut),
128 Pat::TupleStruct(p) => p.elems.iter().any(pat_contains_mut),
129 Pat::Slice(p) => p.elems.iter().any(pat_contains_mut),
130 Pat::Or(p) => p.cases.iter().any(pat_contains_mut),
131 Pat::Type(p) => pat_contains_mut(&p.pat),
132 _ => false,
133 }
134}
135
136fn classify_local(local: &Local) -> StmtWeight {
137 if let Some(init) = &local.init {
138 if expr_is_heavy(&init.expr) {
139 return StmtWeight::Heavy;
140 }
141 }
142 if pat_contains_mut(&local.pat) {
143 StmtWeight::Binding
144 } else {
145 StmtWeight::Light
146 }
147}
148
149#[derive(#[automatically_derived]
impl ::core::fmt::Debug for TracingLevel {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
TracingLevel::Trace => "Trace",
TracingLevel::Debug => "Debug",
TracingLevel::Info => "Info",
TracingLevel::Warn => "Warn",
TracingLevel::Error => "Error",
})
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for TracingLevel {
#[inline]
fn clone(&self) -> TracingLevel { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for TracingLevel { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for TracingLevel {
#[inline]
fn eq(&self, other: &TracingLevel) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for TracingLevel {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq)]
154enum TracingLevel {
155 Trace,
156 Debug,
157 Info,
158 Warn,
159 Error,
160}
161
162fn is_tracing_macro(expr: &Expr) -> Option<TracingLevel> {
163 if let Expr::Macro(m) = expr {
164 let name = m.mac.path.segments.last()?.ident.to_string();
165 match name.as_str() {
166 "trace" => Some(TracingLevel::Trace),
167 "debug" => Some(TracingLevel::Debug),
168 "info" => Some(TracingLevel::Info),
169 "warn" => Some(TracingLevel::Warn),
170 "error" => Some(TracingLevel::Error),
171 _ => None,
172 }
173 } else {
174 None
175 }
176}
177
178fn stmt_expr(stmt: &Stmt) -> Option<&Expr> {
179 match stmt {
180 Stmt::Expr(expr, _) => Some(expr),
181 _ => None,
182 }
183}
184
185fn tracing_blank_line(prev: &Stmt, next: &Stmt) -> Option<bool> {
187 if let Some(prev_expr) = stmt_expr(prev) {
189 if let Some(level) = is_tracing_macro(prev_expr) {
190 return Some(match level {
191 TracingLevel::Trace => false,
192 TracingLevel::Debug => true,
193 TracingLevel::Info | TracingLevel::Warn | TracingLevel::Error => true,
194 });
195 }
196 }
197
198 if let Some(next_expr) = stmt_expr(next) {
200 if let Some(level) = is_tracing_macro(next_expr) {
201 return Some(match level {
202 TracingLevel::Trace => true,
203 TracingLevel::Debug => false,
204 TracingLevel::Info | TracingLevel::Warn | TracingLevel::Error => true,
205 });
206 }
207 }
208
209 None
210}
211
212fn classify_weight(stmt: &Stmt) -> StmtWeight {
217 match stmt {
218 Stmt::Local(local) => classify_local(local),
219 Stmt::Expr(expr, _) => {
220 if expr_is_heavy(expr) {
221 StmtWeight::Heavy
222 } else {
223 StmtWeight::Medium
224 }
225 }
226 Stmt::Item(_) => StmtWeight::Item,
227 Stmt::Macro(_) => StmtWeight::Medium,
228 }
229}
230
231fn should_blank_between_stmts(prev: &Stmt, next: &Stmt) -> bool {
232 if let Some(decision) = tracing_blank_line(prev, next) {
234 return decision;
235 }
236
237 let pw = classify_weight(prev);
238 let nw = classify_weight(next);
239
240 if nw == StmtWeight::Item || pw == StmtWeight::Item {
242 return true;
243 }
244
245 if pw == StmtWeight::Heavy || nw == StmtWeight::Heavy {
247 return true;
248 }
249
250 if pw == nw {
252 return false;
253 }
254
255 true
257}
258
259pub fn stmt_blank_lines(stmts: &[Stmt]) -> Vec<bool> {
263 let len = stmts.len();
264 let mut blanks = ::alloc::vec::from_elem(false, len)vec![false; len];
265 if len <= 1 {
266 return blanks;
267 }
268 for i in 1..len {
269 blanks[i] = should_blank_between_stmts(&stmts[i - 1], &stmts[i]);
270 }
271 blanks
272}