1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.lookup;
13 import org.eclipse.jdt.core.compiler.CharOperation;
14 import org.eclipse.jdt.internal.compiler.ast.*;
15 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
16 import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
17 import org.eclipse.jdt.internal.compiler.impl.Constant;
18 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
20 public class BlockScope extends Scope {
22 // Local variable management
23 public LocalVariableBinding[] locals;
24 public int localIndex; // position for next variable
25 public int startIndex; // start position in this scope - for ordering scopes vs. variables
26 public int offset; // for variable allocation throughout scopes
27 public int maxOffset; // for variable allocation throughout scopes
29 // finally scopes must be shifted behind respective try&catch scope(s) so as to avoid
30 // collisions of secret variables (return address, save value).
31 public BlockScope[] shiftScopes;
33 public final static VariableBinding[] EmulationPathToImplicitThis = {};
34 public final static VariableBinding[] NoEnclosingInstanceInConstructorCall = {};
35 public final static VariableBinding[] NoEnclosingInstanceInStaticContext = {};
37 public Scope[] subscopes = new Scope[1]; // need access from code assist
38 public int subscopeCount = 0; // need access from code assist
40 // record the current case statement being processed (for entire switch case block).
41 public CaseStatement switchCase; // from 1.4 on, local types should not be accessed across switch case blocks (52221)
43 protected BlockScope(int kind, Scope parent) {
48 public BlockScope(BlockScope parent) {
53 public BlockScope(BlockScope parent, boolean addToParentScope) {
55 this(BLOCK_SCOPE, parent);
56 locals = new LocalVariableBinding[5];
57 if (addToParentScope) parent.addSubscope(this);
58 this.startIndex = parent.localIndex;
61 public BlockScope(BlockScope parent, int variableCount) {
63 this(BLOCK_SCOPE, parent);
64 locals = new LocalVariableBinding[variableCount];
65 parent.addSubscope(this);
66 this.startIndex = parent.localIndex;
69 /* Create the class scope & binding for the anonymous type.
71 public final void addAnonymousType(
72 TypeDeclaration anonymousType,
73 ReferenceBinding superBinding) {
75 ClassScope anonymousClassScope = new ClassScope(this, anonymousType);
76 anonymousClassScope.buildAnonymousTypeBinding(
77 enclosingSourceType(),
81 /* Create the class scope & binding for the local type.
83 public final void addLocalType(TypeDeclaration localType) {
85 // check that the localType does not conflict with an enclosing type
86 ReferenceBinding type = enclosingSourceType();
88 if (CharOperation.equals(type.sourceName, localType.name)) {
89 problemReporter().hidingEnclosingType(localType);
92 type = type.enclosingType();
93 } while (type != null);
95 // check that the localType does not conflict with another sibling local type
98 if (((BlockScope) scope).findLocalType(localType.name) != null) {
99 problemReporter().duplicateNestedType(localType);
102 } while ((scope = scope.parent) instanceof BlockScope);
104 ClassScope localTypeScope = new ClassScope(this, localType);
105 addSubscope(localTypeScope);
106 localTypeScope.buildLocalTypeBinding(enclosingSourceType());
109 /* Insert a local variable into a given scope, updating its position
110 * and checking there are not too many locals or arguments allocated.
112 public final void addLocalVariable(LocalVariableBinding binding) {
114 checkAndSetModifiersForVariable(binding);
116 // insert local in scope
117 if (localIndex == locals.length)
121 (locals = new LocalVariableBinding[localIndex * 2]),
124 locals[localIndex++] = binding;
126 // update local variable binding
127 binding.declaringScope = this;
128 binding.id = this.outerMostMethodScope().analysisIndex++;
129 // share the outermost method scope analysisIndex
132 public void addSubscope(Scope childScope) {
133 if (subscopeCount == subscopes.length)
137 (subscopes = new Scope[subscopeCount * 2]),
140 subscopes[subscopeCount++] = childScope;
143 /* Answer true if the receiver is suitable for assigning final blank fields.
145 * in other words, it is inside an initializer, a constructor or a clinit
147 public final boolean allowBlankFinalFieldAssignment(FieldBinding binding) {
149 if (enclosingSourceType() != binding.declaringClass)
152 MethodScope methodScope = methodScope();
153 if (methodScope.isStatic != binding.isStatic())
155 return methodScope.isInsideInitializer() // inside initializer
156 || ((AbstractMethodDeclaration) methodScope.referenceContext)
157 .isInitializationMethod(); // inside constructor or clinit
159 String basicToString(int tab) {
160 String newLine = "\n"; //$NON-NLS-1$
161 for (int i = tab; --i >= 0;)
162 newLine += "\t"; //$NON-NLS-1$
164 String s = newLine + "--- Block Scope ---"; //$NON-NLS-1$
165 newLine += "\t"; //$NON-NLS-1$
166 s += newLine + "locals:"; //$NON-NLS-1$
167 for (int i = 0; i < localIndex; i++)
168 s += newLine + "\t" + locals[i].toString(); //$NON-NLS-1$
169 s += newLine + "startIndex = " + startIndex; //$NON-NLS-1$
173 private void checkAndSetModifiersForVariable(LocalVariableBinding varBinding) {
175 int modifiers = varBinding.modifiers;
176 if ((modifiers & AccAlternateModifierProblem) != 0 && varBinding.declaration != null){
177 problemReporter().duplicateModifierForVariable(varBinding.declaration, this instanceof MethodScope);
179 int realModifiers = modifiers & AccJustFlag;
181 int unexpectedModifiers = ~AccFinal;
182 if ((realModifiers & unexpectedModifiers) != 0 && varBinding.declaration != null){
183 problemReporter().illegalModifierForVariable(varBinding.declaration, this instanceof MethodScope);
185 varBinding.modifiers = modifiers;
188 /* Compute variable positions in scopes given an initial position offset
189 * ignoring unused local variables.
191 * No argument is expected here (ilocal is the first non-argument local of the outermost scope)
192 * Arguments are managed by the MethodScope method
194 void computeLocalVariablePositions(int ilocal, int initOffset, CodeStream codeStream) {
196 this.offset = initOffset;
197 this.maxOffset = initOffset;
199 // local variable init
200 int maxLocals = this.localIndex;
201 boolean hasMoreVariables = ilocal < maxLocals;
204 int iscope = 0, maxScopes = this.subscopeCount;
205 boolean hasMoreScopes = maxScopes > 0;
207 // iterate scopes and variables in parallel
208 while (hasMoreVariables || hasMoreScopes) {
210 && (!hasMoreVariables || (subscopes[iscope].startIndex() <= ilocal))) {
211 // consider subscope first
212 if (subscopes[iscope] instanceof BlockScope) {
213 BlockScope subscope = (BlockScope) subscopes[iscope];
214 int subOffset = subscope.shiftScopes == null ? this.offset : subscope.maxShiftedOffset();
215 subscope.computeLocalVariablePositions(0, subOffset, codeStream);
216 if (subscope.maxOffset > this.maxOffset)
217 this.maxOffset = subscope.maxOffset;
219 hasMoreScopes = ++iscope < maxScopes;
222 // consider variable first
223 LocalVariableBinding local = locals[ilocal]; // if no local at all, will be locals[ilocal]==null
225 // check if variable is actually used, and may force it to be preserved
226 boolean generateCurrentLocalVar = (local.useFlag == LocalVariableBinding.USED && (local.constant == Constant.NotAConstant));
228 // do not report fake used variable
229 if (local.useFlag == LocalVariableBinding.UNUSED
230 && (local.declaration != null) // unused (and non secret) local
231 && ((local.declaration.bits & ASTNode.IsLocalDeclarationReachableMASK) != 0)) { // declaration is reachable
233 if (!(local.declaration instanceof Argument)) // do not report unused catch arguments
234 this.problemReporter().unusedLocalVariable(local.declaration);
237 // could be optimized out, but does need to preserve unread variables ?
238 if (!generateCurrentLocalVar) {
239 if (local.declaration != null && environment().options.preserveAllLocalVariables) {
240 generateCurrentLocalVar = true; // force it to be preserved in the generated code
241 local.useFlag = LocalVariableBinding.USED;
246 if (generateCurrentLocalVar) {
248 if (local.declaration != null) {
249 codeStream.record(local); // record user-defined local variables for attribute generation
251 // assign variable position
252 local.resolvedPosition = this.offset;
254 if ((local.type == LongBinding) || (local.type == DoubleBinding)) {
259 if (this.offset > 0xFFFF) { // no more than 65535 words of locals
260 this.problemReporter().noMoreAvailableSpaceForLocal(
262 local.declaration == null ? (ASTNode)this.methodScope().referenceContext : local.declaration);
265 local.resolvedPosition = -1; // not generated
267 hasMoreVariables = ++ilocal < maxLocals;
270 if (this.offset > this.maxOffset)
271 this.maxOffset = this.offset;
275 * Record the suitable binding denoting a synthetic field or constructor argument,
276 * mapping to the actual outer local variable in the scope context.
277 * Note that this may not need any effect, in case the outer local variable does not
278 * need to be emulated and can directly be used as is (using its back pointer to its
281 public void emulateOuterAccess(LocalVariableBinding outerLocalVariable) {
283 MethodScope currentMethodScope;
284 if ((currentMethodScope = this.methodScope())
285 != outerLocalVariable.declaringScope.methodScope()) {
286 NestedTypeBinding currentType = (NestedTypeBinding) this.enclosingSourceType();
288 //do nothing for member types, pre emulation was performed already
289 if (!currentType.isLocalType()) {
292 // must also add a synthetic field if we're not inside a constructor
293 if (!currentMethodScope.isInsideInitializerOrConstructor()) {
294 currentType.addSyntheticArgumentAndField(outerLocalVariable);
296 currentType.addSyntheticArgument(outerLocalVariable);
301 /* Note that it must never produce a direct access to the targetEnclosingType,
302 * but instead a field sequence (this$2.this$1.this$0) so as to handle such a test case:
310 * return (Object) A.this == (Object) B.this;
315 * new A().new B().new C();
318 * where we only want to deal with ONE enclosing instance for C (could not figure out an A for C)
320 public final ReferenceBinding findLocalType(char[] name) {
322 long compliance = environment().options.complianceLevel;
323 for (int i = 0, length = subscopeCount; i < length; i++) {
324 if (subscopes[i] instanceof ClassScope) {
325 LocalTypeBinding sourceType = (LocalTypeBinding)((ClassScope) subscopes[i]).referenceContext.binding;
326 // from 1.4 on, local types should not be accessed across switch case blocks (52221)
327 if (compliance >= ClassFileConstants.JDK1_4 && sourceType.switchCase != this.switchCase) continue;
328 if (CharOperation.equals(sourceType.sourceName(), name))
335 public LocalVariableBinding findVariable(char[] variable) {
337 int varLength = variable.length;
338 for (int i = 0, length = locals.length; i < length; i++) {
339 LocalVariableBinding local = locals[i];
342 if (local.name.length == varLength && CharOperation.equals(local.name, variable))
348 * flag is a mask of the following values VARIABLE (= FIELD or LOCAL), TYPE.
349 * Only bindings corresponding to the mask will be answered.
351 * if the VARIABLE mask is set then
352 * If the first name provided is a field (or local) then the field (or local) is answered
353 * Otherwise, package names and type names are consumed until a field is found.
354 * In this case, the field is answered.
356 * if the TYPE mask is set,
357 * package names and type names are consumed until the end of the input.
358 * Only if all of the input is consumed is the type answered
360 * All other conditions are errors, and a problem binding is returned.
362 * NOTE: If a problem binding is returned, senders should extract the compound name
363 * from the binding & not assume the problem applies to the entire compoundName.
365 * The VARIABLE mask has precedence over the TYPE mask.
367 * InvocationSite implements
368 * isSuperAccess(); this is used to determine if the discovered field is visible.
369 * setFieldIndex(int); this is used to record the number of names that were consumed.
371 * For example, getBinding({"foo","y","q", VARIABLE, site) will answer
372 * the binding for the field or local named "foo" (or an error binding if none exists).
373 * In addition, setFieldIndex(1) will be sent to the invocation site.
374 * If a type named "foo" exists, it will not be detected (and an error binding will be answered)
376 * IMPORTANT NOTE: This method is written under the assumption that compoundName is longer than length 1.
378 public Binding getBinding(char[][] compoundName, int mask, InvocationSite invocationSite, boolean needResolve) {
380 Binding binding = getBinding(compoundName[0], mask | TYPE | PACKAGE, invocationSite, needResolve);
381 invocationSite.setFieldIndex(1);
382 if (binding instanceof VariableBinding) return binding;
383 compilationUnitScope().recordSimpleReference(compoundName[0]);
384 if (!binding.isValidBinding()) return binding;
386 int length = compoundName.length;
387 int currentIndex = 1;
388 foundType : if (binding instanceof PackageBinding) {
389 PackageBinding packageBinding = (PackageBinding) binding;
390 while (currentIndex < length) {
391 compilationUnitScope().recordReference(packageBinding.compoundName, compoundName[currentIndex]);
392 binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]);
393 invocationSite.setFieldIndex(currentIndex);
394 if (binding == null) {
395 if (currentIndex == length) {
396 // must be a type if its the last name, otherwise we have no idea if its a package or type
397 return new ProblemReferenceBinding(
398 CharOperation.subarray(compoundName, 0, currentIndex),
401 return new ProblemBinding(
402 CharOperation.subarray(compoundName, 0, currentIndex),
405 if (binding instanceof ReferenceBinding) {
406 if (!binding.isValidBinding())
407 return new ProblemReferenceBinding(
408 CharOperation.subarray(compoundName, 0, currentIndex),
409 binding.problemId());
410 if (!((ReferenceBinding) binding).canBeSeenBy(this))
411 return new ProblemReferenceBinding(
412 CharOperation.subarray(compoundName, 0, currentIndex),
413 (ReferenceBinding) binding,
417 packageBinding = (PackageBinding) binding;
420 // It is illegal to request a PACKAGE from this method.
421 return new ProblemReferenceBinding(
422 CharOperation.subarray(compoundName, 0, currentIndex),
426 // know binding is now a ReferenceBinding
427 while (currentIndex < length) {
428 ReferenceBinding typeBinding = (ReferenceBinding) binding;
429 char[] nextName = compoundName[currentIndex++];
430 invocationSite.setFieldIndex(currentIndex);
431 invocationSite.setActualReceiverType(typeBinding);
432 if ((mask & FIELD) != 0 && (binding = findField(typeBinding, nextName, invocationSite, true /*resolve*/)) != null) {
433 if (!binding.isValidBinding())
434 return new ProblemFieldBinding(
435 ((FieldBinding) binding).declaringClass,
436 CharOperation.subarray(compoundName, 0, currentIndex),
437 binding.problemId());
438 break; // binding is now a field
440 if ((binding = findMemberType(nextName, typeBinding)) == null) {
441 if ((mask & FIELD) != 0) {
442 return new ProblemBinding(
443 CharOperation.subarray(compoundName, 0, currentIndex),
447 return new ProblemReferenceBinding(
448 CharOperation.subarray(compoundName, 0, currentIndex),
452 if (!binding.isValidBinding())
453 return new ProblemReferenceBinding(
454 CharOperation.subarray(compoundName, 0, currentIndex),
455 binding.problemId());
457 if ((mask & FIELD) != 0 && (binding instanceof FieldBinding)) {
458 // was looking for a field and found a field
459 FieldBinding field = (FieldBinding) binding;
460 if (!field.isStatic())
461 return new ProblemFieldBinding(
462 field.declaringClass,
463 CharOperation.subarray(compoundName, 0, currentIndex),
464 NonStaticReferenceInStaticContext);
467 if ((mask & TYPE) != 0 && (binding instanceof ReferenceBinding)) {
468 // was looking for a type and found a type
472 // handle the case when a field or type was asked for but we resolved the compoundName to a type or field
473 return new ProblemBinding(
474 CharOperation.subarray(compoundName, 0, currentIndex),
478 // Added for code assist... NOT Public API
479 public final Binding getBinding(
480 char[][] compoundName,
481 InvocationSite invocationSite) {
482 int currentIndex = 0;
483 int length = compoundName.length;
486 compoundName[currentIndex++],
487 VARIABLE | TYPE | PACKAGE,
490 if (!binding.isValidBinding())
493 foundType : if (binding instanceof PackageBinding) {
494 while (currentIndex < length) {
495 PackageBinding packageBinding = (PackageBinding) binding;
496 binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]);
497 if (binding == null) {
498 if (currentIndex == length) {
499 // must be a type if its the last name, otherwise we have no idea if its a package or type
500 return new ProblemReferenceBinding(
501 CharOperation.subarray(compoundName, 0, currentIndex),
504 return new ProblemBinding(
505 CharOperation.subarray(compoundName, 0, currentIndex),
508 if (binding instanceof ReferenceBinding) {
509 if (!binding.isValidBinding())
510 return new ProblemReferenceBinding(
511 CharOperation.subarray(compoundName, 0, currentIndex),
512 binding.problemId());
513 if (!((ReferenceBinding) binding).canBeSeenBy(this))
514 return new ProblemReferenceBinding(
515 CharOperation.subarray(compoundName, 0, currentIndex),
516 (ReferenceBinding) binding,
524 foundField : if (binding instanceof ReferenceBinding) {
525 while (currentIndex < length) {
526 ReferenceBinding typeBinding = (ReferenceBinding) binding;
527 char[] nextName = compoundName[currentIndex++];
528 if ((binding = findField(typeBinding, nextName, invocationSite, true /*resolve*/)) != null) {
529 if (!binding.isValidBinding())
530 return new ProblemFieldBinding(
531 ((FieldBinding) binding).declaringClass,
532 CharOperation.subarray(compoundName, 0, currentIndex),
533 binding.problemId());
534 if (!((FieldBinding) binding).isStatic())
535 return new ProblemFieldBinding(
536 ((FieldBinding) binding).declaringClass,
537 CharOperation.subarray(compoundName, 0, currentIndex),
538 NonStaticReferenceInStaticContext);
539 break foundField; // binding is now a field
541 if ((binding = findMemberType(nextName, typeBinding)) == null)
542 return new ProblemBinding(
543 CharOperation.subarray(compoundName, 0, currentIndex),
546 if (!binding.isValidBinding())
547 return new ProblemReferenceBinding(
548 CharOperation.subarray(compoundName, 0, currentIndex),
549 binding.problemId());
554 VariableBinding variableBinding = (VariableBinding) binding;
555 while (currentIndex < length) {
556 TypeBinding typeBinding = variableBinding.type;
557 if (typeBinding == null)
558 return new ProblemFieldBinding(
560 CharOperation.subarray(compoundName, 0, currentIndex + 1),
563 findField(typeBinding, compoundName[currentIndex++], invocationSite, true /*resolve*/);
564 if (variableBinding == null)
565 return new ProblemFieldBinding(
567 CharOperation.subarray(compoundName, 0, currentIndex),
569 if (!variableBinding.isValidBinding())
570 return variableBinding;
572 return variableBinding;
576 * This retrieves the argument that maps to an enclosing instance of the suitable type,
577 * if not found then answers nil -- do not create one
579 * #implicitThis : the implicit this will be ok
580 * #((arg) this$n) : available as a constructor arg
581 * #((arg) this$n ... this$p) : available as as a constructor arg + a sequence of fields
582 * #((fieldDescr) this$n ... this$p) : available as a sequence of fields
585 * Note that this algorithm should answer the shortest possible sequence when
586 * shortcuts are available:
587 * this$0 . this$0 . this$0
589 * this$2 . this$1 . this$0 . this$1 . this$0
590 * thus the code generation will be more compact and runtime faster
592 public VariableBinding[] getEmulationPath(LocalVariableBinding outerLocalVariable) {
594 MethodScope currentMethodScope = this.methodScope();
595 SourceTypeBinding sourceType = currentMethodScope.enclosingSourceType();
598 if (currentMethodScope == outerLocalVariable.declaringScope.methodScope()) {
599 return new VariableBinding[] { outerLocalVariable };
600 // implicit this is good enough
602 // use synthetic constructor arguments if possible
603 if (currentMethodScope.isInsideInitializerOrConstructor()
604 && (sourceType.isNestedType())) {
605 SyntheticArgumentBinding syntheticArg;
606 if ((syntheticArg = ((NestedTypeBinding) sourceType).getSyntheticArgument(outerLocalVariable)) != null) {
607 return new VariableBinding[] { syntheticArg };
610 // use a synthetic field then
611 if (!currentMethodScope.isStatic) {
612 FieldBinding syntheticField;
613 if ((syntheticField = sourceType.getSyntheticField(outerLocalVariable)) != null) {
614 return new VariableBinding[] { syntheticField };
621 * This retrieves the argument that maps to an enclosing instance of the suitable type,
622 * if not found then answers nil -- do not create one
624 * #implicitThis : the implicit this will be ok
625 * #((arg) this$n) : available as a constructor arg
626 * #((arg) this$n access$m... access$p) : available as as a constructor arg + a sequence of synthetic accessors to synthetic fields
627 * #((fieldDescr) this$n access#m... access$p) : available as a first synthetic field + a sequence of synthetic accessors to synthetic fields
629 * jls 15.9.2 + http://www.ergnosis.com/java-spec-report/java-language/jls-8.8.5.1-d.html
631 public Object[] getEmulationPath(
632 ReferenceBinding targetEnclosingType,
633 boolean onlyExactMatch,
634 boolean ignoreEnclosingArgInConstructorCall) {
636 MethodScope currentMethodScope = this.methodScope();
637 SourceTypeBinding sourceType = currentMethodScope.enclosingSourceType();
639 // use 'this' if possible
640 if (!currentMethodScope.isConstructorCall && !currentMethodScope.isStatic) {
641 if (sourceType == targetEnclosingType || (!onlyExactMatch && targetEnclosingType.isSuperclassOf(sourceType))) {
642 return EmulationPathToImplicitThis; // implicit this is good enough
645 if (!sourceType.isNestedType() || sourceType.isStatic()) { // no emulation from within non-inner types
646 if (currentMethodScope.isConstructorCall) {
647 return NoEnclosingInstanceInConstructorCall;
648 } else if (currentMethodScope.isStatic){
649 return NoEnclosingInstanceInStaticContext;
653 boolean insideConstructor = currentMethodScope.isInsideInitializerOrConstructor();
654 // use synthetic constructor arguments if possible
655 if (insideConstructor) {
656 SyntheticArgumentBinding syntheticArg;
657 if ((syntheticArg = ((NestedTypeBinding) sourceType).getSyntheticArgument(targetEnclosingType, onlyExactMatch)) != null) {
658 // reject allocation and super constructor call
659 if (ignoreEnclosingArgInConstructorCall
660 && currentMethodScope.isConstructorCall
661 && (sourceType == targetEnclosingType || (!onlyExactMatch && targetEnclosingType.isSuperclassOf(sourceType)))) {
662 return NoEnclosingInstanceInConstructorCall;
664 return new Object[] { syntheticArg };
668 // use a direct synthetic field then
669 if (currentMethodScope.isStatic) {
670 return NoEnclosingInstanceInStaticContext;
672 FieldBinding syntheticField = sourceType.getSyntheticField(targetEnclosingType, onlyExactMatch);
673 if (syntheticField != null) {
674 if (currentMethodScope.isConstructorCall){
675 return NoEnclosingInstanceInConstructorCall;
677 return new Object[] { syntheticField };
679 // could be reached through a sequence of enclosing instance link (nested members)
680 Object[] path = new Object[2]; // probably at least 2 of them
681 ReferenceBinding currentType = sourceType.enclosingType();
682 if (insideConstructor) {
683 path[0] = ((NestedTypeBinding) sourceType).getSyntheticArgument(currentType, onlyExactMatch);
685 if (currentMethodScope.isConstructorCall){
686 return NoEnclosingInstanceInConstructorCall;
688 path[0] = sourceType.getSyntheticField(currentType, onlyExactMatch);
690 if (path[0] != null) { // keep accumulating
693 ReferenceBinding currentEnclosingType;
694 while ((currentEnclosingType = currentType.enclosingType()) != null) {
697 if (currentType == targetEnclosingType
698 || (!onlyExactMatch && targetEnclosingType.isSuperclassOf(currentType))) break;
700 if (currentMethodScope != null) {
701 currentMethodScope = currentMethodScope.enclosingMethodScope();
702 if (currentMethodScope != null && currentMethodScope.isConstructorCall){
703 return NoEnclosingInstanceInConstructorCall;
705 if (currentMethodScope != null && currentMethodScope.isStatic){
706 return NoEnclosingInstanceInStaticContext;
710 syntheticField = ((NestedTypeBinding) currentType).getSyntheticField(currentEnclosingType, onlyExactMatch);
711 if (syntheticField == null) break;
713 // append inside the path
714 if (count == path.length) {
715 System.arraycopy(path, 0, (path = new Object[count + 1]), 0, count);
717 // private access emulation is necessary since synthetic field is private
718 path[count++] = ((SourceTypeBinding) syntheticField.declaringClass).addSyntheticMethod(syntheticField, true);
719 currentType = currentEnclosingType;
721 if (currentType == targetEnclosingType
722 || (!onlyExactMatch && targetEnclosingType.isSuperclassOf(currentType))) {
729 /* Answer true if the variable name already exists within the receiver's scope.
731 public final boolean isDuplicateLocalVariable(char[] name) {
732 BlockScope current = this;
734 for (int i = 0; i < localIndex; i++) {
735 if (CharOperation.equals(name, current.locals[i].name))
738 if (current.kind != BLOCK_SCOPE) return false;
739 current = (BlockScope)current.parent;
743 public int maxShiftedOffset() {
745 if (this.shiftScopes != null){
746 for (int i = 0, length = this.shiftScopes.length; i < length; i++){
747 int subMaxOffset = this.shiftScopes[i].maxOffset;
748 if (subMaxOffset > max) max = subMaxOffset;
754 /* Answer the problem reporter to use for raising new problems.
756 * Note that as a side-effect, this updates the current reference context
757 * (unit, type or method) in case the problem handler decides it is necessary
760 public ProblemReporter problemReporter() {
762 return outerMostMethodScope().problemReporter();
766 * Code responsible to request some more emulation work inside the invocation type, so as to supply
767 * correct synthetic arguments to any allocation of the target type.
769 public void propagateInnerEmulation(ReferenceBinding targetType, boolean isEnclosingInstanceSupplied) {
771 // no need to propagate enclosing instances, they got eagerly allocated already.
773 SyntheticArgumentBinding[] syntheticArguments;
774 if ((syntheticArguments = targetType.syntheticOuterLocalVariables()) != null) {
775 for (int i = 0, max = syntheticArguments.length; i < max; i++) {
776 SyntheticArgumentBinding syntheticArg = syntheticArguments[i];
777 // need to filter out the one that could match a supplied enclosing instance
778 if (!(isEnclosingInstanceSupplied
779 && (syntheticArg.type == targetType.enclosingType()))) {
780 this.emulateOuterAccess(syntheticArg.actualOuterLocalVariable);
786 /* Answer the reference type of this scope.
788 * It is the nearest enclosing type of this scope.
790 public TypeDeclaration referenceType() {
792 return methodScope().referenceType();
796 * Answer the index of this scope relatively to its parent.
797 * For method scope, answers -1 (not a classScope relative position)
799 public int scopeIndex() {
800 if (this instanceof MethodScope) return -1;
801 BlockScope parentScope = (BlockScope)parent;
802 Scope[] parentSubscopes = parentScope.subscopes;
803 for (int i = 0, max = parentScope.subscopeCount; i < max; i++) {
804 if (parentSubscopes[i] == this) return i;
809 // start position in this scope - for ordering scopes vs. variables
814 public String toString() {
818 public String toString(int tab) {
820 String s = basicToString(tab);
821 for (int i = 0; i < subscopeCount; i++)
822 if (subscopes[i] instanceof BlockScope)
823 s += ((BlockScope) subscopes[i]).toString(tab + 1) + "\n"; //$NON-NLS-1$