forge_lint/linter/
early.rs1use solar_ast::{self as ast, visit::Visit};
2use solar_interface::data_structures::Never;
3use std::ops::ControlFlow;
4
5use super::LintContext;
6
7pub trait EarlyLintPass<'ast>: Send + Sync {
10 fn check_expr(&mut self, _ctx: &LintContext<'_>, _expr: &'ast ast::Expr<'ast>) {}
11 fn check_item_struct(&mut self, _ctx: &LintContext<'_>, _struct: &'ast ast::ItemStruct<'ast>) {}
12 fn check_item_function(
13 &mut self,
14 _ctx: &LintContext<'_>,
15 _func: &'ast ast::ItemFunction<'ast>,
16 ) {
17 }
18 fn check_variable_definition(
19 &mut self,
20 _ctx: &LintContext<'_>,
21 _var: &'ast ast::VariableDefinition<'ast>,
22 ) {
23 }
24 fn check_import_directive(
25 &mut self,
26 _ctx: &LintContext<'_>,
27 _import: &'ast ast::ImportDirective<'ast>,
28 ) {
29 }
30 fn check_using_directive(
31 &mut self,
32 _ctx: &LintContext<'_>,
33 _using: &'ast ast::UsingDirective<'ast>,
34 ) {
35 }
36 fn check_item_contract(
37 &mut self,
38 _ctx: &LintContext<'_>,
39 _contract: &'ast ast::ItemContract<'ast>,
40 ) {
41 }
42 fn check_doc_comment(&mut self, _ctx: &LintContext<'_>, _cmnt: &'ast ast::DocComment) {}
43 fn check_full_source_unit(
48 &mut self,
49 _ctx: &LintContext<'ast>,
50 _ast: &'ast ast::SourceUnit<'ast>,
51 ) {
52 }
53}
54
55pub struct EarlyLintVisitor<'a, 's, 'ast> {
57 pub ctx: &'a LintContext<'s>,
58 pub passes: &'a mut [Box<dyn EarlyLintPass<'ast> + 's>],
59}
60
61impl<'a, 's, 'ast> EarlyLintVisitor<'a, 's, 'ast>
62where
63 's: 'ast,
64{
65 pub fn new(
66 ctx: &'a LintContext<'s>,
67 passes: &'a mut [Box<dyn EarlyLintPass<'ast> + 's>],
68 ) -> Self {
69 Self { ctx, passes }
70 }
71
72 pub fn post_source_unit(&mut self, ast: &'ast ast::SourceUnit<'ast>) {
75 for pass in self.passes.iter_mut() {
76 pass.check_full_source_unit(self.ctx, ast);
77 }
78 }
79}
80
81impl<'s, 'ast> Visit<'ast> for EarlyLintVisitor<'_, 's, 'ast>
82where
83 's: 'ast,
84{
85 type BreakValue = Never;
86
87 fn visit_doc_comment(&mut self, cmnt: &'ast ast::DocComment) -> ControlFlow<Self::BreakValue> {
88 for pass in self.passes.iter_mut() {
89 pass.check_doc_comment(self.ctx, cmnt)
90 }
91 self.walk_doc_comment(cmnt)
92 }
93
94 fn visit_expr(&mut self, expr: &'ast ast::Expr<'ast>) -> ControlFlow<Self::BreakValue> {
95 for pass in self.passes.iter_mut() {
96 pass.check_expr(self.ctx, expr)
97 }
98 self.walk_expr(expr)
99 }
100
101 fn visit_variable_definition(
102 &mut self,
103 var: &'ast ast::VariableDefinition<'ast>,
104 ) -> ControlFlow<Self::BreakValue> {
105 for pass in self.passes.iter_mut() {
106 pass.check_variable_definition(self.ctx, var)
107 }
108 self.walk_variable_definition(var)
109 }
110
111 fn visit_item_struct(
112 &mut self,
113 strukt: &'ast ast::ItemStruct<'ast>,
114 ) -> ControlFlow<Self::BreakValue> {
115 for pass in self.passes.iter_mut() {
116 pass.check_item_struct(self.ctx, strukt)
117 }
118 self.walk_item_struct(strukt)
119 }
120
121 fn visit_item_function(
122 &mut self,
123 func: &'ast ast::ItemFunction<'ast>,
124 ) -> ControlFlow<Self::BreakValue> {
125 for pass in self.passes.iter_mut() {
126 pass.check_item_function(self.ctx, func)
127 }
128 self.walk_item_function(func)
129 }
130
131 fn visit_import_directive(
132 &mut self,
133 import: &'ast ast::ImportDirective<'ast>,
134 ) -> ControlFlow<Self::BreakValue> {
135 for pass in self.passes.iter_mut() {
136 pass.check_import_directive(self.ctx, import);
137 }
138 self.walk_import_directive(import)
139 }
140
141 fn visit_using_directive(
142 &mut self,
143 using: &'ast ast::UsingDirective<'ast>,
144 ) -> ControlFlow<Self::BreakValue> {
145 for pass in self.passes.iter_mut() {
146 pass.check_using_directive(self.ctx, using);
147 }
148 self.walk_using_directive(using)
149 }
150
151 fn visit_item_contract(
152 &mut self,
153 contract: &'ast ast::ItemContract<'ast>,
154 ) -> ControlFlow<Self::BreakValue> {
155 for pass in self.passes.iter_mut() {
156 pass.check_item_contract(self.ctx, contract);
157 }
158 self.walk_item_contract(contract)
159 }
160
161 }