Fix crash when using out parameters in delegates, fixes bug 563705
[vala-lang.git] / vala / valanullchecker.vala
blobd2ba8245d5b4748b4c33ddacacf3f6b34ea9e378
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
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
25 /**
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);
238 break;
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);