1 /* valanullchecker.vala
3 * Copyright (C) 2008 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Jürg Billeter <j@bitron.ch>
26 * Code visitor checking null references.
28 public class Vala
.NullChecker
: CodeVisitor
{
29 private CodeContext context
;
31 DataType current_return_type
;
33 public NullChecker () {
36 public void check (CodeContext context
) {
37 this
.context
= context
;
39 context
.accept (this
);
42 void check_compatible (Expression expr
, DataType target_type
) {
43 if (!target_type
.nullable
) {
44 if (expr
.value_type is NullType
) {
45 Report
.error (expr
.source_reference
, "`null' incompatible with `%s'".printf (target_type
.to_string ()));
46 } else if (expr
.value_type
.nullable
) {
47 Report
.warning (expr
.source_reference
, "`%s' incompatible with `%s'".printf (expr
.value_type
.to_string (), target_type
.to_string ()));
52 void check_non_null (Expression expr
) {
53 if (expr
.value_type is NullType
) {
54 Report
.error (expr
.source_reference
, "null dereference");
55 } else if (expr
.value_type
.nullable
) {
56 Report
.warning (expr
.source_reference
, "possible null dereference");
60 public override void visit_source_file (SourceFile file
) {
61 file
.accept_children (this
);
64 public override void visit_class (Class cl
) {
65 cl
.accept_children (this
);
68 public override void visit_struct (Struct st
) {
69 st
.accept_children (this
);
72 public override void visit_interface (Interface iface
) {
73 iface
.accept_children (this
);
76 public override void visit_enum (Enum en
) {
77 en
.accept_children (this
);
80 public override void visit_error_domain (ErrorDomain ed
) {
81 ed
.accept_children (this
);
84 public override void visit_field (Field f
) {
85 f
.accept_children (this
);
88 public override void visit_method (Method m
) {
89 var old_return_type
= current_return_type
;
90 current_return_type
= m
.return_type
;
92 m
.accept_children (this
);
94 current_return_type
= old_return_type
;
97 public override void visit_creation_method (CreationMethod m
) {
98 m
.accept_children (this
);
101 public override void visit_formal_parameter (FormalParameter p
) {
102 p
.accept_children (this
);
104 if (p
.default_expression
!= null) {
105 check_compatible (p
.default_expression
, p
.parameter_type
);
109 public override void visit_property (Property prop
) {
110 prop
.accept_children (this
);
113 public override void visit_property_accessor (PropertyAccessor acc
) {
114 acc
.accept_children (this
);
117 public override void visit_constructor (Constructor c
) {
118 c
.accept_children (this
);
121 public override void visit_destructor (Destructor d
) {
122 d
.accept_children (this
);
125 public override void visit_block (Block b
) {
126 b
.accept_children (this
);
129 public override void visit_local_variable (LocalVariable local
) {
130 local
.accept_children (this
);
132 if (local
.initializer
!= null) {
133 check_compatible (local
.initializer
, local
.variable_type
);
137 public override void visit_expression_statement (ExpressionStatement stmt
) {
138 stmt
.accept_children (this
);
141 public override void visit_if_statement (IfStatement stmt
) {
142 stmt
.accept_children (this
);
144 check_non_null (stmt
.condition
);
147 public override void visit_switch_statement (SwitchStatement stmt
) {
148 stmt
.accept_children (this
);
151 public override void visit_switch_section (SwitchSection section
) {
152 section
.accept_children (this
);
155 public override void visit_while_statement (WhileStatement stmt
) {
156 stmt
.accept_children (this
);
158 check_non_null (stmt
.condition
);
161 public override void visit_do_statement (DoStatement stmt
) {
162 stmt
.accept_children (this
);
164 check_non_null (stmt
.condition
);
167 public override void visit_for_statement (ForStatement stmt
) {
168 stmt
.accept_children (this
);
170 check_non_null (stmt
.condition
);
173 public override void visit_foreach_statement (ForeachStatement stmt
) {
174 stmt
.accept_children (this
);
176 check_non_null (stmt
.collection
);
179 public override void visit_return_statement (ReturnStatement stmt
) {
180 stmt
.accept_children (this
);
182 if (stmt
.return_expression
!= null) {
183 check_compatible (stmt
.return_expression
, current_return_type
);
187 public override void visit_yield_statement (YieldStatement stmt
) {
188 stmt
.accept_children (this
);
191 public override void visit_throw_statement (ThrowStatement stmt
) {
192 stmt
.accept_children (this
);
194 check_non_null (stmt
.error_expression
);
197 public override void visit_try_statement (TryStatement stmt
) {
198 stmt
.accept_children (this
);
201 public override void visit_catch_clause (CatchClause clause
) {
202 clause
.accept_children (this
);
205 public override void visit_delete_statement (DeleteStatement stmt
) {
206 stmt
.accept_children (this
);
209 public override void visit_method_call (MethodCall expr
) {
210 expr
.accept_children (this
);
212 var mtype
= expr
.call
.value_type as MethodType
;
213 var ma
= expr
.call as MemberAccess
;
214 if (mtype
!= null && mtype
.method_symbol
.binding
== MemberBinding
.INSTANCE
&& ma
!= null) {
215 check_non_null (ma
.inner
);
219 public override void visit_element_access (ElementAccess expr
) {
220 expr
.accept_children (this
);
222 check_non_null (expr
.container
);
225 public override void visit_postfix_expression (PostfixExpression expr
) {
226 check_non_null (expr
.inner
);
229 public override void visit_unary_expression (UnaryExpression expr
) {
230 switch (expr
.operator
) {
231 case UnaryOperator
.PLUS
:
232 case UnaryOperator
.MINUS
:
233 case UnaryOperator
.LOGICAL_NEGATION
:
234 case UnaryOperator
.BITWISE_COMPLEMENT
:
235 case UnaryOperator
.INCREMENT
:
236 case UnaryOperator
.DECREMENT
:
237 check_non_null (expr
.inner
);
242 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr
) {
243 expr
.accept_children (this
);
246 public override void visit_lambda_expression (LambdaExpression l
) {
247 l
.accept_children (this
);
250 public override void visit_assignment (Assignment a
) {
251 a
.accept_children (this
);
253 check_compatible (a
.right
, a
.left
.value_type
);