1 /******************************************************************************* 2 * Copyright (c) 2000, 2003 IBM Corporation and others. 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Common Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/cpl-v10.html 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 *******************************************************************************/ 11 package net.sourceforge.phpdt.internal.compiler.lookup; 12 13 import net.sourceforge.phpdt.core.compiler.CharOperation; 14 import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration; 15 import net.sourceforge.phpdt.internal.compiler.ast.ConstructorDeclaration; 16 import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration; 17 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter; 18 19 public class BlockScope extends Scope { 20 21 // Local variable management 22 public LocalVariableBinding[] locals; 23 24 public int localIndex; // position for next variable 25 26 public int startIndex; // start position in this scope - for ordering 27 // scopes vs. variables 28 29 public int offset; // for variable allocation throughout scopes 30 31 public int maxOffset; // for variable allocation throughout scopes 32 33 // finally scopes must be shifted behind respective try&catch scope(s) so as 34 // to avoid 35 // collisions of secret variables (return address, save value). 36 public BlockScope[] shiftScopes; 37 38 public final static VariableBinding[] EmulationPathToImplicitThis = {}; 39 40 public final static VariableBinding[] NoEnclosingInstanceInConstructorCall = {}; 41 42 public final static VariableBinding[] NoEnclosingInstanceInStaticContext = {}; 43 44 public Scope[] subscopes = new Scope[1]; // need access from code assist 45 46 public int scopeIndex = 0; // need access from code assist 47 BlockScope(int kind, Scope parent)48 protected BlockScope(int kind, Scope parent) { 49 50 super(kind, parent); 51 } 52 BlockScope(BlockScope parent)53 public BlockScope(BlockScope parent) { 54 55 this(parent, true); 56 } 57 BlockScope(BlockScope parent, boolean addToParentScope)58 public BlockScope(BlockScope parent, boolean addToParentScope) { 59 60 this(BLOCK_SCOPE, parent); 61 locals = new LocalVariableBinding[5]; 62 if (addToParentScope) 63 parent.addSubscope(this); 64 this.startIndex = parent.localIndex; 65 } 66 BlockScope(BlockScope parent, int variableCount)67 public BlockScope(BlockScope parent, int variableCount) { 68 69 this(BLOCK_SCOPE, parent); 70 locals = new LocalVariableBinding[variableCount]; 71 parent.addSubscope(this); 72 this.startIndex = parent.localIndex; 73 } 74 75 /* 76 * Create the class scope & binding for the anonymous type. 77 */ addAnonymousType(TypeDeclaration anonymousType, ReferenceBinding superBinding)78 public final void addAnonymousType(TypeDeclaration anonymousType, 79 ReferenceBinding superBinding) { 80 81 ClassScope anonymousClassScope = new ClassScope(this, anonymousType); 82 anonymousClassScope.buildAnonymousTypeBinding(enclosingSourceType(), 83 superBinding); 84 } 85 86 /* 87 * Create the class scope & binding for the local type. 88 */ addLocalType(TypeDeclaration localType)89 public final void addLocalType(TypeDeclaration localType) { 90 91 // check that the localType does not conflict with an enclosing type 92 ReferenceBinding type = enclosingSourceType(); 93 do { 94 if (CharOperation.equals(type.sourceName, localType.name)) { 95 problemReporter().hidingEnclosingType(localType); 96 return; 97 } 98 type = type.enclosingType(); 99 } while (type != null); 100 101 // check that the localType does not conflict with another sibling local 102 // type 103 Scope scope = this; 104 do { 105 if (((BlockScope) scope).findLocalType(localType.name) != null) { 106 problemReporter().duplicateNestedType(localType); 107 return; 108 } 109 } while ((scope = scope.parent) instanceof BlockScope); 110 111 ClassScope localTypeScope = new ClassScope(this, localType); 112 addSubscope(localTypeScope); 113 localTypeScope.buildLocalTypeBinding(enclosingSourceType()); 114 } 115 116 /* 117 * Insert a local variable into a given scope, updating its position and 118 * checking there are not too many locals or arguments allocated. 119 */ addLocalVariable(LocalVariableBinding binding)120 public final void addLocalVariable(LocalVariableBinding binding) { 121 122 checkAndSetModifiersForVariable(binding); 123 124 // insert local in scope 125 if (localIndex == locals.length) 126 System.arraycopy(locals, 0, 127 (locals = new LocalVariableBinding[localIndex * 2]), 0, 128 localIndex); 129 locals[localIndex++] = binding; 130 131 // update local variable binding 132 binding.declaringScope = this; 133 binding.id = this.outerMostMethodScope().analysisIndex++; 134 // share the outermost method scope analysisIndex 135 } 136 addSubscope(Scope childScope)137 public void addSubscope(Scope childScope) { 138 if (scopeIndex == subscopes.length) 139 System.arraycopy(subscopes, 0, 140 (subscopes = new Scope[scopeIndex * 2]), 0, scopeIndex); 141 subscopes[scopeIndex++] = childScope; 142 } 143 144 /* 145 * Answer true if the receiver is suitable for assigning final blank fields. 146 * 147 * in other words, it is inside an initializer, a constructor or a clinit 148 */ allowBlankFinalFieldAssignment(FieldBinding binding)149 public final boolean allowBlankFinalFieldAssignment(FieldBinding binding) { 150 151 if (enclosingSourceType() != binding.declaringClass) 152 return false; 153 154 MethodScope methodScope = methodScope(); 155 if (methodScope.isStatic != binding.isStatic()) 156 return false; 157 return methodScope.isInsideInitializer() // inside initializer 158 || ((AbstractMethodDeclaration) methodScope.referenceContext) 159 .isInitializationMethod(); // inside constructor or 160 // clinit 161 } 162 basicToString(int tab)163 String basicToString(int tab) { 164 String newLine = "\n"; //$NON-NLS-1$ 165 for (int i = tab; --i >= 0;) 166 newLine += "\t"; //$NON-NLS-1$ 167 168 String s = newLine + "--- Block Scope ---"; //$NON-NLS-1$ 169 newLine += "\t"; //$NON-NLS-1$ 170 s += newLine + "locals:"; //$NON-NLS-1$ 171 for (int i = 0; i < localIndex; i++) 172 s += newLine + "\t" + locals[i].toString(); //$NON-NLS-1$ 173 s += newLine + "startIndex = " + startIndex; //$NON-NLS-1$ 174 return s; 175 } 176 checkAndSetModifiersForVariable(LocalVariableBinding varBinding)177 private void checkAndSetModifiersForVariable(LocalVariableBinding varBinding) { 178 179 int modifiers = varBinding.modifiers; 180 if ((modifiers & AccAlternateModifierProblem) != 0 181 && varBinding.declaration != null) { 182 problemReporter().duplicateModifierForVariable( 183 varBinding.declaration, this instanceof MethodScope); 184 } 185 int realModifiers = modifiers & AccJustFlag; 186 187 int unexpectedModifiers = ~AccFinal; 188 if ((realModifiers & unexpectedModifiers) != 0 189 && varBinding.declaration != null) { 190 problemReporter().illegalModifierForVariable( 191 varBinding.declaration, this instanceof MethodScope); 192 } 193 varBinding.modifiers = modifiers; 194 } 195 196 /* 197 * Compute variable positions in scopes given an initial position offset 198 * ignoring unused local variables. 199 * 200 * No argument is expected here (ilocal is the first non-argument local of 201 * the outermost scope) Arguments are managed by the MethodScope method 202 */ 203 // void computeLocalVariablePositions(int ilocal, int initOffset, CodeStream 204 // codeStream) { 205 // 206 // this.offset = initOffset; 207 // this.maxOffset = initOffset; 208 // 209 // // local variable init 210 // int maxLocals = this.localIndex; 211 // boolean hasMoreVariables = ilocal < maxLocals; 212 // 213 // // scope init 214 // int iscope = 0, maxScopes = this.scopeIndex; 215 // boolean hasMoreScopes = maxScopes > 0; 216 // 217 // // iterate scopes and variables in parallel 218 // while (hasMoreVariables || hasMoreScopes) { 219 // if (hasMoreScopes 220 // && (!hasMoreVariables || (subscopes[iscope].startIndex() <= ilocal))) { 221 // // consider subscope first 222 // if (subscopes[iscope] instanceof BlockScope) { 223 // BlockScope subscope = (BlockScope) subscopes[iscope]; 224 // int subOffset = subscope.shiftScopes == null ? this.offset : 225 // subscope.maxShiftedOffset(); 226 // subscope.computeLocalVariablePositions(0, subOffset, codeStream); 227 // if (subscope.maxOffset > this.maxOffset) 228 // this.maxOffset = subscope.maxOffset; 229 // } 230 // hasMoreScopes = ++iscope < maxScopes; 231 // } else { 232 // 233 // // consider variable first 234 // LocalVariableBinding local = locals[ilocal]; // if no local at all, will 235 // be locals[ilocal]==null 236 // 237 // // check if variable is actually used, and may force it to be preserved 238 // boolean generateCurrentLocalVar = (local.useFlag == 239 // LocalVariableBinding.USED && (local.constant == Constant.NotAConstant)); 240 // 241 // // do not report fake used variable 242 // if (local.useFlag == LocalVariableBinding.UNUSED 243 // && (local.declaration != null) // unused (and non secret) local 244 // && ((local.declaration.bits & ASTNode.IsLocalDeclarationReachableMASK) != 245 // 0)) { // declaration is reachable 246 // 247 // if (!(local.declaration instanceof Argument)) // do not report unused 248 // catch arguments 249 // this.problemReporter().unusedLocalVariable(local.declaration); 250 // } 251 // 252 // // could be optimized out, but does need to preserve unread variables ? 253 // // if (!generateCurrentLocalVar) { 254 // // if (local.declaration != null && 255 // environment().options.preserveAllLocalVariables) { 256 // // generateCurrentLocalVar = true; // force it to be preserved in the 257 // generated code 258 // // local.useFlag = LocalVariableBinding.USED; 259 // // } 260 // // } 261 // 262 // // allocate variable 263 // if (generateCurrentLocalVar) { 264 // 265 // if (local.declaration != null) { 266 // codeStream.record(local); // record user-defined local variables for 267 // attribute generation 268 // } 269 // // assign variable position 270 // local.resolvedPosition = this.offset; 271 // 272 // if ((local.type == LongBinding) || (local.type == DoubleBinding)) { 273 // this.offset += 2; 274 // } else { 275 // this.offset++; 276 // } 277 // if (this.offset > 0xFFFF) { // no more than 65535 words of locals 278 // this.problemReporter().noMoreAvailableSpaceForLocal( 279 // local, 280 // local.declaration == null ? (ASTNode)this.methodScope().referenceContext 281 // : local.declaration); 282 // } 283 // } else { 284 // local.resolvedPosition = -1; // not generated 285 // } 286 // hasMoreVariables = ++ilocal < maxLocals; 287 // } 288 // } 289 // if (this.offset > this.maxOffset) 290 // this.maxOffset = this.offset; 291 // } 292 /* 293 * Answer true if the variable name already exists within the receiver's 294 * scope. 295 */ duplicateName(char[] name)296 public final LocalVariableBinding duplicateName(char[] name) { 297 for (int i = 0; i < localIndex; i++) 298 if (CharOperation.equals(name, locals[i].name)) 299 return locals[i]; 300 301 if (this instanceof MethodScope) 302 return null; 303 else 304 return ((BlockScope) parent).duplicateName(name); 305 } 306 307 /* 308 * Record the suitable binding denoting a synthetic field or constructor 309 * argument, mapping to the actual outer local variable in the scope 310 * context. Note that this may not need any effect, in case the outer local 311 * variable does not need to be emulated and can directly be used as is 312 * (using its back pointer to its declaring scope). 313 */ emulateOuterAccess(LocalVariableBinding outerLocalVariable)314 public void emulateOuterAccess(LocalVariableBinding outerLocalVariable) { 315 316 MethodScope currentMethodScope; 317 if ((currentMethodScope = this.methodScope()) != outerLocalVariable.declaringScope 318 .methodScope()) { 319 NestedTypeBinding currentType = (NestedTypeBinding) this 320 .enclosingSourceType(); 321 322 // do nothing for member types, pre emulation was performed already 323 if (!currentType.isLocalType()) { 324 return; 325 } 326 // must also add a synthetic field if we're not inside a constructor 327 if (!currentMethodScope.isInsideInitializerOrConstructor()) { 328 currentType.addSyntheticArgumentAndField(outerLocalVariable); 329 } else { 330 currentType.addSyntheticArgument(outerLocalVariable); 331 } 332 } 333 } 334 335 /* 336 * Note that it must never produce a direct access to the 337 * targetEnclosingType, but instead a field sequence (this$2.this$1.this$0) 338 * so as to handle such a test case: 339 * 340 * class XX { void foo() { class A { class B { class C { boolean foo() { 341 * return (Object) A.this == (Object) B.this; } } } } new A().new B().new 342 * C(); } } where we only want to deal with ONE enclosing instance for C 343 * (could not figure out an A for C) 344 */ findLocalType(char[] name)345 public final ReferenceBinding findLocalType(char[] name) { 346 347 for (int i = 0, length = scopeIndex; i < length; i++) { 348 if (subscopes[i] instanceof ClassScope) { 349 SourceTypeBinding sourceType = ((ClassScope) subscopes[i]).referenceContext.binding; 350 if (CharOperation.equals(sourceType.sourceName(), name)) 351 return sourceType; 352 } 353 } 354 return null; 355 } 356 findVariable(char[] variable)357 public LocalVariableBinding findVariable(char[] variable) { 358 359 int variableLength = variable.length; 360 for (int i = 0, length = locals.length; i < length; i++) { 361 LocalVariableBinding local = locals[i]; 362 if (local == null) 363 return null; 364 if (local.name.length == variableLength 365 && CharOperation.prefixEquals(local.name, variable)) 366 return local; 367 } 368 return null; 369 } 370 371 /* 372 * API flag is a mask of the following values VARIABLE (= FIELD or LOCAL), 373 * TYPE. Only bindings corresponding to the mask will be answered. 374 * 375 * if the VARIABLE mask is set then If the first name provided is a field 376 * (or local) then the field (or local) is answered Otherwise, package names 377 * and type names are consumed until a field is found. In this case, the 378 * field is answered. 379 * 380 * if the TYPE mask is set, package names and type names are consumed until 381 * the end of the input. Only if all of the input is consumed is the type 382 * answered 383 * 384 * All other conditions are errors, and a problem binding is returned. 385 * 386 * NOTE: If a problem binding is returned, senders should extract the 387 * compound name from the binding & not assume the problem applies to the 388 * entire compoundName. 389 * 390 * The VARIABLE mask has precedence over the TYPE mask. 391 * 392 * InvocationSite implements isSuperAccess(); this is used to determine if 393 * the discovered field is visible. setFieldIndex(int); this is used to 394 * record the number of names that were consumed. 395 * 396 * For example, getBinding({"foo","y","q", VARIABLE, site) will answer the 397 * binding for the field or local named "foo" (or an error binding if none 398 * exists). In addition, setFieldIndex(1) will be sent to the invocation 399 * site. If a type named "foo" exists, it will not be detected (and an error 400 * binding will be answered) 401 * 402 * IMPORTANT NOTE: This method is written under the assumption that 403 * compoundName is longer than length 1. 404 */ getBinding(char[][] compoundName, int mask, InvocationSite invocationSite)405 public Binding getBinding(char[][] compoundName, int mask, 406 InvocationSite invocationSite) { 407 408 Binding binding = getBinding(compoundName[0], mask | TYPE | PACKAGE, 409 invocationSite); 410 invocationSite.setFieldIndex(1); 411 if (binding instanceof VariableBinding) 412 return binding; 413 compilationUnitScope().recordSimpleReference(compoundName[0]); 414 if (!binding.isValidBinding()) 415 return binding; 416 417 int length = compoundName.length; 418 int currentIndex = 1; 419 foundType: if (binding instanceof PackageBinding) { 420 PackageBinding packageBinding = (PackageBinding) binding; 421 while (currentIndex < length) { 422 compilationUnitScope() 423 .recordReference(packageBinding.compoundName, 424 compoundName[currentIndex]); 425 binding = packageBinding 426 .getTypeOrPackage(compoundName[currentIndex++]); 427 invocationSite.setFieldIndex(currentIndex); 428 if (binding == null) { 429 if (currentIndex == length) 430 // must be a type if its the last name, otherwise we 431 // have no idea if its a package or type 432 return new ProblemReferenceBinding(CharOperation 433 .subarray(compoundName, 0, currentIndex), 434 NotFound); 435 else 436 return new ProblemBinding(CharOperation.subarray( 437 compoundName, 0, currentIndex), NotFound); 438 } 439 if (binding instanceof ReferenceBinding) { 440 if (!binding.isValidBinding()) 441 return new ProblemReferenceBinding(CharOperation 442 .subarray(compoundName, 0, currentIndex), 443 binding.problemId()); 444 if (!((ReferenceBinding) binding).canBeSeenBy(this)) 445 return new ProblemReferenceBinding(CharOperation 446 .subarray(compoundName, 0, currentIndex), 447 (ReferenceBinding) binding, NotVisible); 448 break foundType; 449 } 450 packageBinding = (PackageBinding) binding; 451 } 452 453 // It is illegal to request a PACKAGE from this method. 454 return new ProblemReferenceBinding(CharOperation.subarray( 455 compoundName, 0, currentIndex), NotFound); 456 } 457 458 // know binding is now a ReferenceBinding 459 while (currentIndex < length) { 460 ReferenceBinding typeBinding = (ReferenceBinding) binding; 461 char[] nextName = compoundName[currentIndex++]; 462 invocationSite.setFieldIndex(currentIndex); 463 invocationSite.setActualReceiverType(typeBinding); 464 if ((mask & FIELD) != 0 465 && (binding = findField(typeBinding, nextName, 466 invocationSite)) != null) { 467 if (!binding.isValidBinding()) 468 return new ProblemFieldBinding( 469 ((FieldBinding) binding).declaringClass, 470 CharOperation.subarray(compoundName, 0, 471 currentIndex), binding.problemId()); 472 break; // binding is now a field 473 } 474 if ((binding = findMemberType(nextName, typeBinding)) == null) { 475 if ((mask & FIELD) != 0) { 476 return new ProblemBinding(CharOperation.subarray( 477 compoundName, 0, currentIndex), typeBinding, 478 NotFound); 479 } else { 480 return new ProblemReferenceBinding(CharOperation.subarray( 481 compoundName, 0, currentIndex), typeBinding, 482 NotFound); 483 } 484 } 485 if (!binding.isValidBinding()) 486 return new ProblemReferenceBinding(CharOperation.subarray( 487 compoundName, 0, currentIndex), binding.problemId()); 488 } 489 490 if ((mask & FIELD) != 0 && (binding instanceof FieldBinding)) { 491 // was looking for a field and found a field 492 FieldBinding field = (FieldBinding) binding; 493 if (!field.isStatic()) 494 return new ProblemFieldBinding(field.declaringClass, 495 CharOperation.subarray(compoundName, 0, currentIndex), 496 NonStaticReferenceInStaticContext); 497 return binding; 498 } 499 if ((mask & TYPE) != 0 && (binding instanceof ReferenceBinding)) { 500 // was looking for a type and found a type 501 return binding; 502 } 503 504 // handle the case when a field or type was asked for but we resolved 505 // the compoundName to a type or field 506 return new ProblemBinding(CharOperation.subarray(compoundName, 0, 507 currentIndex), NotFound); 508 } 509 510 // Added for code assist... NOT Public API getBinding(char[][] compoundName, InvocationSite invocationSite)511 public final Binding getBinding(char[][] compoundName, 512 InvocationSite invocationSite) { 513 int currentIndex = 0; 514 int length = compoundName.length; 515 Binding binding = getBinding(compoundName[currentIndex++], VARIABLE 516 | TYPE | PACKAGE, invocationSite); 517 if (!binding.isValidBinding()) 518 return binding; 519 520 foundType: if (binding instanceof PackageBinding) { 521 while (currentIndex < length) { 522 PackageBinding packageBinding = (PackageBinding) binding; 523 binding = packageBinding 524 .getTypeOrPackage(compoundName[currentIndex++]); 525 if (binding == null) { 526 if (currentIndex == length) 527 // must be a type if its the last name, otherwise we 528 // have no idea if its a package or type 529 return new ProblemReferenceBinding(CharOperation 530 .subarray(compoundName, 0, currentIndex), 531 NotFound); 532 else 533 return new ProblemBinding(CharOperation.subarray( 534 compoundName, 0, currentIndex), NotFound); 535 } 536 if (binding instanceof ReferenceBinding) { 537 if (!binding.isValidBinding()) 538 return new ProblemReferenceBinding(CharOperation 539 .subarray(compoundName, 0, currentIndex), 540 binding.problemId()); 541 if (!((ReferenceBinding) binding).canBeSeenBy(this)) 542 return new ProblemReferenceBinding(CharOperation 543 .subarray(compoundName, 0, currentIndex), 544 (ReferenceBinding) binding, NotVisible); 545 break foundType; 546 } 547 } 548 return binding; 549 } 550 551 foundField: if (binding instanceof ReferenceBinding) { 552 while (currentIndex < length) { 553 ReferenceBinding typeBinding = (ReferenceBinding) binding; 554 char[] nextName = compoundName[currentIndex++]; 555 if ((binding = findField(typeBinding, nextName, invocationSite)) != null) { 556 if (!binding.isValidBinding()) 557 return new ProblemFieldBinding( 558 ((FieldBinding) binding).declaringClass, 559 CharOperation.subarray(compoundName, 0, 560 currentIndex), binding.problemId()); 561 if (!((FieldBinding) binding).isStatic()) 562 return new ProblemFieldBinding( 563 ((FieldBinding) binding).declaringClass, 564 CharOperation.subarray(compoundName, 0, 565 currentIndex), 566 NonStaticReferenceInStaticContext); 567 break foundField; // binding is now a field 568 } 569 if ((binding = findMemberType(nextName, typeBinding)) == null) 570 return new ProblemBinding(CharOperation.subarray( 571 compoundName, 0, currentIndex), typeBinding, 572 NotFound); 573 if (!binding.isValidBinding()) 574 return new ProblemReferenceBinding(CharOperation.subarray( 575 compoundName, 0, currentIndex), binding.problemId()); 576 } 577 return binding; 578 } 579 580 VariableBinding variableBinding = (VariableBinding) binding; 581 while (currentIndex < length) { 582 TypeBinding typeBinding = variableBinding.type; 583 if (typeBinding == null) 584 return new ProblemFieldBinding(null, CharOperation.subarray( 585 compoundName, 0, currentIndex + 1), NotFound); 586 variableBinding = findField(typeBinding, 587 compoundName[currentIndex++], invocationSite); 588 if (variableBinding == null) 589 return new ProblemFieldBinding(null, CharOperation.subarray( 590 compoundName, 0, currentIndex), NotFound); 591 if (!variableBinding.isValidBinding()) 592 return variableBinding; 593 } 594 return variableBinding; 595 } 596 597 /* 598 * API 599 * 600 * Answer the binding that corresponds to the argument name. flag is a mask 601 * of the following values VARIABLE (= FIELD or LOCAL), TYPE, PACKAGE. Only 602 * bindings corresponding to the mask can be answered. 603 * 604 * For example, getBinding("foo", VARIABLE, site) will answer the binding 605 * for the field or local named "foo" (or an error binding if none exists). 606 * If a type named "foo" exists, it will not be detected (and an error 607 * binding will be answered) 608 * 609 * The VARIABLE mask has precedence over the TYPE mask. 610 * 611 * If the VARIABLE mask is not set, neither fields nor locals will be looked 612 * for. 613 * 614 * InvocationSite implements: isSuperAccess(); this is used to determine if 615 * the discovered field is visible. 616 * 617 * Limitations: cannot request FIELD independently of LOCAL, or vice versa 618 */ getBinding(char[] name, int mask, InvocationSite invocationSite)619 public Binding getBinding(char[] name, int mask, 620 InvocationSite invocationSite) { 621 622 Binding binding = null; 623 FieldBinding problemField = null; 624 if ((mask & VARIABLE) != 0) { 625 if (this.kind == BLOCK_SCOPE || this.kind == METHOD_SCOPE) { 626 LocalVariableBinding variableBinding = findVariable(name); 627 // looks in this scope only 628 if (variableBinding != null) 629 return variableBinding; 630 } 631 632 boolean insideStaticContext = false; 633 boolean insideConstructorCall = false; 634 if (this.kind == METHOD_SCOPE) { 635 MethodScope methodScope = (MethodScope) this; 636 insideStaticContext |= methodScope.isStatic; 637 insideConstructorCall |= methodScope.isConstructorCall; 638 } 639 640 FieldBinding foundField = null; 641 // can be a problem field which is answered if a valid field is not 642 // found 643 ProblemFieldBinding foundInsideProblem = null; 644 // inside Constructor call or inside static context 645 Scope scope = parent; 646 int depth = 0; 647 int foundDepth = 0; 648 ReferenceBinding foundActualReceiverType = null; 649 done: while (true) { // done when a COMPILATION_UNIT_SCOPE is 650 // found 651 switch (scope.kind) { 652 case METHOD_SCOPE: 653 MethodScope methodScope = (MethodScope) scope; 654 insideStaticContext |= methodScope.isStatic; 655 insideConstructorCall |= methodScope.isConstructorCall; 656 // Fall through... could duplicate the code below to save a 657 // cast - questionable optimization 658 case BLOCK_SCOPE: 659 LocalVariableBinding variableBinding = ((BlockScope) scope) 660 .findVariable(name); 661 // looks in this scope only 662 if (variableBinding != null) { 663 if (foundField != null && foundField.isValidBinding()) 664 return new ProblemFieldBinding( 665 foundField.declaringClass, name, 666 InheritedNameHidesEnclosingName); 667 if (depth > 0) 668 invocationSite.setDepth(depth); 669 return variableBinding; 670 } 671 break; 672 case CLASS_SCOPE: 673 ClassScope classScope = (ClassScope) scope; 674 SourceTypeBinding enclosingType = classScope.referenceContext.binding; 675 FieldBinding fieldBinding = classScope.findField( 676 enclosingType, name, invocationSite); 677 // Use next line instead if willing to enable protected 678 // access accross inner types 679 // FieldBinding fieldBinding = findField(enclosingType, 680 // name, invocationSite); 681 if (fieldBinding != null) { // skip it if we did not find 682 // anything 683 if (fieldBinding.problemId() == Ambiguous) { 684 if (foundField == null 685 || foundField.problemId() == NotVisible) 686 // supercedes any potential 687 // InheritedNameHidesEnclosingName problem 688 return fieldBinding; 689 else 690 // make the user qualify the field, likely wants 691 // the first inherited field (javac generates an 692 // ambiguous error instead) 693 return new ProblemFieldBinding( 694 fieldBinding.declaringClass, name, 695 InheritedNameHidesEnclosingName); 696 } 697 698 ProblemFieldBinding insideProblem = null; 699 if (fieldBinding.isValidBinding()) { 700 if (!fieldBinding.isStatic()) { 701 if (insideConstructorCall) { 702 insideProblem = new ProblemFieldBinding( 703 fieldBinding.declaringClass, name, 704 NonStaticReferenceInConstructorInvocation); 705 } else if (insideStaticContext) { 706 insideProblem = new ProblemFieldBinding( 707 fieldBinding.declaringClass, name, 708 NonStaticReferenceInStaticContext); 709 } 710 } 711 // if (enclosingType == fieldBinding.declaringClass 712 // || environment().options.complianceLevel >= 713 // CompilerOptions.JDK1_4){ 714 // // found a valid field in the 'immediate' scope 715 // (ie. not inherited) 716 // // OR in 1.4 mode (inherited shadows enclosing) 717 // if (foundField == null) { 718 // if (depth > 0){ 719 // invocationSite.setDepth(depth); 720 // invocationSite.setActualReceiverType(enclosingType); 721 // } 722 // // return the fieldBinding if it is not declared 723 // in a superclass of the scope's binding (that is, 724 // inherited) 725 // return insideProblem == null ? fieldBinding : 726 // insideProblem; 727 // } 728 // if (foundField.isValidBinding()) 729 // // if a valid field was found, complain when 730 // another is found in an 'immediate' enclosing type 731 // (that is, not inherited) 732 // if (foundField.declaringClass != 733 // fieldBinding.declaringClass) 734 // // ie. have we found the same field - do not 735 // trust field identity yet 736 // return new ProblemFieldBinding( 737 // fieldBinding.declaringClass, 738 // name, 739 // InheritedNameHidesEnclosingName); 740 // } 741 } 742 743 if (foundField == null 744 || (foundField.problemId() == NotVisible && fieldBinding 745 .problemId() != NotVisible)) { 746 // only remember the fieldBinding if its the first 747 // one found or the previous one was not visible & 748 // fieldBinding is... 749 foundDepth = depth; 750 foundActualReceiverType = enclosingType; 751 foundInsideProblem = insideProblem; 752 foundField = fieldBinding; 753 } 754 } 755 depth++; 756 insideStaticContext |= enclosingType.isStatic(); 757 // 1EX5I8Z - accessing outer fields within a constructor 758 // call is permitted 759 // in order to do so, we change the flag as we exit from the 760 // type, not the method 761 // itself, because the class scope is used to retrieve the 762 // fields. 763 MethodScope enclosingMethodScope = scope.methodScope(); 764 insideConstructorCall = enclosingMethodScope == null ? false 765 : enclosingMethodScope.isConstructorCall; 766 break; 767 case COMPILATION_UNIT_SCOPE: 768 break done; 769 } 770 scope = scope.parent; 771 } 772 773 if (foundInsideProblem != null) { 774 return foundInsideProblem; 775 } 776 if (foundField != null) { 777 if (foundField.isValidBinding()) { 778 if (foundDepth > 0) { 779 invocationSite.setDepth(foundDepth); 780 invocationSite 781 .setActualReceiverType(foundActualReceiverType); 782 } 783 return foundField; 784 } 785 problemField = foundField; 786 } 787 } 788 789 // We did not find a local or instance variable. 790 if ((mask & TYPE) != 0) { 791 if ((binding = getBaseType(name)) != null) 792 return binding; 793 binding = getTypeOrPackage(name, (mask & PACKAGE) == 0 ? TYPE 794 : TYPE | PACKAGE); 795 if (binding.isValidBinding() || mask == TYPE) 796 return binding; 797 // answer the problem type binding if we are only looking for a type 798 } else if ((mask & PACKAGE) != 0) { 799 compilationUnitScope().recordSimpleReference(name); 800 if ((binding = environment().getTopLevelPackage(name)) != null) 801 return binding; 802 } 803 if (problemField != null) 804 return problemField; 805 else 806 return new ProblemBinding(name, enclosingSourceType(), NotFound); 807 } 808 809 /* 810 * API 811 * 812 * Answer the constructor binding that corresponds to receiverType, 813 * argumentTypes. 814 * 815 * InvocationSite implements isSuperAccess(); this is used to determine if 816 * the discovered constructor is visible. 817 * 818 * If no visible constructor is discovered, an error binding is answered. 819 */ getConstructor(ReferenceBinding receiverType, TypeBinding[] argumentTypes, InvocationSite invocationSite)820 public MethodBinding getConstructor(ReferenceBinding receiverType, 821 TypeBinding[] argumentTypes, InvocationSite invocationSite) { 822 823 compilationUnitScope().recordTypeReference(receiverType); 824 compilationUnitScope().recordTypeReferences(argumentTypes); 825 MethodBinding methodBinding = receiverType 826 .getExactConstructor(argumentTypes); 827 if (methodBinding != null) { 828 if (methodBinding.canBeSeenBy(invocationSite, this)) 829 return methodBinding; 830 } 831 MethodBinding[] methods = receiverType 832 .getMethods(ConstructorDeclaration.ConstantPoolName); 833 if (methods == NoMethods) { 834 return new ProblemMethodBinding( 835 ConstructorDeclaration.ConstantPoolName, argumentTypes, 836 NotFound); 837 } 838 MethodBinding[] compatible = new MethodBinding[methods.length]; 839 int compatibleIndex = 0; 840 for (int i = 0, length = methods.length; i < length; i++) 841 if (areParametersAssignable(methods[i].parameters, argumentTypes)) 842 compatible[compatibleIndex++] = methods[i]; 843 if (compatibleIndex == 0) 844 return new ProblemMethodBinding( 845 ConstructorDeclaration.ConstantPoolName, argumentTypes, 846 NotFound); 847 // need a more descriptive error... cannot convert from X to Y 848 849 MethodBinding[] visible = new MethodBinding[compatibleIndex]; 850 int visibleIndex = 0; 851 for (int i = 0; i < compatibleIndex; i++) { 852 MethodBinding method = compatible[i]; 853 if (method.canBeSeenBy(invocationSite, this)) 854 visible[visibleIndex++] = method; 855 } 856 if (visibleIndex == 1) 857 return visible[0]; 858 if (visibleIndex == 0) 859 return new ProblemMethodBinding(compatible[0], 860 ConstructorDeclaration.ConstantPoolName, 861 compatible[0].parameters, NotVisible); 862 return mostSpecificClassMethodBinding(visible, visibleIndex); 863 } 864 865 /* 866 * This retrieves the argument that maps to an enclosing instance of the 867 * suitable type, if not found then answers nil -- do not create one 868 * 869 * #implicitThis : the implicit this will be ok #((arg) this$n) : available 870 * as a constructor arg #((arg) this$n ... this$p) : available as as a 871 * constructor arg + a sequence of fields #((fieldDescr) this$n ... this$p) : 872 * available as a sequence of fields nil : not found 873 * 874 * Note that this algorithm should answer the shortest possible sequence 875 * when shortcuts are available: this$0 . this$0 . this$0 instead of this$2 . 876 * this$1 . this$0 . this$1 . this$0 thus the code generation will be more 877 * compact and runtime faster 878 */ getEmulationPath( LocalVariableBinding outerLocalVariable)879 public VariableBinding[] getEmulationPath( 880 LocalVariableBinding outerLocalVariable) { 881 882 MethodScope currentMethodScope = this.methodScope(); 883 SourceTypeBinding sourceType = currentMethodScope.enclosingSourceType(); 884 885 // identity check 886 if (currentMethodScope == outerLocalVariable.declaringScope 887 .methodScope()) { 888 return new VariableBinding[] { outerLocalVariable }; 889 // implicit this is good enough 890 } 891 // use synthetic constructor arguments if possible 892 if (currentMethodScope.isInsideInitializerOrConstructor() 893 && (sourceType.isNestedType())) { 894 SyntheticArgumentBinding syntheticArg; 895 if ((syntheticArg = ((NestedTypeBinding) sourceType) 896 .getSyntheticArgument(outerLocalVariable)) != null) { 897 return new VariableBinding[] { syntheticArg }; 898 } 899 } 900 // use a synthetic field then 901 if (!currentMethodScope.isStatic) { 902 FieldBinding syntheticField; 903 if ((syntheticField = sourceType 904 .getSyntheticField(outerLocalVariable)) != null) { 905 return new VariableBinding[] { syntheticField }; 906 } 907 } 908 return null; 909 } 910 911 /* 912 * This retrieves the argument that maps to an enclosing instance of the 913 * suitable type, if not found then answers nil -- do not create one 914 * 915 * #implicitThis : the implicit this will be ok #((arg) this$n) : available 916 * as a constructor arg #((arg) this$n access$m... access$p) : available as 917 * as a constructor arg + a sequence of synthetic accessors to synthetic 918 * fields #((fieldDescr) this$n access#m... access$p) : available as a first 919 * synthetic field + a sequence of synthetic accessors to synthetic fields 920 * nil : not found jls 15.9.2 921 */ getEmulationPath(ReferenceBinding targetEnclosingType, boolean onlyExactMatch, boolean ignoreEnclosingArgInConstructorCall)922 public Object[] getEmulationPath(ReferenceBinding targetEnclosingType, 923 boolean onlyExactMatch, boolean ignoreEnclosingArgInConstructorCall) { 924 // TODO: (philippe) investigate why exactly test76 fails if 925 // ignoreEnclosingArgInConstructorCall is always false 926 MethodScope currentMethodScope = this.methodScope(); 927 SourceTypeBinding sourceType = currentMethodScope.enclosingSourceType(); 928 929 // identity check 930 if (!currentMethodScope.isStatic 931 && (!currentMethodScope.isConstructorCall || ignoreEnclosingArgInConstructorCall) 932 && (sourceType == targetEnclosingType || (!onlyExactMatch && targetEnclosingType 933 .isSuperclassOf(sourceType)))) { 934 if (currentMethodScope.isConstructorCall) { 935 return NoEnclosingInstanceInConstructorCall; 936 } 937 if (currentMethodScope.isStatic) { 938 return NoEnclosingInstanceInStaticContext; 939 } 940 return EmulationPathToImplicitThis; // implicit this is good enough 941 } 942 if (!sourceType.isNestedType() || sourceType.isStatic()) { // no 943 // emulation 944 // from 945 // within 946 // non-inner 947 // types 948 if (currentMethodScope.isConstructorCall) { 949 return NoEnclosingInstanceInConstructorCall; 950 } 951 if (currentMethodScope.isStatic) { 952 return NoEnclosingInstanceInStaticContext; 953 } 954 return null; 955 } 956 boolean insideConstructor = currentMethodScope 957 .isInsideInitializerOrConstructor(); 958 // use synthetic constructor arguments if possible 959 if (insideConstructor) { 960 SyntheticArgumentBinding syntheticArg; 961 if ((syntheticArg = ((NestedTypeBinding) sourceType) 962 .getSyntheticArgument(targetEnclosingType, onlyExactMatch)) != null) { 963 return new Object[] { syntheticArg }; 964 } 965 } 966 967 // use a direct synthetic field then 968 if (currentMethodScope.isStatic) { 969 return NoEnclosingInstanceInStaticContext; 970 } 971 FieldBinding syntheticField = sourceType.getSyntheticField( 972 targetEnclosingType, onlyExactMatch); 973 if (syntheticField != null) { 974 if (currentMethodScope.isConstructorCall) { 975 return NoEnclosingInstanceInConstructorCall; 976 } 977 return new Object[] { syntheticField }; 978 } 979 // could be reached through a sequence of enclosing instance link 980 // (nested members) 981 Object[] path = new Object[2]; // probably at least 2 of them 982 ReferenceBinding currentType = sourceType.enclosingType(); 983 if (insideConstructor) { 984 path[0] = ((NestedTypeBinding) sourceType).getSyntheticArgument( 985 (SourceTypeBinding) currentType, onlyExactMatch); 986 } else { 987 if (currentMethodScope.isConstructorCall) { 988 return NoEnclosingInstanceInConstructorCall; 989 } 990 path[0] = sourceType.getSyntheticField( 991 (SourceTypeBinding) currentType, onlyExactMatch); 992 } 993 if (path[0] != null) { // keep accumulating 994 995 int count = 1; 996 ReferenceBinding currentEnclosingType; 997 while ((currentEnclosingType = currentType.enclosingType()) != null) { 998 999 // done? 1000 if (currentType == targetEnclosingType 1001 || (!onlyExactMatch && targetEnclosingType 1002 .isSuperclassOf(currentType))) 1003 break; 1004 1005 if (currentMethodScope != null) { 1006 currentMethodScope = currentMethodScope 1007 .enclosingMethodScope(); 1008 if (currentMethodScope != null 1009 && currentMethodScope.isConstructorCall) { 1010 return NoEnclosingInstanceInConstructorCall; 1011 } 1012 if (currentMethodScope != null 1013 && currentMethodScope.isStatic) { 1014 return NoEnclosingInstanceInStaticContext; 1015 } 1016 } 1017 1018 syntheticField = ((NestedTypeBinding) currentType) 1019 .getSyntheticField( 1020 (SourceTypeBinding) currentEnclosingType, 1021 onlyExactMatch); 1022 if (syntheticField == null) 1023 break; 1024 1025 // append inside the path 1026 if (count == path.length) { 1027 System.arraycopy(path, 0, (path = new Object[count + 1]), 1028 0, count); 1029 } 1030 // private access emulation is necessary since synthetic field 1031 // is private 1032 path[count++] = ((SourceTypeBinding) syntheticField.declaringClass) 1033 .addSyntheticMethod(syntheticField, true); 1034 currentType = currentEnclosingType; 1035 } 1036 if (currentType == targetEnclosingType 1037 || (!onlyExactMatch && targetEnclosingType 1038 .isSuperclassOf(currentType))) { 1039 return path; 1040 } 1041 } 1042 return null; 1043 } 1044 1045 /* 1046 * API 1047 * 1048 * Answer the field binding that corresponds to fieldName. Start the lookup 1049 * at the receiverType. InvocationSite implements isSuperAccess(); this is 1050 * used to determine if the discovered field is visible. Only fields defined 1051 * by the receiverType or its supertypes are answered; a field of an 1052 * enclosing type will not be found using this API. 1053 * 1054 * If no visible field is discovered, an error binding is answered. 1055 */ getField(TypeBinding receiverType, char[] fieldName, InvocationSite invocationSite)1056 public FieldBinding getField(TypeBinding receiverType, char[] fieldName, 1057 InvocationSite invocationSite) { 1058 1059 FieldBinding field = findField(receiverType, fieldName, invocationSite); 1060 if (field == null) 1061 return new ProblemFieldBinding( 1062 receiverType instanceof ReferenceBinding ? (ReferenceBinding) receiverType 1063 : null, fieldName, NotFound); 1064 else 1065 return field; 1066 } 1067 1068 /* 1069 * API 1070 * 1071 * Answer the method binding that corresponds to selector, argumentTypes. 1072 * Start the lookup at the enclosing type of the receiver. InvocationSite 1073 * implements isSuperAccess(); this is used to determine if the discovered 1074 * method is visible. setDepth(int); this is used to record the depth of the 1075 * discovered method relative to the enclosing type of the receiver. (If the 1076 * method is defined in the enclosing type of the receiver, the depth is 0; 1077 * in the next enclosing type, the depth is 1; and so on 1078 * 1079 * If no visible method is discovered, an error binding is answered. 1080 */ getImplicitMethod(char[] selector, TypeBinding[] argumentTypes, InvocationSite invocationSite)1081 public MethodBinding getImplicitMethod(char[] selector, 1082 TypeBinding[] argumentTypes, InvocationSite invocationSite) { 1083 1084 boolean insideStaticContext = false; 1085 boolean insideConstructorCall = false; 1086 MethodBinding foundMethod = null; 1087 ProblemMethodBinding foundFuzzyProblem = null; 1088 // the weird method lookup case (matches method name in scope, then arg 1089 // types, then visibility) 1090 ProblemMethodBinding foundInsideProblem = null; 1091 // inside Constructor call or inside static context 1092 Scope scope = this; 1093 int depth = 0; 1094 done: while (true) { // done when a COMPILATION_UNIT_SCOPE is found 1095 switch (scope.kind) { 1096 case METHOD_SCOPE: 1097 MethodScope methodScope = (MethodScope) scope; 1098 insideStaticContext |= methodScope.isStatic; 1099 insideConstructorCall |= methodScope.isConstructorCall; 1100 break; 1101 case CLASS_SCOPE: 1102 ClassScope classScope = (ClassScope) scope; 1103 SourceTypeBinding receiverType = classScope.referenceContext.binding; 1104 boolean isExactMatch = true; 1105 // retrieve an exact visible match (if possible) 1106 MethodBinding methodBinding = (foundMethod == null) ? classScope 1107 .findExactMethod(receiverType, selector, argumentTypes, 1108 invocationSite) 1109 : classScope.findExactMethod(receiverType, 1110 foundMethod.selector, foundMethod.parameters, 1111 invocationSite); 1112 // ? findExactMethod(receiverType, selector, argumentTypes, 1113 // invocationSite) 1114 // : findExactMethod(receiverType, foundMethod.selector, 1115 // foundMethod.parameters, invocationSite); 1116 if (methodBinding == null) { 1117 // answers closest approximation, may not check 1118 // argumentTypes or visibility 1119 isExactMatch = false; 1120 methodBinding = classScope.findMethod(receiverType, 1121 selector, argumentTypes, invocationSite); 1122 // methodBinding = findMethod(receiverType, selector, 1123 // argumentTypes, invocationSite); 1124 } 1125 if (methodBinding != null) { // skip it if we did not find 1126 // anything 1127 if (methodBinding.problemId() == Ambiguous) { 1128 if (foundMethod == null 1129 || foundMethod.problemId() == NotVisible) 1130 // supercedes any potential 1131 // InheritedNameHidesEnclosingName problem 1132 return methodBinding; 1133 else 1134 // make the user qualify the method, likely wants 1135 // the first inherited method (javac generates an 1136 // ambiguous error instead) 1137 return new ProblemMethodBinding(selector, 1138 argumentTypes, 1139 InheritedNameHidesEnclosingName); 1140 } 1141 1142 ProblemMethodBinding fuzzyProblem = null; 1143 ProblemMethodBinding insideProblem = null; 1144 if (methodBinding.isValidBinding()) { 1145 if (!isExactMatch) { 1146 if (!areParametersAssignable( 1147 methodBinding.parameters, argumentTypes)) { 1148 if (foundMethod == null 1149 || foundMethod.problemId() == NotVisible) { 1150 // inherited mismatch is reported directly, 1151 // not looking at enclosing matches 1152 return new ProblemMethodBinding( 1153 methodBinding, selector, 1154 argumentTypes, NotFound); 1155 } 1156 // make the user qualify the method, likely 1157 // wants the first inherited method (javac 1158 // generates an ambiguous error instead) 1159 fuzzyProblem = new ProblemMethodBinding( 1160 selector, methodBinding.parameters, 1161 InheritedNameHidesEnclosingName); 1162 1163 } else if (!methodBinding.canBeSeenBy(receiverType, 1164 invocationSite, classScope)) { 1165 // using <classScope> instead of <this> for 1166 // visibility check does grant all access to 1167 // innerclass 1168 fuzzyProblem = new ProblemMethodBinding( 1169 methodBinding, selector, 1170 methodBinding.parameters, NotVisible); 1171 } 1172 } 1173 if (fuzzyProblem == null && !methodBinding.isStatic()) { 1174 if (insideConstructorCall) { 1175 insideProblem = new ProblemMethodBinding( 1176 methodBinding.selector, 1177 methodBinding.parameters, 1178 NonStaticReferenceInConstructorInvocation); 1179 } else if (insideStaticContext) { 1180 insideProblem = new ProblemMethodBinding( 1181 methodBinding.selector, 1182 methodBinding.parameters, 1183 NonStaticReferenceInStaticContext); 1184 } 1185 } 1186 1187 // if (receiverType == methodBinding.declaringClass 1188 // || (receiverType.getMethods(selector)) != NoMethods 1189 // || ((fuzzyProblem == null || fuzzyProblem.problemId() 1190 // != NotVisible) && 1191 // environment().options.complianceLevel >= 1192 // CompilerOptions.JDK1_4)){ 1193 // // found a valid method in the 'immediate' scope (ie. 1194 // not inherited) 1195 // // OR the receiverType implemented a method with the 1196 // correct name 1197 // // OR in 1.4 mode (inherited visible shadows 1198 // enclosing) 1199 // if (foundMethod == null) { 1200 // if (depth > 0){ 1201 // invocationSite.setDepth(depth); 1202 // invocationSite.setActualReceiverType(receiverType); 1203 // } 1204 // // return the methodBinding if it is not declared in 1205 // a superclass of the scope's binding (that is, 1206 // inherited) 1207 // if (fuzzyProblem != null) 1208 // return fuzzyProblem; 1209 // if (insideProblem != null) 1210 // return insideProblem; 1211 // return methodBinding; 1212 // } 1213 // // if a method was found, complain when another is 1214 // found in an 'immediate' enclosing type (that is, not 1215 // inherited) 1216 // // NOTE: Unlike fields, a non visible method hides a 1217 // visible method 1218 // if (foundMethod.declaringClass != 1219 // methodBinding.declaringClass) 1220 // // ie. have we found the same method - do not trust 1221 // field identity yet 1222 // return new ProblemMethodBinding( 1223 // methodBinding.selector, 1224 // methodBinding.parameters, 1225 // InheritedNameHidesEnclosingName); 1226 // } 1227 } 1228 1229 if (foundMethod == null 1230 || (foundMethod.problemId() == NotVisible && methodBinding 1231 .problemId() != NotVisible)) { 1232 // only remember the methodBinding if its the first one 1233 // found or the previous one was not visible & 1234 // methodBinding is... 1235 // remember that private methods are visible if defined 1236 // directly by an enclosing class 1237 if (depth > 0) { 1238 invocationSite.setDepth(depth); 1239 invocationSite.setActualReceiverType(receiverType); 1240 } 1241 foundFuzzyProblem = fuzzyProblem; 1242 foundInsideProblem = insideProblem; 1243 if (fuzzyProblem == null) 1244 foundMethod = methodBinding; // only keep it if 1245 // no error was 1246 // found 1247 } 1248 } 1249 depth++; 1250 insideStaticContext |= receiverType.isStatic(); 1251 // 1EX5I8Z - accessing outer fields within a constructor call is 1252 // permitted 1253 // in order to do so, we change the flag as we exit from the 1254 // type, not the method 1255 // itself, because the class scope is used to retrieve the 1256 // fields. 1257 MethodScope enclosingMethodScope = scope.methodScope(); 1258 insideConstructorCall = enclosingMethodScope == null ? false 1259 : enclosingMethodScope.isConstructorCall; 1260 break; 1261 case COMPILATION_UNIT_SCOPE: 1262 break done; 1263 } 1264 scope = scope.parent; 1265 } 1266 1267 if (foundFuzzyProblem != null) 1268 return foundFuzzyProblem; 1269 if (foundInsideProblem != null) 1270 return foundInsideProblem; 1271 if (foundMethod != null) 1272 return foundMethod; 1273 return new ProblemMethodBinding(selector, argumentTypes, NotFound); 1274 } 1275 1276 /* 1277 * API 1278 * 1279 * Answer the method binding that corresponds to selector, argumentTypes. 1280 * Start the lookup at the receiverType. InvocationSite implements 1281 * isSuperAccess(); this is used to determine if the discovered method is 1282 * visible. 1283 * 1284 * Only methods defined by the receiverType or its supertypes are answered; 1285 * use getImplicitMethod() to discover methods of enclosing types. 1286 * 1287 * If no visible method is discovered, an error binding is answered. 1288 */ getMethod(TypeBinding receiverType, char[] selector, TypeBinding[] argumentTypes, InvocationSite invocationSite)1289 public MethodBinding getMethod(TypeBinding receiverType, char[] selector, 1290 TypeBinding[] argumentTypes, InvocationSite invocationSite) { 1291 1292 if (receiverType.isArrayType()) 1293 return findMethodForArray((ArrayBinding) receiverType, selector, 1294 argumentTypes, invocationSite); 1295 if (receiverType.isBaseType()) 1296 return new ProblemMethodBinding(selector, argumentTypes, NotFound); 1297 1298 ReferenceBinding currentType = (ReferenceBinding) receiverType; 1299 if (!currentType.canBeSeenBy(this)) 1300 return new ProblemMethodBinding(selector, argumentTypes, 1301 ReceiverTypeNotVisible); 1302 1303 // retrieve an exact visible match (if possible) 1304 MethodBinding methodBinding = findExactMethod(currentType, selector, 1305 argumentTypes, invocationSite); 1306 if (methodBinding != null) 1307 return methodBinding; 1308 1309 // answers closest approximation, may not check argumentTypes or 1310 // visibility 1311 methodBinding = findMethod(currentType, selector, argumentTypes, 1312 invocationSite); 1313 if (methodBinding == null) 1314 return new ProblemMethodBinding(selector, argumentTypes, NotFound); 1315 if (methodBinding.isValidBinding()) { 1316 if (!areParametersAssignable(methodBinding.parameters, 1317 argumentTypes)) 1318 return new ProblemMethodBinding(methodBinding, selector, 1319 argumentTypes, NotFound); 1320 if (!methodBinding.canBeSeenBy(currentType, invocationSite, this)) 1321 return new ProblemMethodBinding(methodBinding, selector, 1322 methodBinding.parameters, NotVisible); 1323 } 1324 return methodBinding; 1325 } 1326 maxShiftedOffset()1327 public int maxShiftedOffset() { 1328 int max = -1; 1329 if (this.shiftScopes != null) { 1330 for (int i = 0, length = this.shiftScopes.length; i < length; i++) { 1331 int subMaxOffset = this.shiftScopes[i].maxOffset; 1332 if (subMaxOffset > max) 1333 max = subMaxOffset; 1334 } 1335 } 1336 return max; 1337 } 1338 1339 /* 1340 * Answer the problem reporter to use for raising new problems. 1341 * 1342 * Note that as a side-effect, this updates the current reference context 1343 * (unit, type or method) in case the problem handler decides it is 1344 * necessary to abort. 1345 */ problemReporter()1346 public ProblemReporter problemReporter() { 1347 1348 return outerMostMethodScope().problemReporter(); 1349 } 1350 1351 /* 1352 * Code responsible to request some more emulation work inside the 1353 * invocation type, so as to supply correct synthetic arguments to any 1354 * allocation of the target type. 1355 */ propagateInnerEmulation(ReferenceBinding targetType, boolean isEnclosingInstanceSupplied)1356 public void propagateInnerEmulation(ReferenceBinding targetType, 1357 boolean isEnclosingInstanceSupplied) { 1358 1359 // no need to propagate enclosing instances, they got eagerly allocated 1360 // already. 1361 1362 SyntheticArgumentBinding[] syntheticArguments; 1363 if ((syntheticArguments = targetType.syntheticOuterLocalVariables()) != null) { 1364 for (int i = 0, max = syntheticArguments.length; i < max; i++) { 1365 SyntheticArgumentBinding syntheticArg = syntheticArguments[i]; 1366 // need to filter out the one that could match a supplied 1367 // enclosing instance 1368 if (!(isEnclosingInstanceSupplied && (syntheticArg.type == targetType 1369 .enclosingType()))) { 1370 this 1371 .emulateOuterAccess(syntheticArg.actualOuterLocalVariable); 1372 } 1373 } 1374 } 1375 } 1376 1377 /* 1378 * Answer the reference type of this scope. 1379 * 1380 * It is the nearest enclosing type of this scope. 1381 */ referenceType()1382 public TypeDeclaration referenceType() { 1383 1384 return methodScope().referenceType(); 1385 } 1386 1387 // start position in this scope - for ordering scopes vs. variables startIndex()1388 int startIndex() { 1389 return startIndex; 1390 } 1391 toString()1392 public String toString() { 1393 return toString(0); 1394 } 1395 toString(int tab)1396 public String toString(int tab) { 1397 1398 String s = basicToString(tab); 1399 for (int i = 0; i < scopeIndex; i++) 1400 if (subscopes[i] instanceof BlockScope) 1401 s += ((BlockScope) subscopes[i]).toString(tab + 1) + "\n"; //$NON-NLS-1$ 1402 return s; 1403 } 1404 } 1405