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