Line data Source code
1 : /* valamemberaccess.vala
2 : *
3 : * Copyright (C) 2006-2012 Jürg Billeter
4 : *
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.
9 :
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.
14 :
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
18 : *
19 : * Author:
20 : * Jürg Billeter <j@bitron.ch>
21 : */
22 :
23 : using GLib;
24 :
25 : /**
26 : * Represents an access to a type member in the source code.
27 : */
28 3896696 : public class Vala.MemberAccess : Expression {
29 : /**
30 : * The parent of the member.
31 : */
32 : public Expression? inner {
33 38560437 : get {
34 38560437 : return _inner;
35 : }
36 2008747 : set {
37 2241149 : _inner = value;
38 2008747 : if (_inner != null) {
39 499258 : _inner.parent_node = this;
40 : }
41 : }
42 : }
43 :
44 : /**
45 : * The name of the member.
46 : */
47 6283445 : public string member_name { get; set; }
48 :
49 : /**
50 : * Pointer member access.
51 : */
52 2967 : public bool pointer_member_access { get; set; }
53 :
54 : /**
55 : * Represents access to an instance member without an actual instance,
56 : * e.g. `MyClass.an_instance_method`.
57 : */
58 541586 : public bool prototype_access { get; set; }
59 :
60 : /**
61 : * Requires indirect access due to possible side-effects of parent expression.
62 : */
63 1765454 : public bool tainted_access { get; set; }
64 :
65 : /**
66 : * Qualified access to global symbol.
67 : */
68 1129210 : public bool qualified { get; set; }
69 :
70 : /**
71 : * Null-safe access.
72 : */
73 610067 : public bool null_safe_access { get; set; }
74 :
75 1947579 : private Expression? _inner;
76 3895158 : private List<DataType> type_argument_list = new ArrayList<DataType> ();
77 : bool is_with_variable_access;
78 :
79 : /**
80 : * Creates a new member access expression.
81 : *
82 : * @param inner parent of the member
83 : * @param member_name member name
84 : * @param source_reference reference to source code
85 : * @return newly created member access expression
86 : */
87 5192142 : public MemberAccess (Expression? inner, string member_name, SourceReference? source_reference = null) {
88 1730714 : this.inner = inner;
89 1730714 : this.member_name = member_name;
90 1730714 : this.source_reference = source_reference;
91 : }
92 :
93 645981 : public MemberAccess.simple (string member_name, SourceReference? source_reference = null) {
94 215327 : this.inner = null;
95 215327 : this.member_name = member_name;
96 215327 : this.source_reference = source_reference;
97 : }
98 :
99 4614 : public MemberAccess.pointer (Expression inner, string member_name, SourceReference? source_reference = null) {
100 1538 : this.inner = inner;
101 1538 : this.member_name = member_name;
102 1538 : this.source_reference = source_reference;
103 1538 : pointer_member_access = true;
104 : }
105 :
106 : /**
107 : * Appends the specified type as generic type argument.
108 : *
109 : * @param arg a type reference
110 : */
111 2182 : public void add_type_argument (DataType arg) {
112 2182 : type_argument_list.add (arg);
113 2182 : arg.parent_node = this;
114 : }
115 :
116 : /**
117 : * Returns the list of generic type arguments.
118 : *
119 : * @return type argument list
120 : */
121 416050 : public unowned List<DataType> get_type_arguments () {
122 416050 : return type_argument_list;
123 : }
124 :
125 6567312 : public override void accept (CodeVisitor visitor) {
126 6567312 : visitor.visit_member_access (this);
127 :
128 6567312 : visitor.visit_expression (this);
129 : }
130 :
131 6567302 : public override void accept_children (CodeVisitor visitor) {
132 6567302 : if (inner != null) {
133 1663126 : inner.accept (visitor);
134 : }
135 :
136 6584886 : foreach (DataType type_arg in type_argument_list) {
137 8792 : type_arg.accept (visitor);
138 : }
139 : }
140 :
141 8163 : public override string to_string () {
142 8163 : if (symbol_reference == null || symbol_reference.is_instance_member ()) {
143 7906 : if (inner == null) {
144 6880 : return member_name;
145 : } else {
146 4466 : return "%s%s%s".printf (inner.to_string (), pointer_member_access ? "->" : ".", member_name);
147 : }
148 : } else {
149 : // ensure to always use fully-qualified name
150 : // to refer to static members
151 257 : return symbol_reference.get_full_name ();
152 : }
153 : }
154 :
155 59 : public override void replace_expression (Expression old_node, Expression new_node) {
156 59 : if (inner == old_node) {
157 59 : inner = new_node;
158 : }
159 : }
160 :
161 0 : public override bool is_pure () {
162 : // accessing property could have side-effects
163 0 : return (inner == null || inner.is_pure ()) && !(symbol_reference is Property);
164 : }
165 :
166 304203 : public override bool is_accessible (Symbol sym) {
167 304203 : return (inner == null || inner.is_accessible (sym)) && symbol_reference.is_accessible (sym);
168 : }
169 :
170 542 : public override void replace_type (DataType old_type, DataType new_type) {
171 648 : for (int i = 0; i < type_argument_list.size; i++) {
172 648 : if (type_argument_list[i] == old_type) {
173 542 : type_argument_list[i] = new_type;
174 542 : return;
175 : }
176 : }
177 : }
178 :
179 14132 : public override bool is_constant () {
180 14132 : unowned Method? method = symbol_reference as Method;
181 14132 : if (symbol_reference is Constant) {
182 13583 : return true;
183 559 : } else if (symbol_reference is ArrayLengthField && inner != null && inner.symbol_reference is Constant) {
184 : // length of constant array
185 13583 : return true;
186 559 : } else if (method != null &&
187 10 : (method.binding == MemberBinding.STATIC || prototype_access)) {
188 13583 : return true;
189 : } else {
190 549 : return false;
191 : }
192 : }
193 :
194 101633 : public override bool is_non_null () {
195 101633 : unowned Constant? c = symbol_reference as Constant;
196 101633 : unowned LocalVariable? l = symbol_reference as LocalVariable;
197 101633 : unowned Method? m = symbol_reference as Method;
198 101633 : if (c != null) {
199 222 : return (c is EnumValue || !c.type_reference.nullable);
200 101411 : } else if (l != null) {
201 24698 : unowned DataType type = l.variable_type;
202 24698 : if (type is ArrayType) {
203 1606 : return ((ArrayType) type).inline_allocated;
204 : } else {
205 23092 : return type.is_real_non_null_struct_type () || type.is_non_null_simple_type ();
206 : }
207 76713 : } else if (m != null) {
208 29762 : return (m.binding == MemberBinding.STATIC || prototype_access);
209 : } else {
210 101633 : return false;
211 : }
212 : }
213 :
214 2372643 : public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
215 2372643 : if (inner != null) {
216 264012 : inner.get_error_types (collection, source_reference);
217 : }
218 : }
219 :
220 2018018 : public override bool check (CodeContext context) {
221 2018018 : if (checked) {
222 321898 : return !error;
223 : }
224 :
225 1696120 : checked = true;
226 :
227 1696120 : if (null_safe_access) {
228 13 : error = !base.check (context);
229 13 : return !error;
230 : }
231 :
232 1696107 : if (inner != null) {
233 408090 : inner.check (context);
234 : }
235 :
236 1700027 : foreach (DataType type_arg in type_argument_list) {
237 1960 : type_arg.check (context);
238 : }
239 :
240 1696107 : unowned Symbol? base_symbol = null;
241 1696107 : unowned Parameter? this_parameter = null;
242 1696107 : bool may_access_instance_members = false;
243 1696107 : bool may_access_klass_members = false;
244 :
245 1696107 : var visited_types = new ArrayList<DataType> ();
246 :
247 1696107 : symbol_reference = null;
248 :
249 1696107 : if (qualified) {
250 7555 : base_symbol = context.root;
251 7555 : symbol_reference = base_symbol.scope.lookup (member_name);
252 1688552 : } else if (inner == null) {
253 1280462 : if (member_name == "this") {
254 116163 : if (!context.analyzer.is_in_instance_method ()) {
255 1 : error = true;
256 1 : Report.error (source_reference, "This access invalid outside of instance methods");
257 1 : return false;
258 : }
259 : }
260 :
261 1280461 : base_symbol = context.analyzer.current_symbol;
262 :
263 : // track whether method has been found to make sure that access
264 : // to instance member is denied from within static lambda expressions
265 1280461 : bool method_found = false;
266 :
267 1280461 : unowned Symbol? sym = context.analyzer.current_symbol;
268 4746856 : while (sym != null && symbol_reference == null) {
269 3466395 : if (!method_found) {
270 2764920 : if (sym is CreationMethod) {
271 13044 : unowned CreationMethod cm = (CreationMethod) sym;
272 13044 : this_parameter = cm.this_parameter;
273 13044 : may_access_instance_members = true;
274 13044 : may_access_klass_members = true;
275 13044 : method_found = true;
276 2751876 : } else if (sym is Property) {
277 10032 : unowned Property prop = (Property) sym;
278 10032 : this_parameter = prop.this_parameter;
279 10032 : may_access_instance_members = (prop.binding == MemberBinding.INSTANCE);
280 10032 : may_access_klass_members = (prop.binding != MemberBinding.STATIC);
281 10032 : method_found = true;
282 2741844 : } else if (sym is Constructor) {
283 120 : unowned Constructor c = (Constructor) sym;
284 120 : this_parameter = c.this_parameter;
285 120 : may_access_instance_members = (c.binding == MemberBinding.INSTANCE);
286 120 : may_access_klass_members = true;
287 120 : method_found = true;
288 2741724 : } else if (sym is Destructor) {
289 26 : unowned Destructor d = (Destructor) sym;
290 26 : this_parameter = d.this_parameter;
291 26 : may_access_instance_members = (d.binding == MemberBinding.INSTANCE);
292 26 : may_access_klass_members = true;
293 26 : method_found = true;
294 2741698 : } else if (sym is Method) {
295 814435 : unowned Method m = (Method) sym;
296 814435 : this_parameter = m.this_parameter;
297 814435 : may_access_instance_members = (m.binding == MemberBinding.INSTANCE);
298 814435 : may_access_klass_members = (m.binding != MemberBinding.STATIC);
299 814435 : method_found = true;
300 : }
301 : }
302 :
303 3466395 : symbol_reference = SemanticAnalyzer.symbol_lookup_inherited (sym, member_name);
304 :
305 3466463 : if (!is_with_variable_access && symbol_reference == null && sym is WithStatement) {
306 68 : unowned WithStatement w = (WithStatement) sym;
307 :
308 68 : var variable_type = w.with_variable.variable_type;
309 68 : if (variable_type is PointerType) {
310 2 : variable_type = ((PointerType) variable_type).base_type;
311 : }
312 68 : visited_types.add (variable_type);
313 :
314 68 : symbol_reference = variable_type.get_member (member_name);
315 68 : if (symbol_reference != null) {
316 35 : inner = new MemberAccess (null, w.with_variable.name, source_reference);
317 35 : ((MemberAccess) inner).is_with_variable_access = true;
318 35 : inner.check (context);
319 35 : may_access_instance_members = true;
320 : }
321 : }
322 :
323 3466395 : if (symbol_reference == null && sym is TypeSymbol && may_access_instance_members) {
324 : // used for generated to_string methods in enums
325 124609 : symbol_reference = this_parameter.variable_type.get_member (member_name);
326 :
327 124609 : if (symbol_reference != null && is_instance_symbol (symbol_reference)) {
328 : // implicit this
329 1 : inner = new MemberAccess (null, "this", source_reference);
330 1 : inner.value_type = this_parameter.variable_type.copy ();
331 1 : inner.value_type.value_owned = false;
332 1 : inner.symbol_reference = this_parameter;
333 :
334 1 : symbol_reference = inner.value_type.get_member (member_name);
335 : }
336 : }
337 :
338 3466395 : if (symbol_reference == null) {
339 2192930 : if (sym is TypeSymbol) {
340 : // do not allow instance access to outer classes
341 3466395 : this_parameter = null;
342 3466395 : may_access_instance_members = false;
343 3466395 : may_access_klass_members = false;
344 : }
345 : }
346 :
347 3466395 : sym = sym.parent_symbol;
348 : }
349 :
350 1280461 : if (symbol_reference == null && source_reference != null) {
351 27822 : foreach (UsingDirective ns in source_reference.using_directives) {
352 10414 : if (ns.error) {
353 : // ignore previous error
354 0 : continue;
355 : }
356 10414 : var local_sym = ns.namespace_symbol.scope.lookup (member_name);
357 10414 : if (local_sym != null) {
358 7549 : if (symbol_reference != null && symbol_reference != local_sym) {
359 1 : error = true;
360 1 : Report.error (source_reference, "`%s' is an ambiguous reference between `%s' and `%s'", member_name, symbol_reference.get_full_name (), local_sym.get_full_name ());
361 1 : return false;
362 : }
363 :
364 : // Transform to fully qualified member access
365 7548 : unowned Symbol? inner_sym = local_sym.parent_symbol;
366 7548 : unowned MemberAccess? inner_ma = this;
367 15362 : while (inner_sym != null && inner_sym.name != null) {
368 7814 : inner_ma.inner = new MemberAccess (null, inner_sym.name, source_reference);
369 7814 : inner_ma = (MemberAccess) inner_ma.inner;
370 7814 : inner_sym = inner_sym.parent_symbol;
371 : }
372 7548 : inner_ma.qualified = true;
373 7548 : inner.check (context);
374 :
375 7548 : symbol_reference = local_sym;
376 : }
377 : }
378 : }
379 : } else {
380 408090 : if (inner.error) {
381 : /* if there was an error in the inner expression, skip this check */
382 12 : error = true;
383 12 : return false;
384 : }
385 :
386 408078 : if (inner.value_type is PointerType) {
387 1431 : unowned PointerType? pointer_type = inner.value_type as PointerType;
388 1431 : if (pointer_type != null && pointer_type.base_type is ValueType) {
389 1429 : if (inner.formal_value_type is GenericType) {
390 1 : inner = new CastExpression (inner, pointer_type.copy (), source_reference);
391 : }
392 : // transform foo->bar to (*foo).bar
393 1429 : inner = new PointerIndirection (inner, source_reference);
394 1429 : inner.check (context);
395 1429 : pointer_member_access = false;
396 : }
397 : }
398 :
399 408078 : if (inner.value_type is SignalType && member_name == "emit") {
400 : // transform foo.sig.emit() to foo.sig()
401 5 : parent_node.replace_expression (this, inner);
402 5 : return true;
403 : }
404 :
405 408073 : if (inner is MemberAccess) {
406 370049 : unowned MemberAccess ma = (MemberAccess) inner;
407 370049 : if (ma.prototype_access) {
408 0 : error = true;
409 0 : Report.error (source_reference, "Access to instance member `%s' denied", inner.symbol_reference.get_full_name ());
410 0 : return false;
411 : }
412 : }
413 :
414 408073 : if (inner is CastExpression && ((CastExpression) inner).is_silent_cast) {
415 2 : Report.warning (source_reference, "Access to possible `null'. Perform a check or use an unsafe cast.");
416 : }
417 :
418 408073 : if (inner is MemberAccess || inner is BaseAccess) {
419 370177 : base_symbol = inner.symbol_reference;
420 :
421 370177 : if (symbol_reference == null && (base_symbol is Namespace || base_symbol is TypeSymbol)) {
422 264288 : symbol_reference = base_symbol.scope.lookup (member_name);
423 264288 : if (inner is BaseAccess) {
424 : // inner expression is base access
425 : // access to instance members of the base type possible
426 408073 : may_access_instance_members = true;
427 408073 : may_access_klass_members = true;
428 : }
429 : }
430 : }
431 :
432 408073 : if (inner is MemberAccess && inner.symbol_reference is TypeParameter) {
433 18 : inner.value_type = new GenericType ((TypeParameter) inner.symbol_reference, source_reference);
434 : }
435 :
436 408073 : if (symbol_reference == null && inner.value_type != null) {
437 143841 : if (pointer_member_access) {
438 2 : symbol_reference = inner.value_type.get_pointer_member (member_name);
439 : } else {
440 143839 : if (inner.value_type.type_symbol != null) {
441 126300 : base_symbol = inner.value_type.type_symbol;
442 : }
443 143839 : symbol_reference = inner.value_type.get_member (member_name);
444 : }
445 143841 : if (symbol_reference != null) {
446 : // inner expression is variable, field, or parameter
447 : // access to instance members of the corresponding type possible
448 143806 : may_access_instance_members = true;
449 143806 : may_access_klass_members = true;
450 : }
451 : }
452 :
453 408107 : if (symbol_reference == null && inner.value_type != null && inner.value_type.is_dynamic) {
454 : // allow late bound members for dynamic types
455 34 : var dynamic_object_type = (ObjectType) inner.value_type;
456 34 : if (parent_node is MethodCall) {
457 1 : unowned MethodCall invoc = (MethodCall) parent_node;
458 2 : if (invoc.call == this) {
459 : // dynamic method
460 : DataType ret_type;
461 1 : if (invoc.target_type != null) {
462 1 : ret_type = invoc.target_type.copy ();
463 1 : ret_type.value_owned = true;
464 0 : } else if (invoc.parent_node is ExpressionStatement) {
465 0 : ret_type = new VoidType ();
466 : } else {
467 : // expect dynamic object of the same type
468 0 : ret_type = inner.value_type.copy ();
469 : }
470 1 : var m = new DynamicMethod (inner.value_type, member_name, ret_type, source_reference);
471 1 : m.invocation = invoc;
472 1 : var err = new ErrorType (null, null, m.source_reference);
473 1 : err.dynamic_error = true;
474 1 : m.add_error_type (err);
475 1 : m.access = SymbolAccessibility.PUBLIC;
476 1 : m.add_parameter (new Parameter.with_ellipsis ());
477 1 : m.this_parameter = new Parameter ("this", dynamic_object_type.copy (), m.source_reference);
478 1 : dynamic_object_type.type_symbol.scope.add (null, m);
479 1 : symbol_reference = m;
480 : }
481 33 : } else if (parent_node is Assignment) {
482 5 : unowned Assignment a = (Assignment) parent_node;
483 9 : if (a.left == this) {
484 : // dynamic property assignment
485 4 : var prop = new DynamicProperty (inner.value_type, member_name, source_reference);
486 4 : prop.access = SymbolAccessibility.PUBLIC;
487 4 : prop.set_accessor = new PropertyAccessor (false, true, false, null, null, prop.source_reference);
488 4 : prop.owner = inner.value_type.type_symbol.scope;
489 4 : dynamic_object_type.type_symbol.scope.add (null, prop);
490 4 : symbol_reference = prop;
491 4 : if (!dynamic_object_type.type_symbol.is_subtype_of (context.analyzer.object_type)) {
492 1 : Report.error (source_reference, "dynamic properties are not supported for `%s'", dynamic_object_type.type_symbol.get_full_name ());
493 1 : error = true;
494 : }
495 : }
496 28 : } else if (parent_node is MemberAccess && inner is MemberAccess && parent_node.parent_node is MethodCall) {
497 12 : unowned MemberAccess ma = (MemberAccess) parent_node;
498 20 : if (ma.member_name == "connect" || ma.member_name == "connect_after") {
499 : // dynamic signal
500 8 : var s = new DynamicSignal (inner.value_type, member_name, new VoidType (), source_reference);
501 8 : var mcall = (MethodCall) parent_node.parent_node;
502 : // the first argument is the handler
503 8 : if (mcall.get_argument_list().size > 0) {
504 8 : s.handler = mcall.get_argument_list()[0];
505 8 : unowned MemberAccess? arg = s.handler as MemberAccess;
506 8 : if (arg == null || !arg.check (context) || !(arg.symbol_reference is Method)) {
507 2 : error = true;
508 2 : if (s.handler is LambdaExpression) {
509 1 : Report.error (s.handler.source_reference, "Lambdas are not allowed for dynamic signals");
510 : } else {
511 1 : Report.error (s.handler.source_reference, "Cannot infer call signature for dynamic signal `%s' from given expression", s.get_full_name ());
512 : }
513 : }
514 : }
515 8 : s.access = SymbolAccessibility.PUBLIC;
516 8 : dynamic_object_type.type_symbol.scope.add (null, s);
517 8 : symbol_reference = s;
518 7 : } else if (ma.member_name == "emit") {
519 : // dynamic signal
520 3 : unowned MethodCall mcall = (MethodCall) ma.parent_node;
521 5 : var return_type = mcall.target_type ?? new VoidType ();
522 3 : if (return_type is VarType) {
523 1 : error = true;
524 1 : Report.error (mcall.source_reference, "Cannot infer return type for dynamic signal `%s' from given context", member_name);
525 : }
526 3 : var s = new DynamicSignal (inner.value_type, member_name, return_type, source_reference);
527 3 : s.access = SymbolAccessibility.PUBLIC;
528 3 : s.add_parameter (new Parameter.with_ellipsis ());
529 3 : dynamic_object_type.type_symbol.scope.add (null, s);
530 3 : symbol_reference = s;
531 1 : } else if (ma.member_name == "disconnect") {
532 1 : error = true;
533 1 : Report.error (ma.source_reference, "Use SignalHandler.disconnect() to disconnect from dynamic signal");
534 : }
535 : }
536 52 : if (symbol_reference == null) {
537 : // dynamic property read access
538 18 : var prop = new DynamicProperty (inner.value_type, member_name, source_reference);
539 18 : if (target_type != null) {
540 16 : prop.property_type = target_type;
541 : } else {
542 : // expect dynamic object of the same type
543 2 : prop.property_type = inner.value_type.copy ();
544 : }
545 18 : prop.access = SymbolAccessibility.PUBLIC;
546 18 : prop.get_accessor = new PropertyAccessor (true, false, false, prop.property_type.copy (), null, prop.source_reference);
547 18 : prop.owner = inner.value_type.type_symbol.scope;
548 18 : dynamic_object_type.type_symbol.scope.add (null, prop);
549 18 : symbol_reference = prop;
550 18 : if (!dynamic_object_type.type_symbol.is_subtype_of (context.analyzer.object_type)) {
551 1 : Report.error (source_reference, "dynamic properties are not supported for %s", dynamic_object_type.type_symbol.get_full_name ());
552 1 : error = true;
553 : }
554 : }
555 34 : if (symbol_reference != null) {
556 34 : may_access_instance_members = true;
557 34 : may_access_klass_members = true;
558 : }
559 : }
560 :
561 408073 : if (symbol_reference is ArrayResizeMethod) {
562 35 : if (inner.symbol_reference is Variable) {
563 : // require the real type with its original value_owned attritubte
564 17 : var inner_type = context.analyzer.get_value_type_for_symbol (inner.symbol_reference, true) as ArrayType;
565 17 : if (inner_type != null && inner_type.inline_allocated) {
566 1 : Report.error (source_reference, "`resize' is not supported for arrays with fixed length");
567 1 : error = true;
568 16 : } else if (inner_type != null && !inner_type.value_owned) {
569 3 : Report.error (source_reference, "`resize' is not allowed for unowned array references");
570 3 : error = true;
571 : }
572 1 : } else if (inner.symbol_reference is Constant) {
573 : // disallow resize() for const array
574 1 : Report.error (source_reference, "`resize' is not allowed for constant arrays");
575 1 : error = true;
576 : }
577 : }
578 : }
579 :
580 : // enum-type inference
581 1696088 : if (inner == null && symbol_reference == null && target_type != null && target_type.type_symbol is Enum) {
582 108 : unowned Enum enum_type = (Enum) target_type.type_symbol;
583 592 : foreach (var val in enum_type.get_values ()) {
584 350 : if (member_name == val.name) {
585 108 : symbol_reference = val;
586 108 : break;
587 : }
588 : }
589 : }
590 :
591 1696088 : if (symbol_reference == null) {
592 10 : error = true;
593 :
594 10 : string base_type_name = "(null)";
595 10 : unowned Symbol? base_type = null;
596 10 : if (inner != null && inner.value_type != null) {
597 1 : base_type_name = inner.value_type.to_string ();
598 1 : base_type = inner.value_type.type_symbol;
599 9 : } else if (base_symbol != null) {
600 9 : base_type_name = base_symbol.get_full_name ();
601 9 : base_type = base_symbol;
602 : }
603 :
604 10 : string? base_type_package = "";
605 10 : if (base_type != null && base_type.external_package) {
606 4 : base_type_package = base_symbol.source_reference.file.package_name;
607 2 : if (base_type_package != null) {
608 2 : base_type_package = " (%s)".printf (base_type_package);
609 : }
610 : }
611 :
612 10 : string visited_types_string = "";
613 12 : foreach (var type in visited_types) {
614 1 : visited_types_string += " or `%s'".printf (type.to_string ());
615 : }
616 :
617 10 : Report.error (source_reference, "The name `%s' does not exist in the context of `%s'%s%s", member_name, base_type_name, base_type_package, visited_types_string);
618 10 : if (inner != null && inner.symbol_reference != null && inner.symbol_reference.source_reference != null) {
619 3 : Report.notice (inner.symbol_reference.source_reference, "`%s' was declared here", inner.symbol_reference.name);
620 : }
621 10 : value_type = new InvalidType ();
622 10 : return false;
623 1696078 : } else if (symbol_reference.error) {
624 : //ignore previous error
625 6 : error = true;
626 6 : value_type = new InvalidType ();
627 6 : return false;
628 : }
629 :
630 1696072 : if (symbol_reference is Signal) {
631 217 : unowned Signal sig = (Signal) symbol_reference;
632 217 : unowned CodeNode? ma = this;
633 315 : while (ma.parent_node is MemberAccess) {
634 98 : ma = ma.parent_node;
635 : }
636 217 : unowned CodeNode? parent = ma.parent_node;
637 217 : if (parent != null && !(parent is ElementAccess) && !(((MemberAccess) ma).inner is BaseAccess)
638 197 : && (!(parent is MethodCall) || ((MethodCall) parent).get_argument_list ().contains (this))) {
639 13 : if (sig.has_attribute ("HasEmitter")) {
640 8 : if (!sig.check (context)) {
641 0 : return false;
642 : }
643 8 : symbol_reference = sig.emitter;
644 : } else {
645 5 : error = true;
646 5 : Report.error (source_reference, "Signal `%s' requires emitter in this context", symbol_reference.get_full_name ());
647 5 : return false;
648 : }
649 : }
650 : }
651 :
652 1696067 : unowned Symbol? member = symbol_reference;
653 1696067 : var access = SymbolAccessibility.PUBLIC;
654 1696067 : bool instance = false;
655 1696067 : bool klass = false;
656 1696067 : bool generics = false;
657 :
658 1696067 : if (!member.check (context)) {
659 0 : return false;
660 : }
661 :
662 1696067 : if (member is LocalVariable) {
663 441835 : unowned LocalVariable local = (LocalVariable) member;
664 441835 : unowned Block? block = local.parent_symbol as Block;
665 441822 : if (block != null && SemanticAnalyzer.find_parent_method_or_property_accessor (block) != context.analyzer.current_method_or_property_accessor) {
666 : // mark all methods between current method and the captured
667 : // block as closures (to support nested closures)
668 88 : unowned Symbol? sym = context.analyzer.current_method_or_property_accessor;
669 196 : while (sym != block) {
670 108 : unowned Method? method = sym as Method;
671 91 : if (method != null) {
672 91 : method.closure = true;
673 : // consider captured variables as used
674 : // as we require captured variables to be initialized
675 91 : method.add_captured_variable (local);
676 : }
677 108 : sym = sym.parent_symbol;
678 : }
679 :
680 88 : local.captured = true;
681 88 : block.captured = true;
682 :
683 88 : if (local.variable_type.type_symbol == context.analyzer.va_list_type.type_symbol) {
684 1 : error = true;
685 1 : Report.error (source_reference, "Capturing `va_list' variable `%s' is not allowed", local.get_full_name ());
686 : }
687 : }
688 1254232 : } else if (member is Parameter) {
689 485819 : unowned Parameter param = (Parameter) member;
690 485819 : unowned Method? m = param.parent_symbol as Method;
691 956936 : if (m != null && m != context.analyzer.current_method_or_property_accessor && param != m.this_parameter) {
692 : // mark all methods between current method and the captured
693 : // parameter as closures (to support nested closures)
694 5695 : unowned Symbol? sym = context.analyzer.current_method_or_property_accessor;
695 17086 : while (sym != m) {
696 11391 : unowned Method? method = sym as Method;
697 5695 : if (method != null) {
698 5695 : method.closure = true;
699 : }
700 11391 : sym = sym.parent_symbol;
701 : }
702 :
703 5695 : param.captured = true;
704 5695 : m.body.captured = true;
705 :
706 5695 : if (param.direction != ParameterDirection.IN) {
707 1 : error = true;
708 1 : Report.error (source_reference, "Cannot capture reference or output parameter `%s'", param.get_full_name ());
709 : }
710 5695 : if (param.variable_type.type_symbol == context.analyzer.va_list_type.type_symbol) {
711 1 : error = true;
712 1 : Report.error (source_reference, "Capturing `va_list' parameter `%s' is not allowed", param.get_full_name ());
713 : }
714 : } else {
715 480124 : unowned PropertyAccessor? acc = param.parent_symbol.parent_symbol as PropertyAccessor;
716 503 : if (acc != null && acc != context.analyzer.current_method_or_property_accessor && param != acc.prop.this_parameter) {
717 : // mark all methods between current method and the captured
718 : // parameter as closures (to support nested closures)
719 1 : unowned Symbol? sym = context.analyzer.current_method_or_property_accessor;
720 7 : while (sym != m) {
721 6 : unowned Method? method = sym as Method;
722 1 : if (method != null) {
723 1 : method.closure = true;
724 : }
725 6 : sym = sym.parent_symbol;
726 : }
727 :
728 1 : param.captured = true;
729 1 : acc.body.captured = true;
730 : }
731 : }
732 768413 : } else if (member is Field) {
733 119506 : unowned Field f = (Field) member;
734 119506 : access = f.access;
735 119506 : instance = (f.binding == MemberBinding.INSTANCE);
736 119506 : klass = (f.binding == MemberBinding.CLASS);
737 :
738 : // do not allow access to fields of generic types
739 : // if instance type does not specify type arguments
740 119506 : if (f.variable_type is GenericType) {
741 15601 : generics = true;
742 : }
743 648907 : } else if (member is Constant) {
744 143979 : unowned Constant c = (Constant) member;
745 143979 : access = c.access;
746 :
747 143979 : unowned Block? block = c.parent_symbol as Block;
748 34 : if (block != null && SemanticAnalyzer.find_parent_method_or_property_accessor (block) != context.analyzer.current_method_or_property_accessor) {
749 1 : error = true;
750 1 : Report.error (source_reference, "internal error: accessing local constants of outer methods is not supported yet");
751 1 : return false;
752 : }
753 504928 : } else if (member is Method) {
754 184147 : unowned Method m = (Method) member;
755 184147 : if (m.is_async_callback) {
756 : // ensure to use right callback method for virtual/abstract async methods
757 : // and also for lambda expressions within async methods
758 20 : unowned Method? async_method = context.analyzer.current_async_method;
759 :
760 20 : bool is_valid_access = false;
761 20 : if (async_method != null) {
762 20 : if (m == async_method.get_callback_method ()) {
763 : is_valid_access = true;
764 3 : } else if (async_method.base_method != null && m == async_method.base_method.get_callback_method ()) {
765 : is_valid_access = true;
766 2 : } else if (async_method.base_interface_method != null && m == async_method.base_interface_method.get_callback_method ()) {
767 : is_valid_access = true;
768 : }
769 : }
770 : if (!is_valid_access) {
771 1 : error = true;
772 1 : Report.error (source_reference, "Access to async callback `%s' not allowed in this context", m.get_full_name ());
773 1 : return false;
774 : }
775 :
776 19 : if (async_method != context.analyzer.current_method) {
777 2 : unowned Symbol? sym = context.analyzer.current_method;
778 6 : while (sym != async_method) {
779 4 : unowned Method? method = sym as Method;
780 2 : if (method != null) {
781 2 : method.closure = true;
782 : }
783 4 : sym = sym.parent_symbol;
784 : }
785 2 : async_method.body.captured = true;
786 : }
787 :
788 19 : m = async_method.get_callback_method ();
789 19 : symbol_reference = m;
790 19 : member = symbol_reference;
791 184127 : } else if (m.base_method != null) {
792 : // refer to base method to inherit default arguments
793 3246 : m = m.base_method;
794 :
795 3246 : if (m.signal_reference != null) {
796 : // method is class/default handler for a signal
797 : // let signal deal with member access
798 1 : symbol_reference = m.signal_reference;
799 : } else {
800 3245 : symbol_reference = m;
801 : }
802 :
803 3246 : member = symbol_reference;
804 180881 : } else if (m.base_interface_method != null) {
805 : // refer to base method to inherit default arguments
806 385 : m = m.base_interface_method;
807 :
808 385 : if (m.signal_reference != null) {
809 : // method is class/default handler for a signal
810 : // let signal deal with member access
811 1 : symbol_reference = m.signal_reference;
812 : } else {
813 384 : symbol_reference = m;
814 : }
815 :
816 385 : member = symbol_reference;
817 : }
818 184146 : access = m.access;
819 184146 : if (!(m is CreationMethod)) {
820 176748 : instance = (m.binding == MemberBinding.INSTANCE);
821 : }
822 184146 : klass = (m.binding == MemberBinding.CLASS);
823 :
824 : // do not allow access to methods using generic type parameters
825 : // if instance type does not specify type arguments
826 730758 : foreach (var param in m.get_parameters ()) {
827 281465 : unowned GenericType? generic_type = param.variable_type as GenericType;
828 281465 : if (generic_type != null && generic_type.type_parameter.parent_symbol is TypeSymbol) {
829 8159 : generics = true;
830 8159 : break;
831 : }
832 : }
833 184146 : unowned GenericType? generic_type = m.return_type as GenericType;
834 2321 : if (generic_type != null && generic_type.type_parameter.parent_symbol is TypeSymbol) {
835 : generics = true;
836 : }
837 320781 : } else if (member is Property) {
838 36360 : unowned Property prop = (Property) member;
839 36360 : if (!prop.check (context)) {
840 0 : error = true;
841 0 : return false;
842 : }
843 36360 : if (prop.base_property != null) {
844 : // refer to base property
845 127 : prop = prop.base_property;
846 127 : symbol_reference = prop;
847 127 : member = symbol_reference;
848 36233 : } else if (prop.base_interface_property != null) {
849 : // refer to base property
850 427 : prop = prop.base_interface_property;
851 427 : symbol_reference = prop;
852 427 : member = symbol_reference;
853 : }
854 36360 : access = prop.access;
855 36360 : if (lvalue) {
856 1537 : if (prop.set_accessor == null) {
857 1 : error = true;
858 1 : Report.error (source_reference, "Property `%s' is read-only", prop.get_full_name ());
859 1 : return false;
860 1536 : } else if (!prop.set_accessor.writable && prop.set_accessor.construction) {
861 6 : if (context.analyzer.find_current_method () is CreationMethod) {
862 2 : error = true;
863 2 : Report.error (source_reference, "Cannot assign to construct-only properties, use Object (property: value) constructor chain up");
864 2 : return false;
865 4 : } else if (context.analyzer.is_in_constructor ()) {
866 3 : if (!context.analyzer.current_type_symbol.is_subtype_of ((TypeSymbol) prop.parent_symbol)) {
867 1 : error = true;
868 1 : Report.error (source_reference, "Cannot assign to construct-only property `%s' in `construct' of `%s'", prop.get_full_name (), context.analyzer.current_type_symbol.get_full_name ());
869 1 : return false;
870 : }
871 : } else {
872 1 : error = true;
873 1 : Report.error (source_reference, "Cannot assign to construct-only property in this context");
874 1 : return false;
875 : }
876 : }
877 1532 : if (prop.access == SymbolAccessibility.PUBLIC) {
878 1526 : access = prop.set_accessor.access;
879 6 : } else if (prop.access == SymbolAccessibility.PROTECTED
880 0 : && prop.set_accessor.access != SymbolAccessibility.PUBLIC) {
881 0 : access = prop.set_accessor.access;
882 : }
883 : } else {
884 34823 : if (prop.get_accessor == null) {
885 1 : error = true;
886 1 : Report.error (source_reference, "Property `%s' is write-only", prop.get_full_name ());
887 1 : return false;
888 : }
889 34822 : if (prop.access == SymbolAccessibility.PUBLIC) {
890 34805 : access = prop.get_accessor.access;
891 17 : } else if (prop.access == SymbolAccessibility.PROTECTED
892 0 : && prop.get_accessor.access != SymbolAccessibility.PUBLIC) {
893 0 : access = prop.get_accessor.access;
894 : }
895 : }
896 36354 : instance = (prop.binding == MemberBinding.INSTANCE);
897 :
898 : // do not allow access to properties of generic types
899 : // if instance type does not specify type arguments
900 36354 : if (prop.property_type is GenericType) {
901 1696059 : generics = true;
902 : }
903 284421 : } else if (member is Signal) {
904 204 : instance = true;
905 204 : access = member.access;
906 284217 : } else if (member is ErrorCode) {
907 1505 : if (!(parent_node is CallableExpression && ((CallableExpression) parent_node).call == this)) {
908 12 : symbol_reference = ((ErrorCode) member).code;
909 12 : member = symbol_reference;
910 : }
911 : }
912 :
913 : // recursive usage of itself doesn't count as used
914 1696059 : unowned CodeNode? parent = this;
915 11221448 : while (parent != member) {
916 11221448 : parent = parent.parent_node;
917 11221448 : if (parent == null || parent == member) {
918 : break;
919 : }
920 : }
921 1696059 : if (parent != member) {
922 1695944 : member.used = true;
923 : }
924 1696059 : member.version.check (context, source_reference);
925 :
926 : // FIXME Code duplication with MemberInitializer.check()
927 1696059 : if (access == SymbolAccessibility.PROTECTED && member.parent_symbol is TypeSymbol) {
928 729 : unowned TypeSymbol target_type = (TypeSymbol) member.parent_symbol;
929 :
930 729 : bool in_subtype = false;
931 8941 : for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) {
932 2980 : if (this_symbol == target_type) {
933 : // required for interfaces with non-abstract methods
934 : // accessing protected interface members
935 : in_subtype = true;
936 : break;
937 : }
938 :
939 2395 : unowned Class? cl = this_symbol as Class;
940 2395 : if (cl != null && cl.is_subtype_of (target_type)) {
941 : in_subtype = true;
942 : break;
943 : }
944 : }
945 :
946 729 : if (!in_subtype) {
947 1 : error = true;
948 1 : Report.error (source_reference, "Access to protected member `%s' denied", member.get_full_name ());
949 1 : return false;
950 : }
951 1695330 : } else if (access == SymbolAccessibility.PRIVATE) {
952 63518 : unowned Symbol? target_type = member.parent_symbol;
953 :
954 63518 : bool in_target_type = false;
955 687913 : for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) {
956 229304 : if (target_type == this_symbol) {
957 : in_target_type = true;
958 : break;
959 : }
960 : }
961 :
962 63518 : if (!in_target_type) {
963 1 : error = true;
964 1 : Report.error (source_reference, "Access to private member `%s' denied", member.get_full_name ());
965 1 : return false;
966 : }
967 : }
968 :
969 1696057 : if (generics && inner != null) {
970 24476 : unowned DataType instance_type = inner.value_type;
971 24476 : unowned PointerType? pointer_type = inner.value_type as PointerType;
972 0 : if (pointer_type != null) {
973 0 : instance_type = pointer_type.base_type;
974 : }
975 :
976 : // instance type might be a subtype of the parent symbol of the member
977 : // that subtype might not be generic, so do not report an error in that case
978 24476 : unowned ObjectType? object_type = instance_type as ObjectType;
979 23059 : if (object_type != null && object_type.object_type_symbol.has_type_parameters ()
980 23045 : && !instance_type.has_type_arguments ()) {
981 0 : error = true;
982 0 : Report.error (inner.source_reference, "missing generic type arguments");
983 0 : return false;
984 : }
985 : }
986 :
987 1696057 : if ((instance && !may_access_instance_members) ||
988 1696011 : (klass && !may_access_klass_members)) {
989 46 : prototype_access = true;
990 :
991 46 : if (symbol_reference is Method) {
992 : // also set static type for prototype access
993 : // required when using instance methods as delegates in constants
994 : // TODO replace by MethodPrototype
995 39 : value_type = context.analyzer.get_value_type_for_symbol (symbol_reference, lvalue);
996 39 : value_type.source_reference = source_reference;
997 7 : } else if (symbol_reference is Field) {
998 4 : value_type = new FieldPrototype ((Field) symbol_reference, source_reference);
999 3 : } else if (symbol_reference is Property) {
1000 3 : value_type = new PropertyPrototype ((Property) symbol_reference, source_reference);
1001 : } else {
1002 0 : error = true;
1003 0 : value_type = new InvalidType ();
1004 : }
1005 :
1006 46 : if (target_type != null) {
1007 8 : value_type.value_owned = target_type.value_owned;
1008 : }
1009 : } else {
1010 : // implicit this access
1011 1696011 : if (instance && inner == null) {
1012 51817 : inner = new MemberAccess (null, "this", source_reference);
1013 51817 : inner.value_type = this_parameter.variable_type.copy ();
1014 51817 : inner.value_type.value_owned = false;
1015 51817 : inner.symbol_reference = this_parameter;
1016 : } else {
1017 1644194 : check_lvalue_access ();
1018 : }
1019 :
1020 1696011 : if (!instance && !klass && !(symbol_reference is CreationMethod) && may_access_instance_members && inner != null) {
1021 47 : if (inner.symbol_reference is Method) {
1022 : // do not warn when calling .begin or .end on static async method
1023 : } else {
1024 5 : Report.warning (source_reference, "Access to static member `%s' with an instance reference", symbol_reference.get_full_name ());
1025 :
1026 : // Transform to static member access
1027 5 : unowned Symbol? inner_sym = symbol_reference.parent_symbol;
1028 5 : unowned MemberAccess? inner_ma = this;
1029 11 : while (inner_sym != null && inner_sym.name != null) {
1030 6 : inner_ma.inner = new MemberAccess (null, inner_sym.name, source_reference);
1031 6 : inner_ma = (MemberAccess) inner_ma.inner;
1032 6 : inner_sym = inner_sym.parent_symbol;
1033 : }
1034 5 : inner_ma.qualified = true;
1035 5 : inner.check (context);
1036 : }
1037 : }
1038 :
1039 1696011 : if (context.experimental_non_null && instance && inner.value_type.nullable &&
1040 93 : !(inner.value_type is PointerType) && !(inner.value_type is GenericType) &&
1041 93 : !(inner.value_type is ArrayType)) {
1042 2 : Report.error (source_reference, "Access to instance member `%s' from nullable reference denied", symbol_reference.get_full_name ());
1043 : }
1044 :
1045 1696011 : unowned Method? m = symbol_reference as Method;
1046 1696011 : unowned MemberAccess? inner_ma = inner as MemberAccess;
1047 1696011 : if (m != null && m.binding == MemberBinding.STATIC && m.parent_symbol is ObjectTypeSymbol &&
1048 26291 : inner != null && inner.value_type == null && inner_ma.type_argument_list.size > 0) {
1049 : // support static methods in generic classes
1050 1 : inner.value_type = new ObjectType ((ObjectTypeSymbol) m.parent_symbol, source_reference);
1051 :
1052 3 : foreach (var type_argument in inner_ma.type_argument_list) {
1053 1 : inner.value_type.add_type_argument (type_argument);
1054 : }
1055 : }
1056 :
1057 1696011 : formal_value_type = context.analyzer.get_value_type_for_symbol (symbol_reference, lvalue);
1058 1696011 : if (inner != null && formal_value_type != null) {
1059 361769 : value_type = formal_value_type.get_actual_type (inner.value_type, null, this);
1060 : } else {
1061 1334242 : value_type = formal_value_type;
1062 : }
1063 :
1064 1696011 : if (symbol_reference is Method) {
1065 184105 : unowned Method method = (Method) symbol_reference;
1066 184105 : if (target_type != null) {
1067 1606 : value_type.value_owned = target_type.value_owned;
1068 : }
1069 184105 : if (instance && method.parent_symbol is TypeSymbol) {
1070 79464 : inner.target_type = SemanticAnalyzer.get_data_type_for_symbol (method.parent_symbol);
1071 79464 : inner.target_type.value_owned = method.this_parameter.variable_type.value_owned;
1072 : }
1073 1511906 : } else if (symbol_reference is Property
1074 36351 : && instance && symbol_reference.parent_symbol != null) {
1075 36343 : inner.target_type = SemanticAnalyzer.get_data_type_for_symbol (symbol_reference.parent_symbol);
1076 1536523 : } else if ((symbol_reference is Field || symbol_reference is Signal)
1077 119706 : && instance && symbol_reference.parent_symbol != null) {
1078 60960 : var parent_type = SemanticAnalyzer.get_data_type_for_symbol (symbol_reference.parent_symbol);
1079 60960 : inner.target_type = parent_type.get_actual_type (inner.value_type, null, this);
1080 : }
1081 :
1082 1696011 : if (inner == null && value_type != null && context.profile == Profile.GOBJECT) {
1083 1049156 : check_narrowed_value_type ();
1084 : }
1085 : }
1086 :
1087 1696057 : if (value_type != null) {
1088 1411848 : value_type.check (context);
1089 : }
1090 :
1091 1696057 : if (symbol_reference is ArrayLengthField) {
1092 17320 : if (inner.value_type is ArrayType && ((ArrayType) inner.value_type).rank > 1 && !(parent_node is ElementAccess)) {
1093 1 : Report.error (source_reference, "unsupported use of length field of multi-dimensional array");
1094 1 : error = true;
1095 : }
1096 1678737 : } else if (symbol_reference is DelegateTargetField) {
1097 15 : if (!((DelegateType) inner.value_type).delegate_symbol.has_target) {
1098 1 : Report.error (source_reference, "unsupported use of target field of delegate without target");
1099 1 : error = true;
1100 : }
1101 1678722 : } else if (symbol_reference is DelegateDestroyField) {
1102 6 : if (!((DelegateType) inner.value_type).delegate_symbol.has_target) {
1103 1 : Report.error (source_reference, "unsupported use of destroy field of delegate without target");
1104 1 : error = true;
1105 : }
1106 : }
1107 :
1108 : // Provide some extra information for the code generator
1109 1696057 : if (!tainted_access) {
1110 1696057 : tainted_access = is_tainted ();
1111 : }
1112 :
1113 1696057 : return !error;
1114 : }
1115 :
1116 1 : static bool is_instance_symbol (Symbol symbol) {
1117 1 : if (symbol is Field && ((Field) symbol).binding == MemberBinding.INSTANCE) {
1118 : return true;
1119 1 : } else if (symbol is Method && !(symbol is CreationMethod) && ((Method) symbol).binding == MemberBinding.INSTANCE) {
1120 : return true;
1121 0 : } else if (symbol is Property && ((Property) symbol).binding == MemberBinding.INSTANCE) {
1122 : return true;
1123 0 : } else if (symbol is Signal) {
1124 : return true;
1125 : } else {
1126 : return false;
1127 : }
1128 : }
1129 :
1130 1651445 : public void check_lvalue_access () {
1131 1651445 : if (inner == null) {
1132 : return;
1133 : }
1134 424074 : var instance = symbol_reference is Field && ((Field) symbol_reference).binding == MemberBinding.INSTANCE;
1135 58909 : if (!instance) {
1136 365165 : instance = symbol_reference is Method && ((Method) symbol_reference).binding == MemberBinding.INSTANCE;
1137 : }
1138 108967 : if (!instance) {
1139 299032 : instance = symbol_reference is Property && ((Property) symbol_reference).binding == MemberBinding.INSTANCE;
1140 : }
1141 :
1142 414940 : var this_access = inner.symbol_reference is Parameter && inner.symbol_reference.name == "this";
1143 414940 : var struct_or_array = (inner.value_type is StructValueType && !inner.value_type.nullable) || inner.value_type is ArrayType;
1144 :
1145 414940 : unowned MemberAccess? ma = inner as MemberAccess;
1146 38024 : if (ma == null && struct_or_array && inner is PointerIndirection) {
1147 : // (*struct)->method()
1148 1428 : ma = ((PointerIndirection) inner).inner as MemberAccess;
1149 : }
1150 :
1151 414940 : if (instance && struct_or_array && (symbol_reference is Method || lvalue) && ((ma != null && ma.symbol_reference is Variable) || inner is ElementAccess) && !this_access) {
1152 7227 : inner.lvalue = true;
1153 7227 : if (ma != null) {
1154 7221 : ma.lvalue = true;
1155 7221 : ma.check_lvalue_access ();
1156 : }
1157 : }
1158 :
1159 414940 : if (symbol_reference is DelegateTargetField || symbol_reference is DelegateDestroyField) {
1160 21 : inner.lvalue = true;
1161 21 : if (ma != null) {
1162 21 : ma.lvalue = true;
1163 21 : ma.check_lvalue_access ();
1164 : }
1165 : }
1166 :
1167 414940 : if (symbol_reference is Method && ((Method) symbol_reference).has_attribute ("DestroysInstance")) {
1168 9 : unowned Class? cl = ((Method) symbol_reference).parent_symbol as Class;
1169 9 : if (cl != null && cl.is_compact && ma != null) {
1170 7 : ma.lvalue = true;
1171 7 : ma.check_lvalue_access ();
1172 : }
1173 : }
1174 : }
1175 :
1176 130852 : public override void emit (CodeGenerator codegen) {
1177 130852 : if (inner != null) {
1178 53437 : inner.emit (codegen);
1179 : }
1180 :
1181 130852 : codegen.visit_member_access (this);
1182 :
1183 130852 : codegen.visit_expression (this);
1184 : }
1185 :
1186 3043971 : public override void get_defined_variables (Collection<Variable> collection) {
1187 3043971 : if (inner != null) {
1188 591165 : inner.get_defined_variables (collection);
1189 : }
1190 : }
1191 :
1192 864004 : public override void get_used_variables (Collection<Variable> collection) {
1193 864004 : if (inner != null) {
1194 191810 : inner.get_used_variables (collection);
1195 : }
1196 864004 : unowned LocalVariable? local = symbol_reference as LocalVariable;
1197 864004 : unowned Parameter? param = symbol_reference as Parameter;
1198 864004 : if (local != null) {
1199 210898 : collection.add (local);
1200 653106 : } else if (param != null && param.direction == ParameterDirection.OUT) {
1201 22264 : collection.add (param);
1202 : }
1203 : }
1204 :
1205 5955754 : bool is_tainted () {
1206 1696057 : unowned CodeNode node = this;
1207 1696057 : if (node.parent_node is ElementAccess || node.parent_node is MemberAccess) {
1208 414237 : return false;
1209 : }
1210 :
1211 1993659 : while (node.parent_node is Expression) {
1212 1560647 : node = node.parent_node;
1213 1560647 : if (node is Assignment || node is MethodCall || node is ObjectCreationExpression) {
1214 : break;
1215 : }
1216 : }
1217 :
1218 1281820 : bool found = false;
1219 8079645 : var traverse = new TraverseVisitor ((n) => {
1220 6797825 : if (n is PostfixExpression) {
1221 6224 : found = true;
1222 6224 : return TraverseStatus.STOP;
1223 6791601 : } else if (n is UnaryExpression) {
1224 105486 : unowned UnaryExpression e = (UnaryExpression) n;
1225 105486 : if (e.operator == UnaryOperator.INCREMENT || e.operator == UnaryOperator.DECREMENT) {
1226 987 : found = true;
1227 987 : return TraverseStatus.STOP;
1228 : }
1229 : }
1230 6797825 : return TraverseStatus.CONTINUE;
1231 : });
1232 1281820 : node.accept (traverse);
1233 :
1234 1281820 : return found;
1235 : }
1236 :
1237 1147151 : void check_narrowed_value_type () {
1238 1049156 : unowned Variable? variable = symbol_reference as Variable;
1239 2008348 : if (variable == null) {
1240 : return;
1241 : }
1242 :
1243 959192 : if (!(parent_node is MemberAccess)) {
1244 : return;
1245 : }
1246 :
1247 97995 : bool is_negation = false;
1248 97995 : unowned CodeNode? parent = parent_node;
1249 97995 : unowned IfStatement? if_statement = null;
1250 97995 : var scope_type_checks = new ArrayList<unowned TypeCheck> ();
1251 437597 : while (parent != null && !(parent is Method)) {
1252 427645 : if (parent is TypeCheck) {
1253 97995 : parent = null;
1254 : break;
1255 : }
1256 427189 : if (parent.parent_node is IfStatement) {
1257 35096 : if_statement = (IfStatement) parent.parent_node;
1258 35096 : is_negation = if_statement.false_statement == parent;
1259 35096 : break;
1260 : }
1261 392093 : if (parent.parent_node is Method) {
1262 52501 : foreach (Expression expr in ((Method) parent.parent_node).get_preconditions ()) {
1263 5 : if (expr is TypeCheck) {
1264 2 : scope_type_checks.add ((TypeCheck) expr);
1265 : }
1266 : }
1267 : break;
1268 : }
1269 339602 : parent = parent.parent_node;
1270 : }
1271 :
1272 97995 : if (if_statement != null) {
1273 35096 : unowned Expression expr = if_statement.condition;
1274 35096 : if (expr is UnaryExpression && ((UnaryExpression) expr).operator == UnaryOperator.LOGICAL_NEGATION) {
1275 2390 : expr = ((UnaryExpression) expr).inner;
1276 2390 : is_negation = !is_negation;
1277 : }
1278 35096 : unowned TypeCheck? type_check = expr as TypeCheck;
1279 35096 : if (!is_negation && type_check != null) {
1280 641 : unowned TypeSymbol? narrowed_symnol = type_check.type_reference.type_symbol;
1281 641 : if (variable == type_check.expression.symbol_reference) {
1282 50 : if (narrowed_symnol != value_type.type_symbol) {
1283 48 : value_type.context_symbol = narrowed_symnol;
1284 : }
1285 50 : value_type.nullable = false;
1286 : }
1287 : }
1288 : }
1289 97995 : if (value_type.context_symbol == null) {
1290 97951 : foreach (TypeCheck type_check in scope_type_checks) {
1291 2 : unowned TypeSymbol? narrowed_symnol = type_check.type_reference.type_symbol;
1292 2 : if (variable == type_check.expression.symbol_reference) {
1293 2 : if (narrowed_symnol != value_type.type_symbol) {
1294 2 : value_type.context_symbol = narrowed_symnol;
1295 : }
1296 2 : value_type.nullable = false;
1297 : }
1298 : }
1299 : }
1300 : }
1301 : }
|