1use syn::{Expr, Item, Local, Pat, Stmt, StmtMacro, UseTree, Visibility};
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::Mod => "Mod",
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 Mod,
42 Const,
43 Static,
44 TypeAlias,
45 Definition,
46 Other,
47}
48
49fn static_init_is_heavy(expr: &Expr) -> bool {
54 match expr {
55 Expr::Closure(_) | Expr::Block(_) | Expr::Async(_) | Expr::Unsafe(_) => true,
56 Expr::Call(c) => c.args.iter().any(static_init_is_heavy),
57 Expr::MethodCall(mc) => {
58 static_init_is_heavy(&mc.receiver) || mc.args.iter().any(static_init_is_heavy)
59 }
60 _ => false,
61 }
62}
63
64fn classify_item_kind(item: &Item) -> ItemKind {
65 match item {
66 Item::Use(_) => ItemKind::Use,
67 Item::ExternCrate(_) => ItemKind::ExternCrate,
68 Item::Mod(_) => ItemKind::Mod,
69 Item::Const(_) => ItemKind::Const,
70 Item::Static(s) => {
71 if static_init_is_heavy(&s.expr) {
72 ItemKind::Definition
73 } else {
74 ItemKind::Static
75 }
76 }
77 Item::Type(_) => ItemKind::TypeAlias,
78 Item::Fn(_)
79 | Item::Struct(_)
80 | Item::Enum(_)
81 | Item::Union(_)
82 | Item::Trait(_)
83 | Item::TraitAlias(_)
84 | Item::Impl(_)
85 | Item::Macro(_) => ItemKind::Definition,
86 _ => ItemKind::Other,
87 }
88}
89
90pub fn should_blank_between_items(prev: &Item, next: &Item) -> bool {
91 let pk = classify_item_kind(prev);
92 let nk = classify_item_kind(next);
93
94 match (pk, nk) {
96 (ItemKind::Use, ItemKind::Use) => {
97 let Item::Use(prev_use) = prev else { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() };
98 let Item::Use(next_use) = next else { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() };
99 let prev_group = classify_use(prev_use);
100 let next_group = classify_use(next_use);
101 let prev_cfg = prev_use.attrs.iter().any(|a| a.path().is_ident("cfg"));
102 let next_cfg = next_use.attrs.iter().any(|a| a.path().is_ident("cfg"));
103 prev_group != next_group || prev_cfg != next_cfg
104 }
105 (ItemKind::ExternCrate, ItemKind::ExternCrate) => false,
106 (ItemKind::Mod, ItemKind::Mod) => {
107 let prev_pub = #[allow(non_exhaustive_omitted_patterns)] match prev {
Item::Mod(m) if
#[allow(non_exhaustive_omitted_patterns)] match m.vis {
Visibility::Public(_) => true,
_ => false,
} => true,
_ => false,
}matches!(prev, Item::Mod(m) if matches!(m.vis, Visibility::Public(_)));
108 let next_pub = #[allow(non_exhaustive_omitted_patterns)] match next {
Item::Mod(m) if
#[allow(non_exhaustive_omitted_patterns)] match m.vis {
Visibility::Public(_) => true,
_ => false,
} => true,
_ => false,
}matches!(next, Item::Mod(m) if matches!(m.vis, Visibility::Public(_)));
109 prev_pub != next_pub
110 }
111 (ItemKind::Const, ItemKind::Const) => false,
112 (ItemKind::Static, ItemKind::Static) => false,
113 (ItemKind::TypeAlias, ItemKind::TypeAlias) => false,
114 _ => true,
115 }
116}
117
118#[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)]
123enum StmtWeight {
124 Light,
125 Binding,
126 Medium,
127 Heavy,
128 Item,
129}
130
131fn expr_is_heavy(expr: &Expr) -> bool {
132 match expr {
133 Expr::If(_)
134 | Expr::Match(_)
135 | Expr::ForLoop(_)
136 | Expr::While(_)
137 | Expr::Loop(_)
138 | Expr::Block(_)
139 | Expr::Unsafe(_)
140 | Expr::TryBlock(_) => true,
141 Expr::Closure(c) => #[allow(non_exhaustive_omitted_patterns)] match *c.body {
Expr::Block(_) => true,
_ => false,
}matches!(*c.body, Expr::Block(_)),
142 Expr::Assign(a) => expr_is_heavy(&a.right),
143 _ => false,
144 }
145}
146
147fn pat_contains_mut(pat: &Pat) -> bool {
148 match pat {
149 Pat::Ident(p) => p.mutability.is_some(),
150 Pat::Reference(p) => p.mutability.is_some() || pat_contains_mut(&p.pat),
151 Pat::Struct(p) => p.fields.iter().any(|f| pat_contains_mut(&f.pat)),
152 Pat::Tuple(p) => p.elems.iter().any(pat_contains_mut),
153 Pat::TupleStruct(p) => p.elems.iter().any(pat_contains_mut),
154 Pat::Slice(p) => p.elems.iter().any(pat_contains_mut),
155 Pat::Or(p) => p.cases.iter().any(pat_contains_mut),
156 Pat::Type(p) => pat_contains_mut(&p.pat),
157 _ => false,
158 }
159}
160
161fn classify_local(local: &Local) -> StmtWeight {
162 if let Some(init) = &local.init {
163 if init.diverge.is_some() {
164 return StmtWeight::Heavy;
165 }
166
167 if expr_is_heavy(&init.expr) {
168 return StmtWeight::Heavy;
169 }
170 }
171 if pat_contains_mut(&local.pat) {
172 StmtWeight::Binding
173 } else {
174 StmtWeight::Light
175 }
176}
177
178#[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)]
183enum TracingLevel {
184 Trace,
185 Debug,
186 Info,
187 Warn,
188 Error,
189}
190
191fn tracing_level_from_macro(mac: &syn::Macro) -> Option<TracingLevel> {
192 let name = mac.path.segments.last()?.ident.to_string();
193 match name.as_str() {
194 "trace" => Some(TracingLevel::Trace),
195 "debug" => Some(TracingLevel::Debug),
196 "info" => Some(TracingLevel::Info),
197 "warn" => Some(TracingLevel::Warn),
198 "error" => Some(TracingLevel::Error),
199 _ => None,
200 }
201}
202
203fn stmt_is_tracing(stmt: &Stmt) -> Option<TracingLevel> {
205 match stmt {
206 Stmt::Expr(Expr::Macro(m), _) => tracing_level_from_macro(&m.mac),
207 Stmt::Macro(StmtMacro { mac, .. }) => tracing_level_from_macro(mac),
208 _ => None,
209 }
210}
211
212fn tracing_blank_line(prev: &Stmt, next: &Stmt) -> Option<bool> {
214 if let Some(level) = stmt_is_tracing(prev) {
216 return Some(match level {
217 TracingLevel::Trace => false,
218 TracingLevel::Debug => true,
219 TracingLevel::Info | TracingLevel::Warn | TracingLevel::Error => true,
220 });
221 }
222
223 if let Some(level) = stmt_is_tracing(next) {
225 return Some(match level {
226 TracingLevel::Trace => true,
227 TracingLevel::Debug => false,
228 TracingLevel::Info | TracingLevel::Warn | TracingLevel::Error => true,
229 });
230 }
231
232 None
233}
234
235fn classify_weight(stmt: &Stmt) -> StmtWeight {
240 match stmt {
241 Stmt::Local(local) => classify_local(local),
242 Stmt::Expr(expr, _) => {
243 if expr_is_heavy(expr) {
244 StmtWeight::Heavy
245 } else {
246 StmtWeight::Medium
247 }
248 }
249 Stmt::Item(_) => StmtWeight::Item,
250 Stmt::Macro(_) => StmtWeight::Medium,
251 }
252}
253
254fn is_jump_stmt(stmt: &Stmt) -> bool {
255 #[allow(non_exhaustive_omitted_patterns)] match stmt {
Stmt::Expr(Expr::Return(_) | Expr::Continue(_) | Expr::Break(_), _) =>
true,
_ => false,
}matches!(
256 stmt,
257 Stmt::Expr(
258 Expr::Return(_) | Expr::Continue(_) | Expr::Break(_),
259 _
260 )
261 )
262}
263
264fn is_let_else(stmt: &Stmt) -> bool {
265 if let Stmt::Local(local) = stmt {
266 if let Some(init) = &local.init {
267 return init.diverge.is_some();
268 }
269 }
270 false
271}
272
273fn should_blank_between_stmts(prev: &Stmt, next: &Stmt) -> bool {
274 if let Some(decision) = tracing_blank_line(prev, next) {
276 return decision;
277 }
278
279 if is_jump_stmt(next) {
281 return true;
282 }
283
284 if is_let_else(next) {
286 return true;
287 }
288
289 let pw = classify_weight(prev);
290 let nw = classify_weight(next);
291
292 if nw == StmtWeight::Item || pw == StmtWeight::Item {
294 return true;
295 }
296
297 if pw == StmtWeight::Heavy || nw == StmtWeight::Heavy {
299 return true;
300 }
301
302 if pw == nw {
304 return false;
305 }
306
307 true
309}
310
311pub fn stmt_blank_lines(stmts: &[Stmt]) -> Vec<bool> {
315 let len = stmts.len();
316 let mut blanks = ::alloc::vec::from_elem(false, len)vec![false; len];
317 if len <= 1 {
318 return blanks;
319 }
320 for i in 1..len {
321 blanks[i] = should_blank_between_stmts(&stmts[i - 1], &stmts[i]);
322 }
323
324 if len > 1 {
327 if let syn::Stmt::Expr(_, None) = &stmts[len - 1] {
328 blanks[len - 1] = true;
329 }
330 }
331
332 blanks
333}