Skip to main content

forge_lint/linter/
late.rs

1use solar_interface::data_structures::Never;
2use solar_sema::hir;
3use std::ops::ControlFlow;
4
5use super::LintContext;
6
7/// Trait for lints that operate on the HIR (High-level Intermediate Representation).
8/// Its methods mirror `hir::visit::Visit`, with the addition of `LintCotext`.
9pub trait LateLintPass<'hir>: Send + Sync {
10    fn check_nested_source(
11        &mut self,
12        _ctx: &LintContext<'_>,
13        _hir: &'hir hir::Hir<'hir>,
14        _id: hir::SourceId,
15    ) {
16    }
17    fn check_nested_item(
18        &mut self,
19        _ctx: &LintContext<'_>,
20        _hir: &'hir hir::Hir<'hir>,
21        _id: &'hir hir::ItemId,
22    ) {
23    }
24    fn check_nested_contract(
25        &mut self,
26        _ctx: &LintContext<'_>,
27        _hir: &'hir hir::Hir<'hir>,
28        _id: &'hir hir::ContractId,
29    ) {
30    }
31    fn check_nested_function(
32        &mut self,
33        _ctx: &LintContext<'_>,
34        _hir: &'hir hir::Hir<'hir>,
35        _id: &'hir hir::FunctionId,
36    ) {
37    }
38    fn check_nested_var(
39        &mut self,
40        _ctx: &LintContext<'_>,
41        _hir: &'hir hir::Hir<'hir>,
42        _id: &'hir hir::VariableId,
43    ) {
44    }
45    fn check_item(
46        &mut self,
47        _ctx: &LintContext<'_>,
48        _hir: &'hir hir::Hir<'hir>,
49        _item: hir::Item<'hir, 'hir>,
50    ) {
51    }
52    fn check_contract(
53        &mut self,
54        _ctx: &LintContext<'_>,
55        _hir: &'hir hir::Hir<'hir>,
56        _contract: &'hir hir::Contract<'hir>,
57    ) {
58    }
59    fn check_function(
60        &mut self,
61        _ctx: &LintContext<'_>,
62        _hir: &'hir hir::Hir<'hir>,
63        _func: &'hir hir::Function<'hir>,
64    ) {
65    }
66    fn check_modifier(
67        &mut self,
68        _ctx: &LintContext<'_>,
69        _hir: &'hir hir::Hir<'hir>,
70        _mod: &'hir hir::Modifier<'hir>,
71    ) {
72    }
73    fn check_var(
74        &mut self,
75        _ctx: &LintContext<'_>,
76        _hir: &'hir hir::Hir<'hir>,
77        _var: &'hir hir::Variable<'hir>,
78    ) {
79    }
80    fn check_expr(
81        &mut self,
82        _ctx: &LintContext<'_>,
83        _hir: &'hir hir::Hir<'hir>,
84        _expr: &'hir hir::Expr<'hir>,
85    ) {
86    }
87    fn check_call_args(
88        &mut self,
89        _ctx: &LintContext<'_>,
90        _hir: &'hir hir::Hir<'hir>,
91        _args: &'hir hir::CallArgs<'hir>,
92    ) {
93    }
94    fn check_stmt(
95        &mut self,
96        _ctx: &LintContext<'_>,
97        _hir: &'hir hir::Hir<'hir>,
98        _stmt: &'hir hir::Stmt<'hir>,
99    ) {
100    }
101    fn check_ty(
102        &mut self,
103        _ctx: &LintContext<'_>,
104        _hir: &'hir hir::Hir<'hir>,
105        _ty: &'hir hir::Type<'hir>,
106    ) {
107    }
108}
109
110/// Visitor struct for `LateLintPass`es
111pub struct LateLintVisitor<'a, 's, 'hir> {
112    ctx: &'a LintContext<'s>,
113    passes: &'a mut [Box<dyn LateLintPass<'hir> + 's>],
114    hir: &'hir hir::Hir<'hir>,
115}
116
117impl<'a, 's, 'hir> LateLintVisitor<'a, 's, 'hir>
118where
119    's: 'hir,
120{
121    pub fn new(
122        ctx: &'a LintContext<'s>,
123        passes: &'a mut [Box<dyn LateLintPass<'hir> + 's>],
124        hir: &'hir hir::Hir<'hir>,
125    ) -> Self {
126        Self { ctx, passes, hir }
127    }
128}
129
130impl<'s, 'hir> hir::Visit<'hir> for LateLintVisitor<'_, 's, 'hir>
131where
132    's: 'hir,
133{
134    type BreakValue = Never;
135
136    fn hir(&self) -> &'hir hir::Hir<'hir> {
137        self.hir
138    }
139
140    fn visit_nested_source(&mut self, id: hir::SourceId) -> ControlFlow<Self::BreakValue> {
141        for pass in self.passes.iter_mut() {
142            pass.check_nested_source(self.ctx, self.hir, id);
143        }
144        self.walk_nested_source(id)
145    }
146
147    fn visit_contract(
148        &mut self,
149        contract: &'hir hir::Contract<'hir>,
150    ) -> ControlFlow<Self::BreakValue> {
151        for pass in self.passes.iter_mut() {
152            pass.check_contract(self.ctx, self.hir, contract);
153        }
154        self.walk_contract(contract)
155    }
156
157    fn visit_function(&mut self, func: &'hir hir::Function<'hir>) -> ControlFlow<Self::BreakValue> {
158        for pass in self.passes.iter_mut() {
159            pass.check_function(self.ctx, self.hir, func);
160        }
161        self.walk_function(func)
162    }
163
164    fn visit_item(&mut self, item: hir::Item<'hir, 'hir>) -> ControlFlow<Self::BreakValue> {
165        for pass in self.passes.iter_mut() {
166            pass.check_item(self.ctx, self.hir, item);
167        }
168        self.walk_item(item)
169    }
170
171    fn visit_var(&mut self, var: &'hir hir::Variable<'hir>) -> ControlFlow<Self::BreakValue> {
172        for pass in self.passes.iter_mut() {
173            pass.check_var(self.ctx, self.hir, var);
174        }
175        self.walk_var(var)
176    }
177
178    fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) -> ControlFlow<Self::BreakValue> {
179        for pass in self.passes.iter_mut() {
180            pass.check_expr(self.ctx, self.hir, expr);
181        }
182        self.walk_expr(expr)
183    }
184
185    fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'hir>) -> ControlFlow<Self::BreakValue> {
186        for pass in self.passes.iter_mut() {
187            pass.check_stmt(self.ctx, self.hir, stmt);
188        }
189        self.walk_stmt(stmt)
190    }
191
192    fn visit_ty(&mut self, ty: &'hir hir::Type<'hir>) -> ControlFlow<Self::BreakValue> {
193        for pass in self.passes.iter_mut() {
194            pass.check_ty(self.ctx, self.hir, ty);
195        }
196        self.walk_ty(ty)
197    }
198}