cairo_lint/lints/
breaks.rs1use cairo_lang_defs::ids::ModuleItemId;
2use cairo_lang_defs::plugin::PluginDiagnostic;
3use cairo_lang_diagnostics::Severity;
4use cairo_lang_semantic::{Arenas, StatementBreak};
5
6use cairo_lang_syntax::node::{SyntaxNode, TypedStablePtr};
7use if_chain::if_chain;
8
9use crate::context::{CairoLintKind, Lint};
10
11use crate::fixer::InternalFix;
12use crate::queries::{get_all_break_statements, get_all_function_bodies};
13use salsa::Database;
14
15pub struct BreakUnit;
16
17impl Lint for BreakUnit {
41 fn allowed_name(&self) -> &'static str {
42 "break_unit"
43 }
44
45 fn diagnostic_message(&self) -> &'static str {
46 "unnecessary double parentheses found after break. Consider removing them."
47 }
48
49 fn kind(&self) -> CairoLintKind {
50 CairoLintKind::BreakUnit
51 }
52
53 fn has_fixer(&self) -> bool {
54 true
55 }
56
57 fn fix<'db>(&self, db: &'db dyn Database, node: SyntaxNode<'db>) -> Option<InternalFix<'db>> {
58 fix_break_unit(db, node)
59 }
60
61 fn fix_message(&self) -> Option<&'static str> {
62 Some("Remove unnecessary parentheses from break")
63 }
64}
65
66#[tracing::instrument(skip_all, level = "trace")]
67pub fn check_break<'db>(
68 db: &'db dyn Database,
69 item: &ModuleItemId<'db>,
70 diagnostics: &mut Vec<PluginDiagnostic<'db>>,
71) {
72 let function_bodies = get_all_function_bodies(db, item);
73 for function_body in function_bodies {
74 let break_exprs = get_all_break_statements(function_body);
75 for break_expr in break_exprs.iter() {
76 check_single_break(db, break_expr, &function_body.arenas, diagnostics)
77 }
78 }
79}
80
81fn check_single_break<'db>(
82 db: &'db dyn Database,
83 break_expr: &StatementBreak<'db>,
84 arenas: &Arenas<'db>,
85 diagnostics: &mut Vec<PluginDiagnostic<'db>>,
86) {
87 if_chain! {
88 if let Some(expr) = break_expr.expr_option;
89 if arenas.exprs[expr].ty().is_unit(db);
90 then {
91 diagnostics.push(PluginDiagnostic {
92 stable_ptr: break_expr.stable_ptr.untyped(),
93 message: BreakUnit.diagnostic_message().to_string(),
94 severity: Severity::Warning,
95 inner_span: None,
96 error_code: None,
97 });
98 }
99 }
100}
101
102#[tracing::instrument(skip_all, level = "trace")]
104pub fn fix_break_unit<'db>(
105 db: &'db dyn Database,
106 node: SyntaxNode<'db>,
107) -> Option<InternalFix<'db>> {
108 Some(InternalFix {
109 node,
110 suggestion: node.get_text(db).replace("break ();", "break;").to_string(),
111 description: BreakUnit.fix_message().unwrap().to_string(),
112 import_addition_paths: None,
113 })
114}