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(
65 &mut self,
66 _ctx: &LintContext<'ast>,
67 _ast: &'ast ast::SourceUnit<'ast>,
68 ) {
69 }
70}
71
72pub struct EarlyLintVisitor<'a, 's, 'ast> {
74 pub ctx: &'a LintContext<'s>,
75 pub passes: &'a mut [Box<dyn EarlyLintPass<'ast> + 's>],
76}
77
78impl<'a, 's, 'ast> EarlyLintVisitor<'a, 's, 'ast>
79where
80 's: 'ast,
81{
82 pub fn new(
83 ctx: &'a LintContext<'s>,
84 passes: &'a mut [Box<dyn EarlyLintPass<'ast> + 's>],
85 ) -> Self {
86 Self { ctx, passes }
87 }
88
89 pub fn post_source_unit(&mut self, ast: &'ast ast::SourceUnit<'ast>) {
92 for pass in self.passes.iter_mut() {
93 pass.check_full_source_unit(self.ctx, ast);
94 }
95 }
96}
97
98impl<'s, 'ast> Visit<'ast> for EarlyLintVisitor<'_, 's, 'ast>
99where
100 's: 'ast,
101{
102 type BreakValue = Never;
103
104 fn visit_doc_comment(&mut self, cmnt: &'ast ast::DocComment) -> ControlFlow<Self::BreakValue> {
105 for pass in self.passes.iter_mut() {
106 pass.check_doc_comment(self.ctx, cmnt)
107 }
108 self.walk_doc_comment(cmnt)
109 }
110
111 fn visit_expr(&mut self, expr: &'ast ast::Expr<'ast>) -> ControlFlow<Self::BreakValue> {
112 for pass in self.passes.iter_mut() {
113 pass.check_expr(self.ctx, expr)
114 }
115 self.walk_expr(expr)
116 }
117
118 fn visit_variable_definition(
119 &mut self,
120 var: &'ast ast::VariableDefinition<'ast>,
121 ) -> ControlFlow<Self::BreakValue> {
122 for pass in self.passes.iter_mut() {
123 pass.check_variable_definition(self.ctx, var)
124 }
125 self.walk_variable_definition(var)
126 }
127
128 fn visit_item_struct(
129 &mut self,
130 strukt: &'ast ast::ItemStruct<'ast>,
131 ) -> ControlFlow<Self::BreakValue> {
132 for pass in self.passes.iter_mut() {
133 pass.check_item_struct(self.ctx, strukt)
134 }
135 self.walk_item_struct(strukt)
136 }
137
138 fn visit_item_function(
139 &mut self,
140 func: &'ast ast::ItemFunction<'ast>,
141 ) -> ControlFlow<Self::BreakValue> {
142 for pass in self.passes.iter_mut() {
143 pass.check_item_function(self.ctx, func)
144 }
145 self.walk_item_function(func)
146 }
147
148 fn visit_import_directive(
149 &mut self,
150 import: &'ast ast::ImportDirective<'ast>,
151 ) -> ControlFlow<Self::BreakValue> {
152 for pass in self.passes.iter_mut() {
153 pass.check_import_directive(self.ctx, import);
154 }
155 self.walk_import_directive(import)
156 }
157
158 fn visit_using_directive(
159 &mut self,
160 using: &'ast ast::UsingDirective<'ast>,
161 ) -> ControlFlow<Self::BreakValue> {
162 for pass in self.passes.iter_mut() {
163 pass.check_using_directive(self.ctx, using);
164 }
165 self.walk_using_directive(using)
166 }
167
168 fn visit_item_contract(
169 &mut self,
170 contract: &'ast ast::ItemContract<'ast>,
171 ) -> ControlFlow<Self::BreakValue> {
172 for pass in self.passes.iter_mut() {
173 pass.check_item_contract(self.ctx, contract);
174 }
175 self.walk_item_contract(contract)
176 }
177
178 }