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