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