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 23using GLib; 24 25/** 26 * Represents an access to a type member in the source code. 27 */ 28public 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 * Requires indirect access due to possible side-effects of parent expression. 62 */ 63 public bool tainted_access { get; set; } 64 65 /** 66 * Specifies whether the member is used for object creation. 67 */ 68 public bool creation_member { get; set; } 69 70 /** 71 * Qualified access to global symbol. 72 */ 73 public bool qualified { get; set; } 74 75 private Expression? _inner; 76 private List<DataType> type_argument_list = new ArrayList<DataType> (); 77 78 /** 79 * Creates a new member access expression. 80 * 81 * @param inner parent of the member 82 * @param member_name member name 83 * @param source_reference reference to source code 84 * @return newly created member access expression 85 */ 86 public MemberAccess (Expression? inner, string member_name, SourceReference? source_reference = null) { 87 this.inner = inner; 88 this.member_name = member_name; 89 this.source_reference = source_reference; 90 } 91 92 public MemberAccess.simple (string member_name, SourceReference? source_reference = null) { 93 this.inner = null; 94 this.member_name = member_name; 95 this.source_reference = source_reference; 96 } 97 98 public MemberAccess.pointer (Expression inner, string member_name, SourceReference? source_reference = null) { 99 this.inner = inner; 100 this.member_name = member_name; 101 this.source_reference = source_reference; 102 pointer_member_access = true; 103 } 104 105 /** 106 * Appends the specified type as generic type argument. 107 * 108 * @param arg a type reference 109 */ 110 public void add_type_argument (DataType arg) { 111 type_argument_list.add (arg); 112 arg.parent_node = this; 113 } 114 115 /** 116 * Returns the list of generic type arguments. 117 * 118 * @return type argument list 119 */ 120 public unowned List<DataType> get_type_arguments () { 121 return type_argument_list; 122 } 123 124 public override void accept (CodeVisitor visitor) { 125 visitor.visit_member_access (this); 126 127 visitor.visit_expression (this); 128 } 129 130 public override void accept_children (CodeVisitor visitor) { 131 if (inner != null) { 132 inner.accept (visitor); 133 } 134 135 foreach (DataType type_arg in type_argument_list) { 136 type_arg.accept (visitor); 137 } 138 } 139 140 public override string to_string () { 141 if (symbol_reference == null || symbol_reference.is_instance_member ()) { 142 if (inner == null) { 143 return member_name; 144 } else { 145 return "%s%s%s".printf (inner.to_string (), pointer_member_access ? "->" : ".", member_name); 146 } 147 } else { 148 // ensure to always use fully-qualified name 149 // to refer to static members 150 return symbol_reference.get_full_name (); 151 } 152 } 153 154 public override void replace_expression (Expression old_node, Expression new_node) { 155 if (inner == old_node) { 156 inner = new_node; 157 } 158 } 159 160 public override bool is_pure () { 161 // accessing property could have side-effects 162 return (inner == null || inner.is_pure ()) && !(symbol_reference is Property); 163 } 164 165 public override bool is_accessible (Symbol sym) { 166 return (inner == null || inner.is_accessible (sym)) && symbol_reference.is_accessible (sym); 167 } 168 169 public override void replace_type (DataType old_type, DataType new_type) { 170 for (int i = 0; i < type_argument_list.size; i++) { 171 if (type_argument_list[i] == old_type) { 172 type_argument_list[i] = new_type; 173 return; 174 } 175 } 176 } 177 178 public override bool is_constant () { 179 unowned Method? method = symbol_reference as Method; 180 if (symbol_reference is Constant) { 181 return true; 182 } else if (symbol_reference is ArrayLengthField && inner != null && inner.symbol_reference is Constant) { 183 // length of constant array 184 return true; 185 } else if (method != null && 186 (method.binding == MemberBinding.STATIC || prototype_access)) { 187 return true; 188 } else { 189 return false; 190 } 191 } 192 193 public override bool is_non_null () { 194 unowned Constant? c = symbol_reference as Constant; 195 if (c != null) { 196 return (c is EnumValue || !c.type_reference.nullable); 197 } else { 198 return false; 199 } 200 } 201 202 public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) { 203 if (inner != null) { 204 inner.get_error_types (collection, source_reference); 205 } 206 } 207 208 public override bool check (CodeContext context) { 209 if (checked) { 210 return !error; 211 } 212 213 checked = true; 214 215 if (inner != null) { 216 inner.check (context); 217 } 218 219 foreach (DataType type_arg in type_argument_list) { 220 type_arg.check (context); 221 } 222 223 unowned Symbol? base_symbol = null; 224 unowned Parameter? this_parameter = null; 225 bool may_access_instance_members = false; 226 bool may_access_klass_members = false; 227 228 symbol_reference = null; 229 230 if (qualified) { 231 base_symbol = context.root; 232 symbol_reference = base_symbol.scope.lookup (member_name); 233 } else if (inner == null) { 234 if (member_name == "this") { 235 if (!context.analyzer.is_in_instance_method ()) { 236 error = true; 237 Report.error (source_reference, "This access invalid outside of instance methods"); 238 return false; 239 } 240 } 241 242 base_symbol = context.analyzer.current_symbol; 243 244 // track whether method has been found to make sure that access 245 // to instance member is denied from within static lambda expressions 246 bool method_found = false; 247 248 unowned Symbol? sym = context.analyzer.current_symbol; 249 while (sym != null && symbol_reference == null) { 250 if (!method_found) { 251 if (sym is CreationMethod) { 252 unowned CreationMethod cm = (CreationMethod) sym; 253 this_parameter = cm.this_parameter; 254 may_access_instance_members = true; 255 may_access_klass_members = true; 256 method_found = true; 257 } else if (sym is Property) { 258 unowned Property prop = (Property) sym; 259 this_parameter = prop.this_parameter; 260 may_access_instance_members = (prop.binding == MemberBinding.INSTANCE); 261 may_access_klass_members = (prop.binding != MemberBinding.STATIC); 262 method_found = true; 263 } else if (sym is Constructor) { 264 unowned Constructor c = (Constructor) sym; 265 this_parameter = c.this_parameter; 266 may_access_instance_members = (c.binding == MemberBinding.INSTANCE); 267 may_access_klass_members = true; 268 method_found = true; 269 } else if (sym is Destructor) { 270 unowned Destructor d = (Destructor) sym; 271 this_parameter = d.this_parameter; 272 may_access_instance_members = (d.binding == MemberBinding.INSTANCE); 273 may_access_klass_members = true; 274 method_found = true; 275 } else if (sym is Method) { 276 unowned Method m = (Method) sym; 277 this_parameter = m.this_parameter; 278 may_access_instance_members = (m.binding == MemberBinding.INSTANCE); 279 may_access_klass_members = (m.binding != MemberBinding.STATIC); 280 method_found = true; 281 } 282 } 283 284 symbol_reference = SemanticAnalyzer.symbol_lookup_inherited (sym, member_name); 285 286 if (symbol_reference == null && sym is TypeSymbol && may_access_instance_members) { 287 // used for generated to_string methods in enums 288 symbol_reference = this_parameter.variable_type.get_member (member_name); 289 290 if (symbol_reference != null && is_instance_symbol (symbol_reference)) { 291 // implicit this 292 inner = new MemberAccess (null, "this", source_reference); 293 inner.value_type = this_parameter.variable_type.copy (); 294 inner.value_type.value_owned = false; 295 inner.symbol_reference = this_parameter; 296 297 symbol_reference = inner.value_type.get_member (member_name); 298 } 299 } 300 301 if (symbol_reference == null) { 302 if (sym is TypeSymbol) { 303 // do not allow instance access to outer classes 304 this_parameter = null; 305 may_access_instance_members = false; 306 may_access_klass_members = false; 307 } 308 } 309 310 sym = sym.parent_symbol; 311 } 312 313 if (symbol_reference == null && source_reference != null) { 314 foreach (UsingDirective ns in source_reference.using_directives) { 315 if (ns.error) { 316 // ignore previous error 317 continue; 318 } 319 var local_sym = ns.namespace_symbol.scope.lookup (member_name); 320 if (local_sym != null) { 321 if (symbol_reference != null && symbol_reference != local_sym) { 322 error = true; 323 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 ())); 324 return false; 325 } 326 327 // Transform to fully qualified member access 328 unowned Symbol? inner_sym = local_sym.parent_symbol; 329 unowned MemberAccess? inner_ma = this; 330 while (inner_sym != null && inner_sym.name != null) { 331 inner_ma.inner = new MemberAccess (null, inner_sym.name, source_reference); 332 inner_ma = (MemberAccess) inner_ma.inner; 333 inner_sym = inner_sym.parent_symbol; 334 } 335 inner_ma.qualified = true; 336 inner.check (context); 337 338 symbol_reference = local_sym; 339 } 340 } 341 } 342 } else { 343 if (inner.error) { 344 /* if there was an error in the inner expression, skip this check */ 345 error = true; 346 return false; 347 } 348 349 if (inner.value_type is PointerType) { 350 unowned PointerType? pointer_type = inner.value_type as PointerType; 351 if (pointer_type != null && pointer_type.base_type is ValueType) { 352 if (inner.formal_value_type is GenericType) { 353 inner = new CastExpression (inner, pointer_type.copy (), source_reference); 354 } 355 // transform foo->bar to (*foo).bar 356 inner = new PointerIndirection (inner, source_reference); 357 inner.check (context); 358 pointer_member_access = false; 359 } 360 } 361 362 if (inner is MemberAccess) { 363 unowned MemberAccess ma = (MemberAccess) inner; 364 if (ma.prototype_access) { 365 error = true; 366 Report.error (source_reference, "Access to instance member `%s' denied".printf (inner.symbol_reference.get_full_name ())); 367 return false; 368 } 369 } 370 371 if (inner is CastExpression && ((CastExpression) inner).is_silent_cast) { 372 Report.warning (source_reference, "Access to possible `null'. Perform a check or use an unsafe cast."); 373 } 374 375 if (inner is MemberAccess || inner is BaseAccess) { 376 base_symbol = inner.symbol_reference; 377 378 if (symbol_reference == null && (base_symbol is Namespace || base_symbol is TypeSymbol)) { 379 symbol_reference = base_symbol.scope.lookup (member_name); 380 if (inner is BaseAccess) { 381 // inner expression is base access 382 // access to instance members of the base type possible 383 may_access_instance_members = true; 384 may_access_klass_members = true; 385 } 386 } 387 } 388 389 if (inner is MemberAccess && inner.symbol_reference is TypeParameter) { 390 inner.value_type = new GenericType ((TypeParameter) inner.symbol_reference); 391 inner.value_type.source_reference = source_reference; 392 } 393 394 if (symbol_reference == null && inner.value_type != null) { 395 if (pointer_member_access) { 396 symbol_reference = inner.value_type.get_pointer_member (member_name); 397 } else { 398 if (inner.value_type.type_symbol != null) { 399 base_symbol = inner.value_type.type_symbol; 400 } 401 symbol_reference = inner.value_type.get_member (member_name); 402 } 403 if (symbol_reference != null) { 404 // inner expression is variable, field, or parameter 405 // access to instance members of the corresponding type possible 406 may_access_instance_members = true; 407 may_access_klass_members = true; 408 } 409 } 410 411 if (symbol_reference == null && inner.value_type != null && inner.value_type.is_dynamic) { 412 // allow late bound members for dynamic types 413 var dynamic_object_type = (ObjectType) inner.value_type; 414 if (parent_node is MethodCall) { 415 unowned MethodCall invoc = (MethodCall) parent_node; 416 if (invoc.call == this) { 417 // dynamic method 418 DataType ret_type; 419 if (invoc.target_type != null) { 420 ret_type = invoc.target_type.copy (); 421 ret_type.value_owned = true; 422 } else if (invoc.parent_node is ExpressionStatement) { 423 ret_type = new VoidType (); 424 } else { 425 // expect dynamic object of the same type 426 ret_type = inner.value_type.copy (); 427 } 428 var m = new DynamicMethod (inner.value_type, member_name, ret_type, source_reference); 429 m.invocation = invoc; 430 var err = new ErrorType (null, null); 431 err.dynamic_error = true; 432 m.add_error_type (err); 433 m.access = SymbolAccessibility.PUBLIC; 434 m.add_parameter (new Parameter.with_ellipsis ()); 435 m.this_parameter = new Parameter ("this", dynamic_object_type.copy (), m.source_reference); 436 dynamic_object_type.type_symbol.scope.add (null, m); 437 symbol_reference = m; 438 } 439 } else if (parent_node is Assignment) { 440 unowned Assignment a = (Assignment) parent_node; 441 if (a.left == this) { 442 // dynamic property assignment 443 var prop = new DynamicProperty (inner.value_type, member_name, source_reference); 444 prop.access = SymbolAccessibility.PUBLIC; 445 prop.set_accessor = new PropertyAccessor (false, true, false, null, null, prop.source_reference); 446 prop.owner = inner.value_type.type_symbol.scope; 447 dynamic_object_type.type_symbol.scope.add (null, prop); 448 symbol_reference = prop; 449 } 450 } else if (parent_node is MemberAccess && inner is MemberAccess && parent_node.parent_node is MethodCall) { 451 unowned MemberAccess ma = (MemberAccess) parent_node; 452 if (ma.member_name == "connect" || ma.member_name == "connect_after") { 453 // dynamic signal 454 var s = new DynamicSignal (inner.value_type, member_name, new VoidType (), source_reference); 455 var mcall = (MethodCall) parent_node.parent_node; 456 // the first argument is the handler 457 if (mcall.get_argument_list().size > 0) { 458 s.handler = mcall.get_argument_list()[0]; 459 unowned MemberAccess? arg = s.handler as MemberAccess; 460 if (arg == null || !arg.check (context) || !(arg.symbol_reference is Method)) { 461 error = true; 462 Report.error (s.handler.source_reference, "Invalid handler for `%s'".printf (s.get_full_name ())); 463 } 464 } 465 s.access = SymbolAccessibility.PUBLIC; 466 dynamic_object_type.type_symbol.scope.add (null, s); 467 symbol_reference = s; 468 } 469 } 470 if (symbol_reference == null) { 471 // dynamic property read access 472 var prop = new DynamicProperty (inner.value_type, member_name, source_reference); 473 if (target_type != null) { 474 prop.property_type = target_type; 475 } else { 476 // expect dynamic object of the same type 477 prop.property_type = inner.value_type.copy (); 478 } 479 prop.access = SymbolAccessibility.PUBLIC; 480 prop.get_accessor = new PropertyAccessor (true, false, false, prop.property_type.copy (), null, prop.source_reference); 481 prop.owner = inner.value_type.type_symbol.scope; 482 dynamic_object_type.type_symbol.scope.add (null, prop); 483 symbol_reference = prop; 484 } 485 if (symbol_reference != null) { 486 may_access_instance_members = true; 487 may_access_klass_members = true; 488 } 489 } 490 491 if (symbol_reference is ArrayResizeMethod && inner.symbol_reference is Variable) { 492 // require the real type with its original value_owned attritubte 493 var inner_type = context.analyzer.get_value_type_for_symbol (inner.symbol_reference, true) as ArrayType; 494 if (inner_type != null && inner_type.inline_allocated) { 495 Report.error (source_reference, "`resize' is not supported for arrays with fixed length"); 496 error = true; 497 } else if (inner_type != null && !inner_type.value_owned) { 498 Report.error (source_reference, "`resize' is not allowed for unowned array references"); 499 error = true; 500 } 501 } 502 } 503 504 // enum-type inference 505 if (inner == null && symbol_reference == null && target_type != null && target_type.type_symbol is Enum) { 506 unowned Enum enum_type = (Enum) target_type.type_symbol; 507 foreach (var val in enum_type.get_values ()) { 508 if (member_name == val.name) { 509 symbol_reference = val; 510 break; 511 } 512 } 513 } 514 515 if (symbol_reference == null) { 516 error = true; 517 518 string base_type_name = "(null)"; 519 unowned Symbol? base_type = null; 520 if (inner != null && inner.value_type != null) { 521 base_type_name = inner.value_type.to_string (); 522 base_type = inner.value_type.type_symbol; 523 } else if (base_symbol != null) { 524 base_type_name = base_symbol.get_full_name (); 525 base_type = base_symbol; 526 } 527 528 string? base_type_package = ""; 529 if (base_type != null && base_type.external_package) { 530 base_type_package = base_symbol.source_reference.file.package_name; 531 if (base_type_package != null) { 532 base_type_package = " (%s)".printf (base_type_package); 533 } 534 } 535 536 Report.error (source_reference, "The name `%s' does not exist in the context of `%s'%s".printf (member_name, base_type_name, base_type_package)); 537 value_type = new InvalidType (); 538 return false; 539 } else if (symbol_reference.error) { 540 //ignore previous error 541 error = true; 542 return false; 543 } 544 545 if (symbol_reference is Signal) { 546 unowned Signal sig = (Signal) symbol_reference; 547 unowned CodeNode? ma = this; 548 while (ma.parent_node is MemberAccess) { 549 ma = ma.parent_node; 550 } 551 unowned CodeNode? parent = ma.parent_node; 552 if (parent != null && !(parent is ElementAccess) && !(((MemberAccess) ma).inner is BaseAccess) 553 && (!(parent is MethodCall) || ((MethodCall) parent).get_argument_list ().contains (this))) { 554 if (sig.get_attribute ("HasEmitter") != null) { 555 if (!sig.check (context)) { 556 return false; 557 } 558 symbol_reference = sig.emitter; 559 } else { 560 error = true; 561 Report.error (source_reference, "Signal `%s' requires emitter in this context".printf (symbol_reference.get_full_name ())); 562 return false; 563 } 564 } 565 } 566 567 unowned Symbol? member = symbol_reference; 568 var access = SymbolAccessibility.PUBLIC; 569 bool instance = false; 570 bool klass = false; 571 bool generics = false; 572 573 if (!member.check (context)) { 574 return false; 575 } 576 577 if (member is LocalVariable) { 578 unowned LocalVariable local = (LocalVariable) member; 579 unowned Block? block = local.parent_symbol as Block; 580 if (block != null && SemanticAnalyzer.find_parent_method_or_property_accessor (block) != context.analyzer.current_method_or_property_accessor) { 581 // mark all methods between current method and the captured 582 // block as closures (to support nested closures) 583 unowned Symbol? sym = context.analyzer.current_method_or_property_accessor; 584 while (sym != block) { 585 unowned Method? method = sym as Method; 586 if (method != null) { 587 method.closure = true; 588 // consider captured variables as used 589 // as we require captured variables to be initialized 590 method.add_captured_variable (local); 591 } 592 sym = sym.parent_symbol; 593 } 594 595 local.captured = true; 596 block.captured = true; 597 598 if (local.variable_type.type_symbol == context.analyzer.va_list_type.type_symbol) { 599 error = true; 600 Report.error (source_reference, "Capturing `va_list' variable `%s' is not allowed".printf (local.get_full_name ())); 601 } 602 } 603 } else if (member is Parameter) { 604 unowned Parameter param = (Parameter) member; 605 unowned Method? m = param.parent_symbol as Method; 606 if (m != null && m != context.analyzer.current_method_or_property_accessor && param != m.this_parameter) { 607 // mark all methods between current method and the captured 608 // parameter as closures (to support nested closures) 609 unowned Symbol? sym = context.analyzer.current_method_or_property_accessor; 610 while (sym != m) { 611 unowned Method? method = sym as Method; 612 if (method != null) { 613 method.closure = true; 614 } 615 sym = sym.parent_symbol; 616 } 617 618 param.captured = true; 619 m.body.captured = true; 620 621 if (param.direction != ParameterDirection.IN) { 622 error = true; 623 Report.error (source_reference, "Cannot capture reference or output parameter `%s'".printf (param.get_full_name ())); 624 } 625 if (param.variable_type.type_symbol == context.analyzer.va_list_type.type_symbol) { 626 error = true; 627 Report.error (source_reference, "Capturing `va_list' parameter `%s' is not allowed".printf (param.get_full_name ())); 628 } 629 } else { 630 unowned PropertyAccessor? acc = param.parent_symbol.parent_symbol as PropertyAccessor; 631 if (acc != null && acc != context.analyzer.current_method_or_property_accessor && param != acc.prop.this_parameter) { 632 // mark all methods between current method and the captured 633 // parameter as closures (to support nested closures) 634 unowned Symbol? sym = context.analyzer.current_method_or_property_accessor; 635 while (sym != m) { 636 unowned Method? method = sym as Method; 637 if (method != null) { 638 method.closure = true; 639 } 640 sym = sym.parent_symbol; 641 } 642 643 param.captured = true; 644 acc.body.captured = true; 645 } 646 } 647 } else if (member is Field) { 648 unowned Field f = (Field) member; 649 access = f.access; 650 instance = (f.binding == MemberBinding.INSTANCE); 651 klass = (f.binding == MemberBinding.CLASS); 652 653 // do not allow access to fields of generic types 654 // if instance type does not specify type arguments 655 if (f.variable_type is GenericType) { 656 generics = true; 657 } 658 } else if (member is Constant) { 659 unowned Constant c = (Constant) member; 660 access = c.access; 661 662 unowned Block? block = c.parent_symbol as Block; 663 if (block != null && SemanticAnalyzer.find_parent_method_or_property_accessor (block) != context.analyzer.current_method_or_property_accessor) { 664 error = true; 665 Report.error (source_reference, "internal error: accessing local constants of outer methods is not supported yet"); 666 return false; 667 } 668 } else if (member is Method) { 669 unowned Method m = (Method) member; 670 if (m.is_async_callback) { 671 // ensure to use right callback method for virtual/abstract async methods 672 // and also for lambda expressions within async methods 673 unowned Method? async_method = context.analyzer.current_async_method; 674 675 bool is_valid_access = false; 676 if (async_method != null) { 677 if (m == async_method.get_callback_method ()) { 678 is_valid_access = true; 679 } else if (async_method.base_method != null && m == async_method.base_method.get_callback_method ()) { 680 is_valid_access = true; 681 } else if (async_method.base_interface_method != null && m == async_method.base_interface_method.get_callback_method ()) { 682 is_valid_access = true; 683 } 684 } 685 if (!is_valid_access) { 686 error = true; 687 Report.error (source_reference, "Access to async callback `%s' not allowed in this context".printf (m.get_full_name ())); 688 return false; 689 } 690 691 if (async_method != context.analyzer.current_method) { 692 unowned Symbol? sym = context.analyzer.current_method; 693 while (sym != async_method) { 694 unowned Method? method = sym as Method; 695 if (method != null) { 696 method.closure = true; 697 } 698 sym = sym.parent_symbol; 699 } 700 async_method.body.captured = true; 701 } 702 703 m = async_method.get_callback_method (); 704 symbol_reference = m; 705 member = symbol_reference; 706 } else if (m.base_method != null) { 707 // refer to base method to inherit default arguments 708 m = m.base_method; 709 710 if (m.signal_reference != null) { 711 // method is class/default handler for a signal 712 // let signal deal with member access 713 symbol_reference = m.signal_reference; 714 } else { 715 symbol_reference = m; 716 } 717 718 member = symbol_reference; 719 } else if (m.base_interface_method != null) { 720 // refer to base method to inherit default arguments 721 m = m.base_interface_method; 722 723 if (m.signal_reference != null) { 724 // method is class/default handler for a signal 725 // let signal deal with member access 726 symbol_reference = m.signal_reference; 727 } else { 728 symbol_reference = m; 729 } 730 731 member = symbol_reference; 732 } 733 access = m.access; 734 if (!(m is CreationMethod)) { 735 instance = (m.binding == MemberBinding.INSTANCE); 736 } 737 klass = (m.binding == MemberBinding.CLASS); 738 739 // do not allow access to methods using generic type parameters 740 // if instance type does not specify type arguments 741 foreach (var param in m.get_parameters ()) { 742 unowned GenericType? generic_type = param.variable_type as GenericType; 743 if (generic_type != null && generic_type.type_parameter.parent_symbol is TypeSymbol) { 744 generics = true; 745 break; 746 } 747 } 748 unowned GenericType? generic_type = m.return_type as GenericType; 749 if (generic_type != null && generic_type.type_parameter.parent_symbol is TypeSymbol) { 750 generics = true; 751 } 752 } else if (member is Property) { 753 unowned Property prop = (Property) member; 754 if (!prop.check (context)) { 755 error = true; 756 return false; 757 } 758 if (prop.base_property != null) { 759 // refer to base property 760 prop = prop.base_property; 761 symbol_reference = prop; 762 member = symbol_reference; 763 } else if (prop.base_interface_property != null) { 764 // refer to base property 765 prop = prop.base_interface_property; 766 symbol_reference = prop; 767 member = symbol_reference; 768 } 769 access = prop.access; 770 if (lvalue) { 771 if (prop.set_accessor == null) { 772 error = true; 773 Report.error (source_reference, "Property `%s' is read-only".printf (prop.get_full_name ())); 774 return false; 775 } else if (!prop.set_accessor.writable && prop.set_accessor.construction) { 776 if (context.analyzer.find_current_method () is CreationMethod) { 777 error = true; 778 Report.error (source_reference, "Cannot assign to construct-only properties, use Object (property: value) constructor chain up"); 779 return false; 780 } else if (context.analyzer.is_in_constructor ()) { 781 if (!context.analyzer.current_type_symbol.is_subtype_of ((TypeSymbol) prop.parent_symbol)) { 782 error = true; 783 Report.error (source_reference, "Cannot assign to construct-only property `%s' in `construct' of `%s'".printf (prop.get_full_name (), context.analyzer.current_type_symbol.get_full_name ())); 784 return false; 785 } 786 } else { 787 error = true; 788 Report.error (source_reference, "Cannot assign to construct-only property in this context"); 789 return false; 790 } 791 } 792 if (prop.access == SymbolAccessibility.PUBLIC) { 793 access = prop.set_accessor.access; 794 } else if (prop.access == SymbolAccessibility.PROTECTED 795 && prop.set_accessor.access != SymbolAccessibility.PUBLIC) { 796 access = prop.set_accessor.access; 797 } 798 } else { 799 if (prop.get_accessor == null) { 800 error = true; 801 Report.error (source_reference, "Property `%s' is write-only".printf (prop.get_full_name ())); 802 return false; 803 } 804 if (prop.access == SymbolAccessibility.PUBLIC) { 805 access = prop.get_accessor.access; 806 } else if (prop.access == SymbolAccessibility.PROTECTED 807 && prop.get_accessor.access != SymbolAccessibility.PUBLIC) { 808 access = prop.get_accessor.access; 809 } 810 } 811 instance = (prop.binding == MemberBinding.INSTANCE); 812 813 // do not allow access to properties of generic types 814 // if instance type does not specify type arguments 815 if (prop.property_type is GenericType) { 816 generics = true; 817 } 818 } else if (member is Signal) { 819 instance = true; 820 access = member.access; 821 } else if (!creation_member && member is ErrorCode) { 822 symbol_reference = ((ErrorCode) member).code; 823 member = symbol_reference; 824 } 825 826 // recursive usage of itself doesn't count as used 827 unowned CodeNode? parent = this; 828 while (parent != member) { 829 parent = parent.parent_node; 830 if (parent == null || parent == member) { 831 break; 832 } 833 } 834 if (parent != member) { 835 member.used = true; 836 } 837 member.version.check (source_reference); 838 839 if (access == SymbolAccessibility.PROTECTED && member.parent_symbol is TypeSymbol) { 840 unowned TypeSymbol target_type = (TypeSymbol) member.parent_symbol; 841 842 bool in_subtype = false; 843 for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) { 844 if (this_symbol == target_type) { 845 // required for interfaces with non-abstract methods 846 // accessing protected interface members 847 in_subtype = true; 848 break; 849 } 850 851 unowned Class? cl = this_symbol as Class; 852 if (cl != null && cl.is_subtype_of (target_type)) { 853 in_subtype = true; 854 break; 855 } 856 } 857 858 if (!in_subtype) { 859 error = true; 860 Report.error (source_reference, "Access to protected member `%s' denied".printf (member.get_full_name ())); 861 return false; 862 } 863 } else if (access == SymbolAccessibility.PRIVATE) { 864 unowned Symbol? target_type = member.parent_symbol; 865 866 bool in_target_type = false; 867 for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) { 868 if (target_type == this_symbol) { 869 in_target_type = true; 870 break; 871 } 872 } 873 874 if (!in_target_type) { 875 error = true; 876 Report.error (source_reference, "Access to private member `%s' denied".printf (member.get_full_name ())); 877 return false; 878 } 879 } 880 881 if (generics && inner != null) { 882 unowned DataType instance_type = inner.value_type; 883 unowned PointerType? pointer_type = inner.value_type as PointerType; 884 if (pointer_type != null) { 885 instance_type = pointer_type.base_type; 886 } 887 888 // instance type might be a subtype of the parent symbol of the member 889 // that subtype might not be generic, so do not report an error in that case 890 unowned ObjectType? object_type = instance_type as ObjectType; 891 if (object_type != null && object_type.object_type_symbol.has_type_parameters () 892 && !instance_type.has_type_arguments ()) { 893 error = true; 894 Report.error (inner.source_reference, "missing generic type arguments"); 895 return false; 896 } 897 } 898 899 if ((instance && !may_access_instance_members) || 900 (klass && !may_access_klass_members)) { 901 prototype_access = true; 902 903 if (symbol_reference is Method) { 904 // also set static type for prototype access 905 // required when using instance methods as delegates in constants 906 // TODO replace by MethodPrototype 907 value_type = context.analyzer.get_value_type_for_symbol (symbol_reference, lvalue); 908 } else if (symbol_reference is Field) { 909 value_type = new FieldPrototype ((Field) symbol_reference); 910 } else if (symbol_reference is Property) { 911 value_type = new PropertyPrototype ((Property) symbol_reference); 912 } else { 913 error = true; 914 value_type = new InvalidType (); 915 } 916 917 if (target_type != null) { 918 value_type.value_owned = target_type.value_owned; 919 } 920 } else { 921 // implicit this access 922 if (instance && inner == null) { 923 inner = new MemberAccess (null, "this", source_reference); 924 inner.value_type = this_parameter.variable_type.copy (); 925 inner.value_type.value_owned = false; 926 inner.symbol_reference = this_parameter; 927 } else { 928 check_lvalue_access (); 929 } 930 931 if (!instance && !klass && !(symbol_reference is CreationMethod) && may_access_instance_members && inner != null) { 932 if (inner.symbol_reference is Method) { 933 // do not warn when calling .begin or .end on static async method 934 } else { 935 Report.warning (source_reference, "Access to static member `%s' with an instance reference".printf (symbol_reference.get_full_name ())); 936 937 // Transform to static member access 938 unowned Symbol? inner_sym = symbol_reference.parent_symbol; 939 unowned MemberAccess? inner_ma = this; 940 while (inner_sym != null && inner_sym.name != null) { 941 inner_ma.inner = new MemberAccess (null, inner_sym.name, source_reference); 942 inner_ma = (MemberAccess) inner_ma.inner; 943 inner_sym = inner_sym.parent_symbol; 944 } 945 inner_ma.qualified = true; 946 inner.check (context); 947 } 948 } 949 950 if (context.experimental_non_null && instance && inner.value_type.nullable && 951 !(inner.value_type is PointerType) && !(inner.value_type is GenericType) && 952 !(inner.value_type is ArrayType)) { 953 Report.error (source_reference, "Access to instance member `%s' from nullable reference denied".printf (symbol_reference.get_full_name ())); 954 } 955 956 unowned Method? m = symbol_reference as Method; 957 unowned MemberAccess? inner_ma = inner as MemberAccess; 958 if (m != null && m.binding == MemberBinding.STATIC && m.parent_symbol is ObjectTypeSymbol && 959 inner != null && inner.value_type == null && inner_ma.type_argument_list.size > 0) { 960 // support static methods in generic classes 961 inner.value_type = new ObjectType ((ObjectTypeSymbol) m.parent_symbol); 962 963 foreach (var type_argument in inner_ma.type_argument_list) { 964 inner.value_type.add_type_argument (type_argument); 965 } 966 } 967 968 formal_value_type = context.analyzer.get_value_type_for_symbol (symbol_reference, lvalue); 969 if (inner != null && formal_value_type != null) { 970 value_type = formal_value_type.get_actual_type (inner.value_type, null, this); 971 } else { 972 value_type = formal_value_type; 973 } 974 975 if (symbol_reference is Method) { 976 unowned Method method = (Method) symbol_reference; 977 if (target_type != null) { 978 value_type.value_owned = target_type.value_owned; 979 } 980 if (instance && method.parent_symbol is TypeSymbol) { 981 inner.target_type = SemanticAnalyzer.get_data_type_for_symbol (method.parent_symbol); 982 inner.target_type.value_owned = method.this_parameter.variable_type.value_owned; 983 } 984 } else if (symbol_reference is Property 985 && instance && symbol_reference.parent_symbol != null) { 986 inner.target_type = SemanticAnalyzer.get_data_type_for_symbol (symbol_reference.parent_symbol); 987 } else if ((symbol_reference is Field || symbol_reference is Signal) 988 && instance && symbol_reference.parent_symbol != null) { 989 var parent_type = SemanticAnalyzer.get_data_type_for_symbol (symbol_reference.parent_symbol); 990 inner.target_type = parent_type.get_actual_type (inner.value_type, null, this); 991 } 992 } 993 994 if (value_type != null) { 995 value_type.check (context); 996 } 997 998 // Provide some extra information for the code generator 999 if (!tainted_access) { 1000 tainted_access = is_tainted (); 1001 } 1002 1003 return !error; 1004 } 1005 1006 static bool is_instance_symbol (Symbol symbol) { 1007 if (symbol is Field && ((Field) symbol).binding == MemberBinding.INSTANCE) { 1008 return true; 1009 } else if (symbol is Method && !(symbol is CreationMethod) && ((Method) symbol).binding == MemberBinding.INSTANCE) { 1010 return true; 1011 } else if (symbol is Property && ((Property) symbol).binding == MemberBinding.INSTANCE) { 1012 return true; 1013 } else if (symbol is Signal) { 1014 return true; 1015 } else { 1016 return false; 1017 } 1018 } 1019 1020 public void check_lvalue_access () { 1021 if (inner == null) { 1022 return; 1023 } 1024 var instance = symbol_reference is Field && ((Field) symbol_reference).binding == MemberBinding.INSTANCE; 1025 if (!instance) { 1026 instance = symbol_reference is Method && ((Method) symbol_reference).binding == MemberBinding.INSTANCE; 1027 } 1028 if (!instance) { 1029 instance = symbol_reference is Property && ((Property) symbol_reference).binding == MemberBinding.INSTANCE; 1030 } 1031 1032 var this_access = inner.symbol_reference is Parameter && inner.symbol_reference.name == "this"; 1033 var struct_or_array = (inner.value_type is StructValueType && !inner.value_type.nullable) || inner.value_type is ArrayType; 1034 1035 unowned MemberAccess? ma = inner as MemberAccess; 1036 if (ma == null && struct_or_array && inner is PointerIndirection) { 1037 // (*struct)->method() 1038 ma = ((PointerIndirection) inner).inner as MemberAccess; 1039 } 1040 1041 if (instance && struct_or_array && (symbol_reference is Method || lvalue) && ((ma != null && ma.symbol_reference is Variable) || inner is ElementAccess) && !this_access) { 1042 inner.lvalue = true; 1043 if (ma != null) { 1044 ma.lvalue = true; 1045 ma.check_lvalue_access (); 1046 } 1047 } 1048 1049 if (symbol_reference is Method && ((Method) symbol_reference).get_attribute ("DestroysInstance") != null) { 1050 unowned Class? cl = ((Method) symbol_reference).parent_symbol as Class; 1051 if (cl != null && cl.is_compact && ma != null) { 1052 ma.lvalue = true; 1053 ma.check_lvalue_access (); 1054 } 1055 } 1056 } 1057 1058 public override void emit (CodeGenerator codegen) { 1059 if (inner != null) { 1060 inner.emit (codegen); 1061 } 1062 1063 codegen.visit_member_access (this); 1064 1065 codegen.visit_expression (this); 1066 } 1067 1068 public override void get_defined_variables (Collection<Variable> collection) { 1069 if (inner != null) { 1070 inner.get_defined_variables (collection); 1071 } 1072 } 1073 1074 public override void get_used_variables (Collection<Variable> collection) { 1075 if (inner != null) { 1076 inner.get_used_variables (collection); 1077 } 1078 unowned LocalVariable? local = symbol_reference as LocalVariable; 1079 unowned Parameter? param = symbol_reference as Parameter; 1080 if (local != null) { 1081 collection.add (local); 1082 } else if (param != null && param.direction == ParameterDirection.OUT) { 1083 collection.add (param); 1084 } 1085 } 1086 1087 bool is_tainted () { 1088 unowned CodeNode node = this; 1089 if (node.parent_node is MemberAccess) { 1090 return false; 1091 } 1092 1093 while (node.parent_node is Expression) { 1094 node = node.parent_node; 1095 if (node is Assignment || node is MethodCall || node is ObjectCreationExpression) { 1096 break; 1097 } 1098 } 1099 1100 bool found = false; 1101 var traverse = new TraverseVisitor ((n) => { 1102 if (n is PostfixExpression) { 1103 found = true; 1104 return TraverseStatus.STOP; 1105 } else if (n is UnaryExpression) { 1106 unowned UnaryExpression e = (UnaryExpression) n; 1107 if (e.operator == UnaryOperator.INCREMENT || e.operator == UnaryOperator.DECREMENT) { 1108 found = true; 1109 return TraverseStatus.STOP; 1110 } 1111 } 1112 return TraverseStatus.CONTINUE; 1113 }); 1114 node.accept (traverse); 1115 1116 return found; 1117 } 1118} 1119