~ubuntu-branches/ubuntu/raring/vala-0.20/raring-proposed

« back to all changes in this revision

Viewing changes to vala/valamemberaccess.vala

  • Committer: Package Import Robot
  • Author(s): Sebastien Bacher
  • Date: 2013-04-05 13:45:05 UTC
  • Revision ID: package-import@ubuntu.com-20130405134505-yyk3rec9904i7p8o
Tags: upstream-0.20.1
ImportĀ upstreamĀ versionĀ 0.20.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
public class Vala.MemberAccess : Expression {
 
29
        /**
 
30
         * The parent of the member.
 
31
         */
 
32
        public Expression? inner {
 
33
                get {
 
34
                        return _inner;
 
35
                }
 
36
                set {
 
37
                        _inner = value;
 
38
                        if (_inner != null) {
 
39
                                _inner.parent_node = this;
 
40
                        }
 
41
                }
 
42
        }
 
43
        
 
44
        /**
 
45
         * The name of the member.
 
46
         */
 
47
        public string member_name { get; set; }
 
48
 
 
49
        /**
 
50
         * Pointer member access.
 
51
         */
 
52
        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
        public bool prototype_access { get; set; }
 
59
 
 
60
        /**
 
61
         * Specifies whether the member is used for object creation.
 
62
         */
 
63
        public bool creation_member { get; set; }
 
64
 
 
65
        /**
 
66
         * Qualified access to global symbol.
 
67
         */
 
68
        public bool qualified { get; set; }
 
69
 
 
70
        private Expression? _inner;
 
71
        private List<DataType> type_argument_list = new ArrayList<DataType> ();
 
72
        
 
73
        /**
 
74
         * Creates a new member access expression.
 
75
         *
 
76
         * @param inner            parent of the member
 
77
         * @param member_name      member name
 
78
         * @param source_reference reference to source code
 
79
         * @return                 newly created member access expression
 
80
         */
 
81
        public MemberAccess (Expression? inner, string member_name, SourceReference? source_reference = null) {
 
82
                this.inner = inner;
 
83
                this.member_name = member_name;
 
84
                this.source_reference = source_reference;
 
85
        }
 
86
 
 
87
        public MemberAccess.simple (string member_name, SourceReference? source_reference = null) {
 
88
                this.member_name = member_name;
 
89
                this.source_reference = source_reference;
 
90
        }
 
91
 
 
92
        public MemberAccess.pointer (Expression inner, string member_name, SourceReference? source_reference = null) {
 
93
                this.inner = inner;
 
94
                this.member_name = member_name;
 
95
                this.source_reference = source_reference;
 
96
                pointer_member_access = true;
 
97
        }
 
98
 
 
99
        /**
 
100
         * Appends the specified type as generic type argument.
 
101
         *
 
102
         * @param arg a type reference
 
103
         */
 
104
        public void add_type_argument (DataType arg) {
 
105
                type_argument_list.add (arg);
 
106
                arg.parent_node = this;
 
107
        }
 
108
        
 
109
        /**
 
110
         * Returns a copy of the list of generic type arguments.
 
111
         *
 
112
         * @return type argument list
 
113
         */
 
114
        public List<DataType> get_type_arguments () {
 
115
                return type_argument_list;
 
116
        }
 
117
 
 
118
        public override void accept (CodeVisitor visitor) {
 
119
                visitor.visit_member_access (this);
 
120
 
 
121
                visitor.visit_expression (this);
 
122
        }
 
123
 
 
124
        public override void accept_children (CodeVisitor visitor) {
 
125
                if (inner != null) {
 
126
                        inner.accept (visitor);
 
127
                }
 
128
                
 
129
                foreach (DataType type_arg in type_argument_list) {
 
130
                        type_arg.accept (visitor);
 
131
                }
 
132
        }
 
133
 
 
134
        public override string to_string () {
 
135
                if (symbol_reference == null || symbol_reference.is_instance_member ()) {
 
136
                        if (inner == null) {
 
137
                                return member_name;
 
138
                        } else {
 
139
                                return "%s.%s".printf (inner.to_string (), member_name);
 
140
                        }
 
141
                } else {
 
142
                        // ensure to always use fully-qualified name
 
143
                        // to refer to static members
 
144
                        return symbol_reference.get_full_name ();
 
145
                }
 
146
        }
 
147
 
 
148
        public override void replace_expression (Expression old_node, Expression new_node) {
 
149
                if (inner == old_node) {
 
150
                        inner = new_node;
 
151
                }
 
152
        }
 
153
 
 
154
        public override bool is_pure () {
 
155
                // accessing property could have side-effects
 
156
                return (inner == null || inner.is_pure ()) && !(symbol_reference is Property);
 
157
        }
 
158
 
 
159
        public override void replace_type (DataType old_type, DataType new_type) {
 
160
                for (int i = 0; i < type_argument_list.size; i++) {
 
161
                        if (type_argument_list[i] == old_type) {
 
162
                                type_argument_list[i] = new_type;
 
163
                                return;
 
164
                        }
 
165
                }
 
166
        }
 
167
 
 
168
        public override bool is_constant () {
 
169
                var method = symbol_reference as Method;
 
170
                if (symbol_reference is Constant) {
 
171
                        return true;
 
172
                } else if (symbol_reference is ArrayLengthField && inner != null && inner.symbol_reference is Constant) {
 
173
                        // length of constant array
 
174
                        return true;
 
175
                } else if (method != null &&
 
176
                           (method.binding == MemberBinding.STATIC || prototype_access)) {
 
177
                        return true;
 
178
                } else {
 
179
                        return false;
 
180
                }
 
181
        }
 
182
 
 
183
        public override bool is_non_null () {
 
184
                var c = symbol_reference as Constant;
 
185
                if (c != null) {
 
186
                        return !c.type_reference.nullable;
 
187
                } else {
 
188
                        return false;
 
189
                }
 
190
        }
 
191
 
 
192
        public override bool check (CodeContext context) {
 
193
                if (checked) {
 
194
                        return !error;
 
195
                }
 
196
 
 
197
                checked = true;
 
198
 
 
199
                if (inner != null) {
 
200
                        inner.check (context);
 
201
                }
 
202
                
 
203
                foreach (DataType type_arg in type_argument_list) {
 
204
                        type_arg.check (context);
 
205
                }
 
206
 
 
207
                Symbol base_symbol = null;
 
208
                Parameter this_parameter = null;
 
209
                bool may_access_instance_members = false;
 
210
                bool may_access_klass_members = false;
 
211
 
 
212
                symbol_reference = null;
 
213
 
 
214
                if (qualified) {
 
215
                        base_symbol = context.analyzer.root_symbol;
 
216
                        symbol_reference = context.analyzer.root_symbol.scope.lookup (member_name);
 
217
                } else if (inner == null) {
 
218
                        if (member_name == "this") {
 
219
                                if (!context.analyzer.is_in_instance_method ()) {
 
220
                                        error = true;
 
221
                                        Report.error (source_reference, "This access invalid outside of instance methods");
 
222
                                        return false;
 
223
                                }
 
224
                        }
 
225
 
 
226
                        base_symbol = context.analyzer.current_symbol;
 
227
 
 
228
                        // track whether method has been found to make sure that access
 
229
                        // to instance member is denied from within static lambda expressions
 
230
                        bool method_found = false;
 
231
 
 
232
                        var sym = context.analyzer.current_symbol;
 
233
                        while (sym != null && symbol_reference == null) {
 
234
                                if (!method_found) {
 
235
                                        if (sym is CreationMethod) {
 
236
                                                var cm = (CreationMethod) sym;
 
237
                                                this_parameter = cm.this_parameter;
 
238
                                                may_access_instance_members = true;
 
239
                                                may_access_klass_members = true;
 
240
                                                method_found = true;
 
241
                                        } else if (sym is Property) {
 
242
                                                var prop = (Property) sym;
 
243
                                                this_parameter = prop.this_parameter;
 
244
                                                may_access_instance_members = (prop.binding == MemberBinding.INSTANCE);
 
245
                                                may_access_klass_members = (prop.binding != MemberBinding.STATIC);
 
246
                                                method_found = true;
 
247
                                        } else if (sym is Constructor) {
 
248
                                                var c = (Constructor) sym;
 
249
                                                this_parameter = c.this_parameter;
 
250
                                                may_access_instance_members = (c.binding == MemberBinding.INSTANCE);
 
251
                                                may_access_klass_members = true;
 
252
                                                method_found = true;
 
253
                                        } else if (sym is Destructor) {
 
254
                                                var d = (Destructor) sym;
 
255
                                                this_parameter = d.this_parameter;
 
256
                                                may_access_instance_members = (d.binding == MemberBinding.INSTANCE);
 
257
                                                may_access_klass_members = true;
 
258
                                                method_found = true;
 
259
                                        } else if (sym is Method) {
 
260
                                                var m = (Method) sym;
 
261
                                                this_parameter = m.this_parameter;
 
262
                                                may_access_instance_members = (m.binding == MemberBinding.INSTANCE);
 
263
                                                may_access_klass_members = (m.binding != MemberBinding.STATIC);
 
264
                                                method_found = true;
 
265
                                        }
 
266
                                }
 
267
 
 
268
                                symbol_reference = SemanticAnalyzer.symbol_lookup_inherited (sym, member_name);
 
269
 
 
270
                                if (symbol_reference == null && sym is TypeSymbol && may_access_instance_members) {
 
271
                                        // used for generated to_string methods in enums
 
272
                                        symbol_reference = this_parameter.variable_type.get_member (member_name);
 
273
 
 
274
                                        if (symbol_reference != null && is_instance_symbol (symbol_reference)) {
 
275
                                                // implicit this
 
276
                                                inner = new MemberAccess (null, "this", source_reference);
 
277
                                                inner.value_type = this_parameter.variable_type.copy ();
 
278
                                                inner.value_type.value_owned = false;
 
279
                                                inner.symbol_reference = this_parameter;
 
280
 
 
281
                                                symbol_reference = inner.value_type.get_member (member_name);
 
282
                                        }
 
283
                                }
 
284
 
 
285
                                if (symbol_reference == null) {
 
286
                                        if (sym is TypeSymbol) {
 
287
                                                // do not allow instance access to outer classes
 
288
                                                this_parameter = null;
 
289
                                                may_access_instance_members = false;
 
290
                                                may_access_klass_members = false;
 
291
                                        }
 
292
                                }
 
293
 
 
294
                                sym = sym.parent_symbol;
 
295
                        }
 
296
 
 
297
                        if (symbol_reference == null && source_reference != null) {
 
298
                                foreach (UsingDirective ns in source_reference.using_directives) {
 
299
                                        var local_sym = ns.namespace_symbol.scope.lookup (member_name);
 
300
                                        if (local_sym != null) {
 
301
                                                if (symbol_reference != null && symbol_reference != local_sym) {
 
302
                                                        error = true;
 
303
                                                        Report.error (source_reference, "`%s' is an ambiguous reference between `%s' and `%s'".printf (member_name, symbol_reference.get_full_name (), local_sym.get_full_name ()));
 
304
                                                        return false;
 
305
                                                }
 
306
                                                symbol_reference = local_sym;
 
307
                                        }
 
308
                                }
 
309
                        }
 
310
                } else {
 
311
                        if (inner.error) {
 
312
                                /* if there was an error in the inner expression, skip this check */
 
313
                                error = true;
 
314
                                return false;
 
315
                        }
 
316
 
 
317
                        if (inner.value_type is PointerType) {
 
318
                                var pointer_type = inner.value_type as PointerType;
 
319
                                if (pointer_type != null && pointer_type.base_type is ValueType) {
 
320
                                        // transform foo->bar to (*foo).bar
 
321
                                        inner = new PointerIndirection (inner, source_reference);
 
322
                                        inner.check (context);
 
323
                                        pointer_member_access = false;
 
324
                                }
 
325
                        }
 
326
 
 
327
                        if (inner is MemberAccess) {
 
328
                                var ma = (MemberAccess) inner;
 
329
                                if (ma.prototype_access) {
 
330
                                        error = true;
 
331
                                        Report.error (source_reference, "Access to instance member `%s' denied".printf (inner.symbol_reference.get_full_name ()));
 
332
                                        return false;
 
333
                                }
 
334
                        }
 
335
 
 
336
                        if (inner is MemberAccess || inner is BaseAccess) {
 
337
                                base_symbol = inner.symbol_reference;
 
338
 
 
339
                                if (symbol_reference == null && (base_symbol is Namespace || base_symbol is TypeSymbol)) {
 
340
                                        symbol_reference = base_symbol.scope.lookup (member_name);
 
341
                                        if (inner is BaseAccess) {
 
342
                                                // inner expression is base access
 
343
                                                // access to instance members of the base type possible
 
344
                                                may_access_instance_members = true;
 
345
                                                may_access_klass_members = true;
 
346
                                        }
 
347
                                }
 
348
                        }
 
349
 
 
350
                        if (symbol_reference == null && inner.value_type != null) {
 
351
                                if (pointer_member_access) {
 
352
                                        symbol_reference = inner.value_type.get_pointer_member (member_name);
 
353
                                } else {
 
354
                                        if (inner.value_type.data_type != null) {
 
355
                                                base_symbol = inner.value_type.data_type;
 
356
                                        }
 
357
                                        symbol_reference = inner.value_type.get_member (member_name);
 
358
                                }
 
359
                                if (symbol_reference != null) {
 
360
                                        // inner expression is variable, field, or parameter
 
361
                                        // access to instance members of the corresponding type possible
 
362
                                        may_access_instance_members = true;
 
363
                                        may_access_klass_members = true;
 
364
                                }
 
365
                        }
 
366
 
 
367
                        if (symbol_reference == null && inner.value_type != null && inner.value_type.is_dynamic) {
 
368
                                // allow late bound members for dynamic types
 
369
                                var dynamic_object_type = (ObjectType) inner.value_type;
 
370
                                if (parent_node is MethodCall) {
 
371
                                        var invoc = (MethodCall) parent_node;
 
372
                                        if (invoc.call == this) {
 
373
                                                // dynamic method
 
374
                                                DataType ret_type;
 
375
                                                if (invoc.target_type != null) {
 
376
                                                        ret_type = invoc.target_type.copy ();
 
377
                                                        ret_type.value_owned = true;
 
378
                                                } else if (invoc.parent_node is ExpressionStatement) {
 
379
                                                        ret_type = new VoidType ();
 
380
                                                } else {
 
381
                                                        // expect dynamic object of the same type
 
382
                                                        ret_type = inner.value_type.copy ();
 
383
                                                }
 
384
                                                var m = new DynamicMethod (inner.value_type, member_name, ret_type, source_reference);
 
385
                                                m.invocation = invoc;
 
386
                                                var err = new ErrorType (null, null);
 
387
                                                err.dynamic_error = true;
 
388
                                                m.add_error_type (err);
 
389
                                                m.access = SymbolAccessibility.PUBLIC;
 
390
                                                m.add_parameter (new Parameter.with_ellipsis ());
 
391
                                                dynamic_object_type.type_symbol.scope.add (null, m);
 
392
                                                symbol_reference = m;
 
393
                                        }
 
394
                                } else if (parent_node is Assignment) {
 
395
                                        var a = (Assignment) parent_node;
 
396
                                        if (a.left == this
 
397
                                            && (a.operator == AssignmentOperator.ADD
 
398
                                                || a.operator == AssignmentOperator.SUB)) {
 
399
                                                // dynamic signal
 
400
                                                var s = new DynamicSignal (inner.value_type, member_name, new VoidType (), source_reference);
 
401
                                                s.handler = a.right;
 
402
                                                s.access = SymbolAccessibility.PUBLIC;
 
403
                                                dynamic_object_type.type_symbol.scope.add (null, s);
 
404
                                                symbol_reference = s;
 
405
                                        } else if (a.left == this) {
 
406
                                                // dynamic property assignment
 
407
                                                var prop = new DynamicProperty (inner.value_type, member_name, source_reference);
 
408
                                                prop.access = SymbolAccessibility.PUBLIC;
 
409
                                                prop.set_accessor = new PropertyAccessor (false, true, false, null, null, prop.source_reference);
 
410
                                                prop.owner = inner.value_type.data_type.scope;
 
411
                                                dynamic_object_type.type_symbol.scope.add (null, prop);
 
412
                                                symbol_reference = prop;
 
413
                                        }
 
414
                                } else if (parent_node is MemberAccess && inner is MemberAccess && parent_node.parent_node is MethodCall) {
 
415
                                        var ma = (MemberAccess) parent_node;
 
416
                                        if (ma.member_name == "connect" || ma.member_name == "connect_after") {
 
417
                                                // dynamic signal
 
418
                                                var s = new DynamicSignal (inner.value_type, member_name, new VoidType (), source_reference);
 
419
                                                var mcall = (MethodCall) parent_node.parent_node;
 
420
                                                // the first argument is the handler
 
421
                                                if (mcall.get_argument_list().size > 0) {
 
422
                                                        s.handler = mcall.get_argument_list()[0];
 
423
                                                }
 
424
                                                s.access = SymbolAccessibility.PUBLIC;
 
425
                                                dynamic_object_type.type_symbol.scope.add (null, s);
 
426
                                                symbol_reference = s;
 
427
                                        }
 
428
                                }
 
429
                                if (symbol_reference == null) {
 
430
                                        // dynamic property read access
 
431
                                        var prop = new DynamicProperty (inner.value_type, member_name, source_reference);
 
432
                                        if (target_type != null) {
 
433
                                                prop.property_type = target_type;
 
434
                                        } else {
 
435
                                                // expect dynamic object of the same type
 
436
                                                prop.property_type = inner.value_type.copy ();
 
437
                                        }
 
438
                                        prop.access = SymbolAccessibility.PUBLIC;
 
439
                                        prop.get_accessor = new PropertyAccessor (true, false, false, prop.property_type.copy (), null, prop.source_reference);
 
440
                                        prop.owner = inner.value_type.data_type.scope;
 
441
                                        dynamic_object_type.type_symbol.scope.add (null, prop);
 
442
                                        symbol_reference = prop;
 
443
                                }
 
444
                                if (symbol_reference != null) {
 
445
                                        may_access_instance_members = true;
 
446
                                        may_access_klass_members = true;
 
447
                                }
 
448
                        }
 
449
                }
 
450
 
 
451
                if (symbol_reference == null) {
 
452
                        error = true;
 
453
 
 
454
                        string base_type_name = "(null)";
 
455
                        if (inner != null && inner.value_type != null) {
 
456
                                base_type_name = inner.value_type.to_string ();
 
457
                        } else if (base_symbol != null) {
 
458
                                base_type_name = base_symbol.get_full_name ();
 
459
                        }
 
460
 
 
461
                        Report.error (source_reference, "The name `%s' does not exist in the context of `%s'".printf (member_name, base_type_name));
 
462
                        return false;
 
463
                }
 
464
 
 
465
                var member = symbol_reference;
 
466
                var access = SymbolAccessibility.PUBLIC;
 
467
                bool instance = false;
 
468
                bool klass = false;
 
469
                bool generics = false;
 
470
 
 
471
                if (!member.check (context)) {
 
472
                        return false;
 
473
                }
 
474
 
 
475
                if (member is LocalVariable) {
 
476
                        var local = (LocalVariable) member;
 
477
                        var block = local.parent_symbol as Block;
 
478
                        if (block != null && context.analyzer.find_parent_method_or_property_accessor (block) != context.analyzer.current_method_or_property_accessor) {
 
479
                                // mark all methods between current method and the captured
 
480
                                // block as closures (to support nested closures)
 
481
                                Symbol sym = context.analyzer.current_method_or_property_accessor;
 
482
                                while (sym != block) {
 
483
                                        var method = sym as Method;
 
484
                                        if (method != null) {
 
485
                                                method.closure = true;
 
486
                                                // consider captured variables as used
 
487
                                                // as we require captured variables to be initialized
 
488
                                                method.add_captured_variable (local);
 
489
                                        }
 
490
                                        sym = sym.parent_symbol;
 
491
                                }
 
492
 
 
493
                                local.captured = true;
 
494
                                block.captured = true;
 
495
                        }
 
496
                } else if (member is Parameter) {
 
497
                        var param = (Parameter) member;
 
498
                        var m = param.parent_symbol as Method;
 
499
                        if (m != null && m != context.analyzer.current_method_or_property_accessor && param != m.this_parameter) {
 
500
                                // mark all methods between current method and the captured
 
501
                                // parameter as closures (to support nested closures)
 
502
                                Symbol sym = context.analyzer.current_method_or_property_accessor;
 
503
                                while (sym != m) {
 
504
                                        var method = sym as Method;
 
505
                                        if (method != null) {
 
506
                                                method.closure = true;
 
507
                                        }
 
508
                                        sym = sym.parent_symbol;
 
509
                                }
 
510
 
 
511
                                param.captured = true;
 
512
                                m.body.captured = true;
 
513
 
 
514
                                if (param.direction != ParameterDirection.IN) {
 
515
                                        error = true;
 
516
                                        Report.error (source_reference, "Cannot capture reference or output parameter `%s'".printf (param.get_full_name ()));
 
517
                                }
 
518
                        } else {
 
519
                                var acc = param.parent_symbol.parent_symbol as PropertyAccessor;
 
520
                                if (acc != null && acc != context.analyzer.current_method_or_property_accessor && param != acc.prop.this_parameter) {
 
521
                                        // mark all methods between current method and the captured
 
522
                                        // parameter as closures (to support nested closures)
 
523
                                        Symbol sym = context.analyzer.current_method_or_property_accessor;
 
524
                                        while (sym != m) {
 
525
                                                var method = sym as Method;
 
526
                                                if (method != null) {
 
527
                                                        method.closure = true;
 
528
                                                }
 
529
                                                sym = sym.parent_symbol;
 
530
                                        }
 
531
 
 
532
                                        param.captured = true;
 
533
                                        acc.body.captured = true;
 
534
                                }
 
535
                        }
 
536
                } else if (member is Field) {
 
537
                        var f = (Field) member;
 
538
                        access = f.access;
 
539
                        instance = (f.binding == MemberBinding.INSTANCE);
 
540
                        klass = (f.binding == MemberBinding.CLASS);
 
541
 
 
542
                        // do not allow access to fields of generic types
 
543
                        // if instance type does not specify type arguments
 
544
                        if (f.variable_type is GenericType) {
 
545
                                generics = true;
 
546
                        }
 
547
                } else if (member is Constant) {
 
548
                        var c = (Constant) member;
 
549
                        access = c.access;
 
550
 
 
551
                        var block = c.parent_symbol as Block;
 
552
                        if (block != null && context.analyzer.find_parent_method_or_property_accessor (block) != context.analyzer.current_method_or_property_accessor) {
 
553
                                error = true;
 
554
                                Report.error (source_reference, "internal error: accessing local constants of outer methods is not supported yet");
 
555
                                return false;
 
556
                        }
 
557
                } else if (member is Method) {
 
558
                        var m = (Method) member;
 
559
                        if (m.is_async_callback) {
 
560
                                // ensure to use right callback method for virtual/abstract async methods
 
561
                                // and also for lambda expressions within async methods
 
562
                                var async_method = context.analyzer.current_async_method;
 
563
 
 
564
                                bool is_valid_access = false;
 
565
                                if (async_method != null) {
 
566
                                        if (m == async_method.get_callback_method ()) {
 
567
                                                is_valid_access = true;
 
568
                                        } else if (async_method.base_method != null && m == async_method.base_method.get_callback_method ()) {
 
569
                                                is_valid_access = true;
 
570
                                        } else if (async_method.base_interface_method != null && m == async_method.base_interface_method.get_callback_method ()) {
 
571
                                                is_valid_access = true;
 
572
                                        }
 
573
                                }
 
574
                                if (!is_valid_access) {
 
575
                                        error = true;
 
576
                                        Report.error (source_reference, "Access to async callback `%s' not allowed in this context".printf (m.get_full_name ()));
 
577
                                        return false;
 
578
                                }
 
579
 
 
580
                                if (async_method != context.analyzer.current_method) {
 
581
                                        Symbol sym = context.analyzer.current_method;
 
582
                                        while (sym != async_method) {
 
583
                                                var method = sym as Method;
 
584
                                                if (method != null) {
 
585
                                                        method.closure = true;
 
586
                                                }
 
587
                                                sym = sym.parent_symbol;
 
588
                                        }
 
589
                                        async_method.body.captured = true;
 
590
                                }
 
591
 
 
592
                                m = async_method.get_callback_method ();
 
593
                                symbol_reference = m;
 
594
                                member = symbol_reference;
 
595
                        } else if (m.base_method != null) {
 
596
                                // refer to base method to inherit default arguments
 
597
                                m = m.base_method;
 
598
 
 
599
                                if (m.signal_reference != null) {
 
600
                                        // method is class/default handler for a signal
 
601
                                        // let signal deal with member access
 
602
                                        symbol_reference = m.signal_reference;
 
603
                                } else {
 
604
                                        symbol_reference = m;
 
605
                                }
 
606
 
 
607
                                member = symbol_reference;
 
608
                        } else if (m.base_interface_method != null) {
 
609
                                // refer to base method to inherit default arguments
 
610
                                m = m.base_interface_method;
 
611
 
 
612
                                if (m.signal_reference != null) {
 
613
                                        // method is class/default handler for a signal
 
614
                                        // let signal deal with member access
 
615
                                        symbol_reference = m.signal_reference;
 
616
                                } else {
 
617
                                        symbol_reference = m;
 
618
                                }
 
619
 
 
620
                                member = symbol_reference;
 
621
                        }
 
622
                        access = m.access;
 
623
                        if (!(m is CreationMethod)) {
 
624
                                instance = (m.binding == MemberBinding.INSTANCE);
 
625
                        }
 
626
                        klass = (m.binding == MemberBinding.CLASS);
 
627
 
 
628
                        // do not allow access to methods using generic type parameters
 
629
                        // if instance type does not specify type arguments
 
630
                        foreach (var param in m.get_parameters ()) {
 
631
                                var generic_type = param.variable_type as GenericType;
 
632
                                if (generic_type != null && generic_type.type_parameter.parent_symbol is TypeSymbol) {
 
633
                                        generics = true;
 
634
                                        break;
 
635
                                }
 
636
                        }
 
637
                        var generic_type = m.return_type as GenericType;
 
638
                        if (generic_type != null && generic_type.type_parameter.parent_symbol is TypeSymbol) {
 
639
                                generics = true;
 
640
                        }
 
641
                } else if (member is Property) {
 
642
                        var prop = (Property) member;
 
643
                        if (!prop.check (context)) {
 
644
                                error = true;
 
645
                                return false;
 
646
                        }
 
647
                        if (prop.base_property != null) {
 
648
                                // refer to base property
 
649
                                prop = prop.base_property;
 
650
                                symbol_reference = prop;
 
651
                                member = symbol_reference;
 
652
                        } else if (prop.base_interface_property != null) {
 
653
                                // refer to base property
 
654
                                prop = prop.base_interface_property;
 
655
                                symbol_reference = prop;
 
656
                                member = symbol_reference;
 
657
                        }
 
658
                        access = prop.access;
 
659
                        if (lvalue) {
 
660
                                if (prop.set_accessor == null) {
 
661
                                        error = true;
 
662
                                        Report.error (source_reference, "Property `%s' is read-only".printf (prop.get_full_name ()));
 
663
                                        return false;
 
664
                                }
 
665
                                if (prop.access == SymbolAccessibility.PUBLIC) {
 
666
                                        access = prop.set_accessor.access;
 
667
                                } else if (prop.access == SymbolAccessibility.PROTECTED
 
668
                                           && prop.set_accessor.access != SymbolAccessibility.PUBLIC) {
 
669
                                        access = prop.set_accessor.access;
 
670
                                }
 
671
                        } else {
 
672
                                if (prop.get_accessor == null) {
 
673
                                        error = true;
 
674
                                        Report.error (source_reference, "Property `%s' is write-only".printf (prop.get_full_name ()));
 
675
                                        return false;
 
676
                                }
 
677
                                if (prop.access == SymbolAccessibility.PUBLIC) {
 
678
                                        access = prop.get_accessor.access;
 
679
                                } else if (prop.access == SymbolAccessibility.PROTECTED
 
680
                                           && prop.get_accessor.access != SymbolAccessibility.PUBLIC) {
 
681
                                        access = prop.get_accessor.access;
 
682
                                }
 
683
                        }
 
684
                        instance = (prop.binding == MemberBinding.INSTANCE);
 
685
 
 
686
                        // do not allow access to properties of generic types
 
687
                        // if instance type does not specify type arguments
 
688
                        if (prop.property_type is GenericType) {
 
689
                                generics = true;
 
690
                        }
 
691
                } else if (member is Signal) {
 
692
                        instance = true;
 
693
                        access = member.access;
 
694
                }
 
695
 
 
696
                member.used = true;
 
697
                member.check_deprecated (source_reference);
 
698
                member.check_experimental (source_reference);
 
699
 
 
700
                if (access == SymbolAccessibility.PROTECTED) {
 
701
                        var target_type = (TypeSymbol) member.parent_symbol;
 
702
 
 
703
                        bool in_subtype = false;
 
704
                        for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) {
 
705
                                if (this_symbol == target_type) {
 
706
                                        // required for interfaces with non-abstract methods
 
707
                                        // accessing protected interface members
 
708
                                        in_subtype = true;
 
709
                                        break;
 
710
                                }
 
711
 
 
712
                                var cl = this_symbol as Class;
 
713
                                if (cl != null && cl.is_subtype_of (target_type)) {
 
714
                                        in_subtype = true;
 
715
                                        break;
 
716
                                }
 
717
                        }
 
718
 
 
719
                        if (!in_subtype) {
 
720
                                error = true;
 
721
                                Report.error (source_reference, "Access to protected member `%s' denied".printf (member.get_full_name ()));
 
722
                                return false;
 
723
                        }
 
724
                } else if (access == SymbolAccessibility.PRIVATE) {
 
725
                        var target_type = member.parent_symbol;
 
726
 
 
727
                        bool in_target_type = false;
 
728
                        for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) {
 
729
                                if (target_type == this_symbol) {
 
730
                                        in_target_type = true;
 
731
                                        break;
 
732
                                }
 
733
                        }
 
734
 
 
735
                        if (!in_target_type) {
 
736
                                error = true;
 
737
                                Report.error (source_reference, "Access to private member `%s' denied".printf (member.get_full_name ()));
 
738
                                return false;
 
739
                        }
 
740
                }
 
741
 
 
742
                if (generics && inner != null) {
 
743
                        var instance_type = inner.value_type;
 
744
                        var pointer_type = inner.value_type as PointerType;
 
745
                        if (pointer_type != null) {
 
746
                                instance_type = pointer_type.base_type;
 
747
                        }
 
748
 
 
749
                        // instance type might be a subtype of the parent symbol of the member
 
750
                        // that subtype might not be generic, so do not report an error in that case
 
751
                        var object_type = instance_type as ObjectType;
 
752
                        if (object_type != null && object_type.type_symbol.get_type_parameters ().size > 0 &&
 
753
                            instance_type.get_type_arguments ().size == 0) {
 
754
                                error = true;
 
755
                                Report.error (inner.source_reference, "missing generic type arguments");
 
756
                                return false;
 
757
                        }
 
758
                }
 
759
 
 
760
                if ((instance && !may_access_instance_members) ||
 
761
                    (klass && !may_access_klass_members)) {
 
762
                        prototype_access = true;
 
763
 
 
764
                        if (symbol_reference is Method) {
 
765
                                // also set static type for prototype access
 
766
                                // required when using instance methods as delegates in constants
 
767
                                // TODO replace by MethodPrototype
 
768
                                value_type = context.analyzer.get_value_type_for_symbol (symbol_reference, lvalue);
 
769
                        } else if (symbol_reference is Field) {
 
770
                                value_type = new FieldPrototype ((Field) symbol_reference);
 
771
                        } else {
 
772
                                value_type = new InvalidType ();
 
773
                        }
 
774
 
 
775
                        if (target_type != null) {
 
776
                                value_type.value_owned = target_type.value_owned;
 
777
                        }
 
778
                } else {
 
779
                        // implicit this access
 
780
                        if (instance && inner == null) {
 
781
                                inner = new MemberAccess (null, "this", source_reference);
 
782
                                inner.value_type = this_parameter.variable_type.copy ();
 
783
                                inner.value_type.value_owned = false;
 
784
                                inner.symbol_reference = this_parameter;
 
785
                        } else {
 
786
                                check_lvalue_access ();
 
787
                        }
 
788
 
 
789
                        if (!instance && !klass && !(symbol_reference is CreationMethod) && may_access_instance_members && inner != null) {
 
790
                                if (inner.symbol_reference is Method) {
 
791
                                        // do not warn when calling .begin or .end on static async method
 
792
                                } else {
 
793
                                        Report.warning (source_reference, "Access to static member `%s' with an instance reference".printf (symbol_reference.get_full_name ()));
 
794
                                }
 
795
                        }
 
796
 
 
797
                        if (context.experimental_non_null && instance && inner.value_type.nullable &&
 
798
                            !(inner.value_type is PointerType) && !(inner.value_type is GenericType)) {
 
799
                                Report.error (source_reference, "Access to instance member `%s' from nullable reference denied".printf (symbol_reference.get_full_name ()));
 
800
                        }
 
801
 
 
802
                        var m = symbol_reference as Method;
 
803
                        var inner_ma = inner as MemberAccess;
 
804
                        if (m != null && m.binding == MemberBinding.STATIC && m.parent_symbol is ObjectTypeSymbol &&
 
805
                            inner != null && inner.value_type == null && inner_ma.type_argument_list.size > 0) {
 
806
                                // support static methods in generic classes
 
807
                                inner.value_type = new ObjectType ((ObjectTypeSymbol) m.parent_symbol);
 
808
 
 
809
                                foreach (var type_argument in inner_ma.type_argument_list) {
 
810
                                        inner.value_type.add_type_argument (type_argument);
 
811
                                }
 
812
                        }
 
813
 
 
814
                        formal_value_type = context.analyzer.get_value_type_for_symbol (symbol_reference, lvalue);
 
815
                        if (inner != null && formal_value_type != null) {
 
816
                                value_type = formal_value_type.get_actual_type (inner.value_type, null, this);
 
817
                        } else {
 
818
                                value_type = formal_value_type;
 
819
                        }
 
820
 
 
821
                        if (symbol_reference is Method) {
 
822
                                if (target_type != null) {
 
823
                                        value_type.value_owned = target_type.value_owned;
 
824
                                }
 
825
 
 
826
                                Method base_method;
 
827
                                if (m.base_method != null) {
 
828
                                        base_method = m.base_method;
 
829
                                } else if (m.base_interface_method != null) {
 
830
                                        base_method = m.base_interface_method;
 
831
                                } else {
 
832
                                        base_method = m;
 
833
                                }
 
834
 
 
835
                                if (instance && base_method.parent_symbol is TypeSymbol) {
 
836
                                        inner.target_type = SemanticAnalyzer.get_data_type_for_symbol ((TypeSymbol) base_method.parent_symbol);
 
837
                                        inner.target_type.value_owned = base_method.this_parameter.variable_type.value_owned;
 
838
                                }
 
839
                        } else if (symbol_reference is Property) {
 
840
                                var prop = (Property) symbol_reference;
 
841
 
 
842
                                Property base_property;
 
843
                                if (prop.base_property != null) {
 
844
                                        base_property = prop.base_property;
 
845
                                } else if (prop.base_interface_property != null) {
 
846
                                        base_property = prop.base_interface_property;
 
847
                                } else {
 
848
                                        base_property = prop;
 
849
                                }
 
850
 
 
851
                                if (instance && base_property.parent_symbol != null) {
 
852
                                        inner.target_type = SemanticAnalyzer.get_data_type_for_symbol ((TypeSymbol) base_property.parent_symbol);
 
853
                                }
 
854
                        } else if ((symbol_reference is Field
 
855
                                    || symbol_reference is Signal)
 
856
                                   && instance && symbol_reference.parent_symbol != null) {
 
857
                                var parent_type = SemanticAnalyzer.get_data_type_for_symbol ((TypeSymbol) symbol_reference.parent_symbol);
 
858
                                inner.target_type = parent_type.get_actual_type (inner.value_type, null, this);
 
859
                        }
 
860
                }
 
861
 
 
862
                return !error;
 
863
        }
 
864
 
 
865
        static bool is_instance_symbol (Symbol symbol) {
 
866
                if (symbol is Field && ((Field) symbol).binding == MemberBinding.INSTANCE) {
 
867
                        return true;
 
868
                } else if (symbol is Method && !(symbol is CreationMethod) && ((Method) symbol).binding == MemberBinding.INSTANCE) {
 
869
                        return true;
 
870
                } else if (symbol is Property && ((Property) symbol).binding == MemberBinding.INSTANCE) {
 
871
                        return true;
 
872
                } else if (symbol is Signal) {
 
873
                        return true;
 
874
                } else {
 
875
                        return false;
 
876
                }
 
877
        }
 
878
 
 
879
        public void check_lvalue_access () {
 
880
                if (inner == null) {
 
881
                        return;
 
882
                }
 
883
                var instance = symbol_reference is Field && ((Field) symbol_reference).binding == MemberBinding.INSTANCE;
 
884
                if (!instance) {
 
885
                        instance = symbol_reference is Method && ((Method) symbol_reference).binding == MemberBinding.INSTANCE;
 
886
                }
 
887
                if (!instance) {
 
888
                        instance = symbol_reference is Property && ((Property) symbol_reference).binding == MemberBinding.INSTANCE;
 
889
                }
 
890
 
 
891
                var this_access = inner.symbol_reference is Parameter && inner.symbol_reference.name == "this";
 
892
                var struct_or_array = (inner.value_type is StructValueType && !inner.value_type.nullable) || inner.value_type is ArrayType;
 
893
 
 
894
                if (instance && struct_or_array && (symbol_reference is Method || lvalue) && ((inner is MemberAccess && inner.symbol_reference is Variable) || inner is ElementAccess) && !this_access) {
 
895
                        inner.lvalue = true;
 
896
                        if (inner is MemberAccess) {
 
897
                                ((MemberAccess) inner).check_lvalue_access ();
 
898
                        }
 
899
                }
 
900
        }
 
901
 
 
902
        public override void emit (CodeGenerator codegen) {
 
903
                if (inner != null) {
 
904
                        inner.emit (codegen);
 
905
                }
 
906
 
 
907
                codegen.visit_member_access (this);
 
908
 
 
909
                codegen.visit_expression (this);
 
910
        }
 
911
 
 
912
        public override void get_defined_variables (Collection<Variable> collection) {
 
913
                if (inner != null) {
 
914
                        inner.get_defined_variables (collection);
 
915
                }
 
916
        }
 
917
 
 
918
        public override void get_used_variables (Collection<Variable> collection) {
 
919
                if (inner != null) {
 
920
                        inner.get_used_variables (collection);
 
921
                }
 
922
                var local = symbol_reference as LocalVariable;
 
923
                var param = symbol_reference as Parameter;
 
924
                if (local != null) {
 
925
                        collection.add (local);
 
926
                } else if (param != null && param.direction == ParameterDirection.OUT) {
 
927
                        collection.add (param);
 
928
                }
 
929
        }
 
930
}