1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2012 Jean Privat <jean@pryen.org>
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
17 # Verify that local variables are initialized before their usage
18 # Require that the scope and the flow analaysis are already performed
25 # Entry point of the whole local variable initialization verifier
26 fun do_local_var_init
(toolcontext
: ToolContext)
28 var v
= new LocalVarInitVisitor(toolcontext
)
33 private class LocalVarInitVisitor
36 var toolcontext
: ToolContext
38 init(toolcontext
: ToolContext)
40 self.toolcontext
= toolcontext
43 # Local variables that are possibily unset (ie local variable without an initial value)
44 var maybe_unset_vars
: Set[Variable] = new HashSet[Variable]
46 fun mark_is_unset
(node
: AExpr, variable
: nullable Variable)
48 assert variable
!= null
49 self.maybe_unset_vars
.add
(variable
)
52 fun mark_is_set
(node
: AExpr, variable
: nullable Variable)
54 assert variable
!= null
55 if not maybe_unset_vars
.has
(variable
) then return
57 var flow
= node
.after_flow_context
.as(not null)
58 flow
.set_vars
.add
(variable
)
61 fun check_is_set
(node
: AExpr, variable
: nullable Variable)
63 assert variable
!= null
64 if not maybe_unset_vars
.has
(variable
) then return
66 var flow
= node
.after_flow_context
.as(not null)
67 if not flow
.is_variable_set
(variable
) then
68 self.toolcontext
.error
(node
.hot_location
, "Error: variable '{variable}' is possibly unset.")
69 # Remove the variable to avoid repetting errors
70 self.maybe_unset_vars
.remove
(variable
)
76 if n
!= null then n
.accept_local_var_visitor
(self)
80 redef class FlowContext
81 private var set_vars
: Set[Variable] = new HashSet[Variable]
83 private fun is_variable_set
(variable
: Variable): Bool
85 if self.set_vars
.has
(variable
) then return true
86 var previous
= self.previous
87 if previous
.length
== 0 then return false
88 if previous
.length
== 1 then return previous
.first
.is_variable_set
(variable
)
89 for p
in self.previous
do
90 if not p
.is_variable_set
(variable
) then
95 self.set_vars
.add
(variable
)
101 private fun accept_local_var_visitor
(v
: LocalVarInitVisitor) do self.visit_all
(v
)
104 redef class AVardeclExpr
105 redef fun accept_local_var_visitor
(v
)
108 # The variable is unset only if there is no initial value.
110 # Note: loops in inital value are not a problem
113 # var foo = foo + 1 #-> Error during typing: "self.foo" unknown
116 # foo = foo + 1 #-> Error here because 'foo' is possibly unset
117 if self.n_expr
== null then
118 v
.mark_is_unset
(self, self.variable
)
124 redef fun accept_local_var_visitor
(v
)
127 v
.check_is_set
(self, self.variable
)
131 redef class AVarAssignExpr
132 redef fun accept_local_var_visitor
(v
)
135 v
.mark_is_set
(self, self.variable
)
139 redef class AVarReassignExpr
140 redef fun accept_local_var_visitor
(v
)
143 v
.check_is_set
(self, self.variable
)