1 /* valamemorymanager.vala
3 * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini
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 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>
21 * Raffaele Sandrini <rasa@gmx.ch>
27 * Code visitor analyzing memory usage. The memory manager finds leaked and
30 public class Vala
.MemoryManager
: CodeVisitor
{
31 Symbol current_symbol
;
34 * Analyze memory usage in the specified code context.
36 * @param context a code context
38 public void analyze (CodeContext
! context
) {
39 context
.accept (this
);
42 private void visit_possibly_leaked_expression (Expression
! expr
) {
43 if (expr
.static_type
!= null &&
44 ((expr
.static_type
.data_type
!= null &&
45 expr
.static_type
.data_type
.is_reference_type ()) ||
46 expr
.static_type
.type_parameter
!= null) &&
47 expr
.static_type
.transfers_ownership
) {
48 /* mark reference as leaked */
49 expr
.ref_leaked
= true;
53 private void visit_possibly_missing_copy_expression (Expression
! expr
) {
54 if (expr
.static_type
!= null &&
55 ((expr
.static_type
.data_type
!= null &&
56 expr
.static_type
.data_type
.is_reference_type ()) ||
57 expr
.static_type
.type_parameter
!= null) &&
58 !expr
.static_type
.transfers_ownership
) {
59 /* mark reference as missing */
60 expr
.ref_missing
= true;
64 public override void visit_source_file (SourceFile
! source_file
) {
65 source_file
.accept_children (this
);
68 public override void visit_namespace (Namespace
! ns
) {
69 ns
.accept_children (this
);
72 public override void visit_class (Class
! cl
) {
73 cl
.accept_children (this
);
76 public override void visit_struct (Struct
! st
) {
77 st
.accept_children (this
);
80 public override void visit_interface (Interface
! iface
) {
81 iface
.accept_children (this
);
84 public override void visit_field (Field
! f
) {
85 if (f
.initializer
!= null) {
86 if (f
.type_reference
.takes_ownership
) {
87 visit_possibly_missing_copy_expression (f
.initializer
);
89 visit_possibly_leaked_expression (f
.initializer
);
94 public override void visit_method (Method
! m
) {
95 current_symbol
= m
.symbol
;
97 m
.accept_children (this
);
100 public override void visit_creation_method (CreationMethod
! m
) {
104 public override void visit_property (Property
! prop
) {
105 current_symbol
= prop
.symbol
;
107 prop
.accept_children (this
);
110 public override void visit_property_accessor (PropertyAccessor
! acc
) {
111 acc
.accept_children (this
);
114 public override void visit_constructor (Constructor
! c
) {
115 c
.accept_children (this
);
118 public override void visit_destructor (Destructor
! d
) {
119 d
.accept_children (this
);
122 public override void visit_named_argument (NamedArgument
! n
) {
123 visit_possibly_leaked_expression (n
.argument
);
126 public override void visit_variable_declarator (VariableDeclarator
! decl
) {
127 if (decl
.initializer
!= null) {
128 if (decl
.type_reference
.takes_ownership
) {
129 visit_possibly_missing_copy_expression (decl
.initializer
);
131 visit_possibly_leaked_expression (decl
.initializer
);
136 public override void visit_expression_statement (ExpressionStatement
! stmt
) {
137 visit_possibly_leaked_expression (stmt
.expression
);
140 public override void visit_end_return_statement (ReturnStatement
! stmt
) {
141 if (stmt
.return_expression
!= null) {
142 if (current_symbol
.node is Method
) {
143 var m
= (Method
) current_symbol
.node
;
145 if (m
.return_type
.transfers_ownership
) {
146 visit_possibly_missing_copy_expression (stmt
.return_expression
);
148 visit_possibly_leaked_expression (stmt
.return_expression
);
151 /* property get accessor */
152 visit_possibly_leaked_expression (stmt
.return_expression
);
157 public override void visit_member_access (MemberAccess
! expr
) {
158 if (expr
.inner
!= null) {
159 visit_possibly_leaked_expression (expr
.inner
);
163 public override void visit_end_invocation_expression (InvocationExpression
! expr
) {
164 List
<weak FormalParameter
> params
;
166 var msym
= expr
.call
.symbol_reference
;
167 if (msym
.node is VariableDeclarator
) {
168 var decl
= (VariableDeclarator
) msym
.node
;
169 var cb
= (Callback
) decl
.type_reference
.data_type
;
170 params
= cb
.get_parameters ();
171 } else if (msym
.node is FormalParameter
) {
172 var param
= (FormalParameter
) msym
.node
;
173 var cb
= (Callback
) param
.type_reference
.data_type
;
174 params
= cb
.get_parameters ();
175 } else if (msym
.node is Field
) {
176 var f
= (Field
) msym
.node
;
177 var cb
= (Callback
) f
.type_reference
.data_type
;
178 params
= cb
.get_parameters ();
179 } else if (msym
.node is Method
) {
180 var m
= (Method
) msym
.node
;
181 params
= m
.get_parameters ();
182 } else if (msym
.node is Signal
) {
183 var sig
= (Signal
) msym
.node
;
184 params
= sig
.get_parameters ();
186 weak List
<weak FormalParameter
> params_it
= params
;
187 foreach (Expression arg
in expr
.get_argument_list ()) {
188 if (params_it
!= null) {
189 var param
= (FormalParameter
) params_it
.data
;
191 && ((param
.type_reference
.data_type
!= null
192 && param
.type_reference
.data_type
.is_reference_type ())
193 || param
.type_reference
.type_parameter
!= null)) {
194 bool is_ref
= param
.type_reference
.takes_ownership
;
195 if (is_ref
&& param
.type_reference
.type_parameter
!= null) {
196 // TODO move this to semantic analyzer
197 if (expr
.call is MemberAccess
) {
198 var ma
= (MemberAccess
) expr
.call
;
199 TypeReference instance_type
= ma
.inner
.static_type
;
200 // trace type arguments back to the datatype where the method has been declared
201 while (instance_type
.data_type
!= msym
.parent_symbol
.node
) {
202 List
<weak TypeReference
> base_types
= null;
203 if (instance_type
.data_type is Class
) {
204 var cl
= (Class
) instance_type
.data_type
;
205 base_types
= cl
.get_base_types ();
206 } else if (instance_type
.data_type is Interface
) {
207 var iface
= (Interface
) instance_type
.data_type
;
208 base_types
= iface
.get_prerequisites ();
210 Report
.error (expr
.source_reference
, "internal error: unsupported generic type");
214 foreach (TypeReference base_type
in base_types
) {
215 if (SemanticAnalyzer
.symbol_lookup_inherited (base_type
.data_type
.symbol
, msym
.name
) != null) {
216 // construct a new type reference for the base type with correctly linked type arguments
217 var instance_base_type
= new
TypeReference ();
218 instance_base_type
.data_type
= base_type
.data_type
;
219 foreach (TypeReference type_arg
in base_type
.get_type_arguments ()) {
220 if (type_arg
.type_parameter
!= null) {
221 // link to type argument of derived type
222 int param_index
= instance_type
.data_type
.get_type_parameter_index (type_arg
.type_parameter
.name
);
223 if (param_index
== -1) {
224 Report
.error (expr
.source_reference
, "internal error: unknown type parameter %s".printf (type_arg
.type_parameter
.name
));
228 type_arg
= instance_type
.get_type_arguments ().nth_data (param_index
);
230 instance_base_type
.add_type_argument (type_arg
);
232 instance_type
= instance_base_type
;
236 if (instance_type
.data_type
!= msym
.parent_symbol
.node
) {
237 Report
.error (expr
.source_reference
, "internal error: generic type parameter tracing not supported yet");
241 int param_index
= instance_type
.data_type
.get_type_parameter_index (param
.type_reference
.type_parameter
.name
);
242 if (param_index
== -1) {
243 Report
.error (expr
.source_reference
, "internal error: unknown type parameter %s".printf (param
.type_reference
.type_parameter
.name
));
247 var param_type
= (TypeReference
) instance_type
.get_type_arguments ().nth_data (param_index
);
248 if (param_type
== null) {
249 Report
.error (expr
.source_reference
, "internal error: no actual argument found for type parameter %s".printf (param
.type_reference
.type_parameter
.name
));
253 is_ref
= param_type
.takes_ownership
;
258 visit_possibly_missing_copy_expression (arg
);
260 visit_possibly_leaked_expression (arg
);
263 visit_possibly_leaked_expression (arg
);
266 params_it
= params_it
.next
;
268 visit_possibly_leaked_expression (arg
);
273 public override void visit_binary_expression (BinaryExpression
! expr
) {
274 visit_possibly_leaked_expression (expr
.left
);
275 visit_possibly_leaked_expression (expr
.right
);
278 public override void visit_end_assignment (Assignment
! a
) {
279 if (a
.left is PointerIndirection
|| (a
.left
.symbol_reference
!= null && a
.left
.symbol_reference
.node is Signal
)) {
281 if (a
.left
.static_type
.takes_ownership
) {
282 visit_possibly_missing_copy_expression (a
.right
);
284 visit_possibly_leaked_expression (a
.right
);