frontend: handle multi-iterators
[nit.git] / src / frontend / simple_misc_analysis.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2012 Jean Privat <jean@pryen.org>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Simple vavious processing on a AST
18 # The analysis warns on :
19 # * superfluous parentheses
20 # * nested "once" expressions
21 # * use of "while true" instead of "loop"
22 module simple_misc_analysis
23
24 import phase
25
26 redef class ToolContext
27 # Execute `AModule::do_simple_misc_analysis` on each module.
28 var simple_misc_analysis_phase: Phase = new SimpleMiscAnalysisPhase(self, null)
29 end
30
31 private class SimpleMiscAnalysisPhase
32 super Phase
33 redef fun process_nmodule(nmodule) do nmodule.do_simple_misc_analysis(toolcontext)
34 end
35
36 redef class AModule
37 # Visit the module to detect easy warnings that does not need the metamodel or the importation
38 # Warnings are displayed on the toolcontext
39 fun do_simple_misc_analysis(toolcontext: ToolContext)
40 do
41 var v = new SimpleMiscVisitor(toolcontext)
42 v.enter_visit(self)
43
44 var t = location.file.first_token
45 while t != null do
46 t.accept_simple_misc_token(v)
47 t = t.next_token
48 end
49 end
50 end
51
52 private class SimpleMiscVisitor
53 super Visitor
54 redef fun visit(n)
55 do
56 n.accept_simple_misc(self)
57 end
58
59 # Number of nested once
60 var once_count: Int = 0
61
62 var toolcontext: ToolContext
63
64 fun warning(node: ANode, tag, msg: String)
65 do
66 toolcontext.warning(node.hot_location, tag, msg)
67 end
68
69 # Issue a warning if `sub` is a standalone `do` block.
70 fun check_do_expr(sub: nullable AExpr)
71 do
72 if sub isa ADoExpr then
73 warning(sub, "useless-do", "Warning: superfluous `do` block.")
74 end
75 end
76 end
77
78
79 ###############################################################################
80
81 redef class ANode
82 private fun accept_simple_misc(v: SimpleMiscVisitor)
83 do
84 visit_all(v)
85 after_simple_misc(v)
86 end
87 private fun after_simple_misc(v: SimpleMiscVisitor) do end
88 end
89
90 redef class Token
91 private fun accept_simple_misc_token(v: SimpleMiscVisitor)
92 do
93 end
94 end
95
96 redef class ASignature
97 redef fun after_simple_misc(v)
98 do
99 if self.n_opar != null and self.n_params.is_empty then
100 v.warning(self, "parentheses", "Warning: superfluous parentheses.")
101 end
102 end
103 end
104
105 redef class AExpr
106 # Warn in case of superfluous parentheses
107 private fun warn_parentheses(v: SimpleMiscVisitor) do end
108 end
109
110 redef class AParExpr
111 redef fun warn_parentheses(v)
112 do
113 v.warning(self, "parentheses", "Warning: superfluous parentheses.")
114 end
115 end
116
117 redef class AParExprs
118 redef fun after_simple_misc(v)
119 do
120 if n_exprs.is_empty then
121 v.warning(self, "parentheses", "Warning: superfluous parentheses.")
122 end
123 end
124 end
125
126 redef class AReturnExpr
127 redef fun after_simple_misc(v)
128 do
129 var e = n_expr
130 if e != null then
131 e.warn_parentheses(v)
132 end
133 end
134 end
135
136 redef class AEscapeExpr
137 redef fun after_simple_misc(v)
138 do
139 var e = n_expr
140 if e != null then
141 e.warn_parentheses(v)
142 end
143 end
144 end
145
146 redef class AWhileExpr
147 redef fun after_simple_misc(v)
148 do
149 if n_expr isa ATrueExpr then
150 v.warning(self, "loop", "Warning: use `loop` instead of `while true do`.")
151 else
152 n_expr.warn_parentheses(v)
153 end
154 v.check_do_expr(n_block)
155 end
156 end
157
158 redef class ADoExpr
159 redef fun after_simple_misc(v)
160 do
161 v.check_do_expr(n_block)
162 end
163 end
164
165 redef class ALoopExpr
166 redef fun after_simple_misc(v)
167 do
168 v.check_do_expr(n_block)
169 end
170 end
171
172 redef class AForExpr
173 redef fun after_simple_misc(v)
174 do
175 v.check_do_expr(n_block)
176 end
177 end
178
179 redef class AForGroup
180 redef fun after_simple_misc(v)
181 do
182 n_expr.warn_parentheses(v)
183 end
184 end
185
186 redef class AWithExpr
187 redef fun after_simple_misc(v)
188 do
189 v.check_do_expr(n_block)
190 end
191 end
192
193 redef class AIfExpr
194 redef fun after_simple_misc(v)
195 do
196 n_expr.warn_parentheses(v)
197 end
198 end
199
200 redef class AIfexprExpr
201 redef fun after_simple_misc(v)
202 do
203 n_expr.warn_parentheses(v)
204 end
205 end
206
207 redef class AOnceExpr
208 redef fun accept_simple_misc(v)
209 do
210 if v.once_count > 0 then
211 v.warning(self, "nested-once", "Warning: useless once in a once expression.")
212 end
213 v.once_count = v.once_count + 1
214
215 super
216
217 v.once_count = v.once_count - 1
218 end
219 end
220
221 redef class TSemi
222 redef fun accept_simple_misc_token(v)
223 do
224 var n = next_token
225 var p = prev_token
226 if
227 n == null or
228 n isa TEol or
229 n isa EOF or
230 n isa TComment or
231 p == null or
232 p isa TEol or
233 p isa EOF or
234 p isa TComment or
235 p isa TSemi
236 then
237 v.warning(self, "semi", "Warning: superfluous `;`.")
238 return
239 end
240 end
241 end