Makefile fixup
[org.ibex.tool.git] / repo / org.ibex.tool / src / org / eclipse / jdt / internal / compiler / lookup / MethodScope.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.lookup;
12
13 import org.eclipse.jdt.internal.compiler.ast.*;
14 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
15 import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
16 import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
17 import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
18 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
19 import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
20 import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
21 import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo;
22 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
23 import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
24 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
25
26 /**
27  * Particular block scope used for methods, constructors or clinits, representing
28  * its outermost blockscope. Note also that such a scope will be provided to enclose
29  * field initializers subscopes as well.
30  */
31 public class MethodScope extends BlockScope {
32
33         public ReferenceContext referenceContext;
34         public boolean isStatic; // method modifier or initializer one
35
36         //fields used during name resolution
37         public boolean isConstructorCall = false; 
38         public FieldBinding initializedField; // the field being initialized
39         public int lastVisibleFieldID = -1; // the ID of the last field which got declared 
40         // note that #initializedField can be null AND lastVisibleFieldID >= 0, when processing instance field initializers.
41
42         // flow analysis
43         public int analysisIndex; // for setting flow-analysis id
44         public boolean isPropagatingInnerClassEmulation;
45
46         // for local variables table attributes
47         public int lastIndex = 0;
48         public long[] definiteInits = new long[4];
49         public long[][] extraDefiniteInits = new long[4][];
50
51         // inner-emulation
52         public SyntheticArgumentBinding[] extraSyntheticArguments;
53         
54         public MethodScope(ClassScope parent, ReferenceContext context, boolean isStatic) {
55
56                 super(METHOD_SCOPE, parent);
57                 locals = new LocalVariableBinding[5];
58                 this.referenceContext = context;
59                 this.isStatic = isStatic;
60                 this.startIndex = 0;
61         }
62
63         /* Spec : 8.4.3 & 9.4
64          */
65         private void checkAndSetModifiersForConstructor(MethodBinding methodBinding) {
66                 
67                 int modifiers = methodBinding.modifiers;
68                 if ((modifiers & AccAlternateModifierProblem) != 0)
69                         problemReporter().duplicateModifierForMethod(
70                                 methodBinding.declaringClass,
71                                 (AbstractMethodDeclaration) referenceContext);
72
73                 if (((ConstructorDeclaration) referenceContext).isDefaultConstructor) {
74                         if (methodBinding.declaringClass.isPublic())
75                                 modifiers |= AccPublic;
76                         else if (methodBinding.declaringClass.isProtected())
77                                 modifiers |= AccProtected;
78                 }
79
80                 // after this point, tests on the 16 bits reserved.
81                 int realModifiers = modifiers & AccJustFlag;
82
83                 // check for abnormal modifiers
84                 int unexpectedModifiers =
85                         ~(AccPublic | AccPrivate | AccProtected | AccStrictfp);
86                 if ((realModifiers & unexpectedModifiers) != 0)
87                         problemReporter().illegalModifierForMethod(
88                                 methodBinding.declaringClass,
89                                 (AbstractMethodDeclaration) referenceContext);
90                 else if (
91                         (((AbstractMethodDeclaration) referenceContext).modifiers & AccStrictfp) != 0)
92                         // must check the parse node explicitly
93                         problemReporter().illegalModifierForMethod(
94                                 methodBinding.declaringClass,
95                                 (AbstractMethodDeclaration) referenceContext);
96
97                 // check for incompatible modifiers in the visibility bits, isolate the visibility bits
98                 int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate);
99                 if ((accessorBits & (accessorBits - 1)) != 0) {
100                         problemReporter().illegalVisibilityModifierCombinationForMethod(
101                                 methodBinding.declaringClass,
102                                 (AbstractMethodDeclaration) referenceContext);
103
104                         // need to keep the less restrictive
105                         if ((accessorBits & AccPublic) != 0) {
106                                 if ((accessorBits & AccProtected) != 0)
107                                         modifiers ^= AccProtected;
108                                 if ((accessorBits & AccPrivate) != 0)
109                                         modifiers ^= AccPrivate;
110                         }
111                         if ((accessorBits & AccProtected) != 0)
112                                 if ((accessorBits & AccPrivate) != 0)
113                                         modifiers ^= AccPrivate;
114                 }
115
116                 // if the receiver's declaring class is a private nested type, then make sure the receiver is not private (causes problems for inner type emulation)
117                 if (methodBinding.declaringClass.isPrivate())
118                         if ((modifiers & AccPrivate) != 0)
119                                 modifiers ^= AccPrivate;
120
121                 methodBinding.modifiers = modifiers;
122         }
123         
124         /* Spec : 8.4.3 & 9.4
125          */
126         private void checkAndSetModifiersForMethod(MethodBinding methodBinding) {
127                 
128                 int modifiers = methodBinding.modifiers;
129                 if ((modifiers & AccAlternateModifierProblem) != 0)
130                         problemReporter().duplicateModifierForMethod(
131                                 methodBinding.declaringClass,
132                                 (AbstractMethodDeclaration) referenceContext);
133
134                 // after this point, tests on the 16 bits reserved.
135                 int realModifiers = modifiers & AccJustFlag;
136
137                 // set the requested modifiers for a method in an interface
138                 if (methodBinding.declaringClass.isInterface()) {
139                         if ((realModifiers & ~(AccPublic | AccAbstract)) != 0)
140                                 problemReporter().illegalModifierForInterfaceMethod(
141                                         methodBinding.declaringClass,
142                                         (AbstractMethodDeclaration) referenceContext);
143                         return;
144                 }
145
146                 // check for abnormal modifiers
147                 int unexpectedModifiers =
148                         ~(
149                                 AccPublic
150                                         | AccPrivate
151                                         | AccProtected
152                                         | AccAbstract
153                                         | AccStatic
154                                         | AccFinal
155                                         | AccSynchronized
156                                         | AccNative
157                                         | AccStrictfp);
158                 if ((realModifiers & unexpectedModifiers) != 0)
159                         problemReporter().illegalModifierForMethod(
160                                 methodBinding.declaringClass,
161                                 (AbstractMethodDeclaration) referenceContext);
162
163                 // check for incompatible modifiers in the visibility bits, isolate the visibility bits
164                 int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate);
165                 if ((accessorBits & (accessorBits - 1)) != 0) {
166                         problemReporter().illegalVisibilityModifierCombinationForMethod(
167                                 methodBinding.declaringClass,
168                                 (AbstractMethodDeclaration) referenceContext);
169
170                         // need to keep the less restrictive
171                         if ((accessorBits & AccPublic) != 0) {
172                                 if ((accessorBits & AccProtected) != 0)
173                                         modifiers ^= AccProtected;
174                                 if ((accessorBits & AccPrivate) != 0)
175                                         modifiers ^= AccPrivate;
176                         }
177                         if ((accessorBits & AccProtected) != 0)
178                                 if ((accessorBits & AccPrivate) != 0)
179                                         modifiers ^= AccPrivate;
180                 }
181
182                 // check for modifiers incompatible with abstract modifier
183                 if ((modifiers & AccAbstract) != 0) {
184                         int incompatibleWithAbstract =
185                                 AccPrivate | AccStatic | AccFinal | AccSynchronized | AccNative | AccStrictfp;
186                         if ((modifiers & incompatibleWithAbstract) != 0)
187                                 problemReporter().illegalAbstractModifierCombinationForMethod(
188                                         methodBinding.declaringClass,
189                                         (AbstractMethodDeclaration) referenceContext);
190                         if (!methodBinding.declaringClass.isAbstract())
191                                 problemReporter().abstractMethodInAbstractClass(
192                                         (SourceTypeBinding) methodBinding.declaringClass,
193                                         (AbstractMethodDeclaration) referenceContext);
194                 }
195
196                 /* DISABLED for backward compatibility with javac (if enabled should also mark private methods as final)
197                 // methods from a final class are final : 8.4.3.3 
198                 if (methodBinding.declaringClass.isFinal())
199                         modifiers |= AccFinal;
200                 */
201                 // native methods cannot also be tagged as strictfp
202                 if ((modifiers & AccNative) != 0 && (modifiers & AccStrictfp) != 0)
203                         problemReporter().nativeMethodsCannotBeStrictfp(
204                                 methodBinding.declaringClass,
205                                 (AbstractMethodDeclaration) referenceContext);
206
207                 // static members are only authorized in a static member or top level type
208                 if (((realModifiers & AccStatic) != 0)
209                         && methodBinding.declaringClass.isNestedType()
210                         && !methodBinding.declaringClass.isStatic())
211                         problemReporter().unexpectedStaticModifierForMethod(
212                                 methodBinding.declaringClass,
213                                 (AbstractMethodDeclaration) referenceContext);
214
215                 methodBinding.modifiers = modifiers;
216         }
217         
218         /* Compute variable positions in scopes given an initial position offset
219          * ignoring unused local variables.
220          * 
221          * Deal with arguments here, locals and subscopes are processed in BlockScope method
222          */
223         public void computeLocalVariablePositions(int initOffset, CodeStream codeStream) {
224
225                 boolean isReportingUnusedArgument = false;
226
227                 if (referenceContext instanceof AbstractMethodDeclaration) {
228                         AbstractMethodDeclaration methodDecl = (AbstractMethodDeclaration)referenceContext;
229                         MethodBinding method = methodDecl.binding;
230                         CompilerOptions options = compilationUnitScope().environment.options;
231                         if (!(method.isAbstract()
232                                         || (method.isImplementing() && !options.reportUnusedParameterWhenImplementingAbstract) 
233                                         || (method.isOverriding() && !method.isImplementing() && !options.reportUnusedParameterWhenOverridingConcrete)
234                                         || method.isMain())) {
235                                 isReportingUnusedArgument = true;
236                         }
237                 }
238                 this.offset = initOffset;
239                 this.maxOffset = initOffset;
240
241                 // manage arguments     
242                 int ilocal = 0, maxLocals = this.localIndex;    
243                 while (ilocal < maxLocals) {
244                         LocalVariableBinding local = locals[ilocal];
245                         if (local == null || !local.isArgument) break; // done with arguments
246
247                         // do not report fake used variable
248                         if (isReportingUnusedArgument
249                                         && local.useFlag == LocalVariableBinding.UNUSED
250                                         && ((local.declaration.bits & ASTNode.IsLocalDeclarationReachableMASK) != 0)) { // declaration is reachable
251                                 this.problemReporter().unusedArgument(local.declaration);
252                         }
253
254                         // record user-defined argument for attribute generation
255                         codeStream.record(local); 
256
257                         // assign variable position
258                         local.resolvedPosition = this.offset;
259
260                         if ((local.type == LongBinding) || (local.type == DoubleBinding)) {
261                                 this.offset += 2;
262                         } else {
263                                 this.offset++;
264                         }
265                         // check for too many arguments/local variables
266                         if (this.offset > 0xFF) { // no more than 255 words of arguments
267                                 this.problemReporter().noMoreAvailableSpaceForArgument(local, local.declaration);
268                         }
269                         ilocal++;
270                 }
271                 
272                 // sneak in extra argument before other local variables
273                 if (extraSyntheticArguments != null) {
274                         for (int iarg = 0, maxArguments = extraSyntheticArguments.length; iarg < maxArguments; iarg++){
275                                 SyntheticArgumentBinding argument = extraSyntheticArguments[iarg];
276                                 argument.resolvedPosition = this.offset;
277                                 if ((argument.type == LongBinding) || (argument.type == DoubleBinding)){
278                                         this.offset += 2;
279                                 } else {
280                                         this.offset++;
281                                 }
282                                 if (this.offset > 0xFF) { // no more than 255 words of arguments
283                                         this.problemReporter().noMoreAvailableSpaceForArgument(argument, (ASTNode)this.referenceContext); 
284                                 }
285                         }
286                 }
287                 this.computeLocalVariablePositions(ilocal, this.offset, codeStream);
288         }
289
290         /* Error management:
291          *              keep null for all the errors that prevent the method to be created
292          *              otherwise return a correct method binding (but without the element
293          *              that caused the problem) : ie : Incorrect thrown exception
294          */
295         MethodBinding createMethod(AbstractMethodDeclaration method) {
296
297                 // is necessary to ensure error reporting
298                 this.referenceContext = method;
299                 method.scope = this;
300                 SourceTypeBinding declaringClass = referenceType().binding;
301                 int modifiers = method.modifiers | AccUnresolved;
302                 if (method.isConstructor()) {
303                         if (method.isDefaultConstructor()) {
304                                 modifiers |= AccIsDefaultConstructor;
305                         }
306                         method.binding = new MethodBinding(modifiers, null, null, declaringClass);
307                         checkAndSetModifiersForConstructor(method.binding);
308                 } else {
309                         if (declaringClass.isInterface())
310                                 modifiers |= AccPublic | AccAbstract;
311                         method.binding =
312                                 new MethodBinding(modifiers, method.selector, null, null, null, declaringClass);
313                         checkAndSetModifiersForMethod(method.binding);
314                 }
315                 this.isStatic = method.binding.isStatic();
316                 return method.binding;
317         }
318
319         /* Overridden to detect the error case inside an explicit constructor call:
320         
321         class X {
322                 int i;
323                 X myX;
324                 X(X x) {
325                         this(i, myX.i, x.i); // same for super calls... only the first 2 field accesses are errors
326                 }
327         }
328         */
329         public FieldBinding findField(
330                 TypeBinding receiverType,
331                 char[] fieldName,
332                 InvocationSite invocationSite,
333                 boolean needResolve) {
334
335                 FieldBinding field = super.findField(receiverType, fieldName, invocationSite, needResolve);
336                 if (field == null)
337                         return null;
338                 if (!field.isValidBinding())
339                         return field; // answer the error field
340                 if (field.isStatic())
341                         return field; // static fields are always accessible
342
343                 if (!isConstructorCall || receiverType != enclosingSourceType())
344                         return field;
345
346                 if (invocationSite instanceof SingleNameReference)
347                         return new ProblemFieldBinding(
348                                 field, // closest match
349                                 field.declaringClass,
350                                 fieldName,
351                                 NonStaticReferenceInConstructorInvocation);
352                 if (invocationSite instanceof QualifiedNameReference) {
353                         // look to see if the field is the first binding
354                         QualifiedNameReference name = (QualifiedNameReference) invocationSite;
355                         if (name.binding == null)
356                                 // only true when the field is the fieldbinding at the beginning of name's tokens
357                                 return new ProblemFieldBinding(
358                                         field, // closest match
359                                         field.declaringClass,
360                                         fieldName,
361                                         NonStaticReferenceInConstructorInvocation);
362                 }
363                 return field;
364         }
365
366         public boolean isInsideConstructor() {
367
368                 return (referenceContext instanceof ConstructorDeclaration);
369         }
370         
371         public boolean isInsideInitializer() {
372
373                 return (referenceContext instanceof TypeDeclaration);
374         }
375
376         public boolean isInsideInitializerOrConstructor() {
377
378                 return (referenceContext instanceof TypeDeclaration)
379                         || (referenceContext instanceof ConstructorDeclaration);
380         }
381
382         /* Answer the problem reporter to use for raising new problems.
383          *
384          * Note that as a side-effect, this updates the current reference context
385          * (unit, type or method) in case the problem handler decides it is necessary
386          * to abort.
387          */
388         public ProblemReporter problemReporter() {
389
390                 MethodScope outerMethodScope;
391                 if ((outerMethodScope = outerMostMethodScope()) == this) {
392                         ProblemReporter problemReporter = referenceCompilationUnit().problemReporter;
393                         problemReporter.referenceContext = referenceContext;
394                         return problemReporter;
395                 }
396                 return outerMethodScope.problemReporter();
397         }
398
399         public final int recordInitializationStates(FlowInfo flowInfo) {
400
401                 if (!flowInfo.isReachable()) return -1;
402
403                 UnconditionalFlowInfo unconditionalFlowInfo = flowInfo.unconditionalInits();
404                 long[] extraInits = unconditionalFlowInfo.extraDefiniteInits;
405                 long inits = unconditionalFlowInfo.definiteInits;
406                 checkNextEntry : for (int i = lastIndex; --i >= 0;) {
407                         if (definiteInits[i] == inits) {
408                                 long[] otherInits = extraDefiniteInits[i];
409                                 if ((extraInits != null) && (otherInits != null)) {
410                                         if (extraInits.length == otherInits.length) {
411                                                 int j, max;
412                                                 for (j = 0, max = extraInits.length; j < max; j++) {
413                                                         if (extraInits[j] != otherInits[j]) {
414                                                                 continue checkNextEntry;
415                                                         }
416                                                 }
417                                                 return i;
418                                         }
419                                 } else {
420                                         if ((extraInits == null) && (otherInits == null)) {
421                                                 return i;
422                                         }
423                                 }
424                         }
425                 }
426
427                 // add a new entry
428                 if (definiteInits.length == lastIndex) {
429                         // need a resize
430                         System.arraycopy(
431                                 definiteInits,
432                                 0,
433                                 (definiteInits = new long[lastIndex + 20]),
434                                 0,
435                                 lastIndex);
436                         System.arraycopy(
437                                 extraDefiniteInits,
438                                 0,
439                                 (extraDefiniteInits = new long[lastIndex + 20][]),
440                                 0,
441                                 lastIndex);
442                 }
443                 definiteInits[lastIndex] = inits;
444                 if (extraInits != null) {
445                         extraDefiniteInits[lastIndex] = new long[extraInits.length];
446                         System.arraycopy(
447                                 extraInits,
448                                 0,
449                                 extraDefiniteInits[lastIndex],
450                                 0,
451                                 extraInits.length);
452                 }
453                 return lastIndex++;
454         }
455
456         /* Answer the reference method of this scope, or null if initialization scoope.
457         */
458         public AbstractMethodDeclaration referenceMethod() {
459
460                 if (referenceContext instanceof AbstractMethodDeclaration) return (AbstractMethodDeclaration) referenceContext;
461                 return null;
462         }
463
464         /* Answer the reference type of this scope.
465         *
466         * It is the nearest enclosing type of this scope.
467         */
468         public TypeDeclaration referenceType() {
469
470                 return ((ClassScope) parent).referenceContext;
471         }
472
473         String basicToString(int tab) {
474
475                 String newLine = "\n"; //$NON-NLS-1$
476                 for (int i = tab; --i >= 0;)
477                         newLine += "\t"; //$NON-NLS-1$
478
479                 String s = newLine + "--- Method Scope ---"; //$NON-NLS-1$
480                 newLine += "\t"; //$NON-NLS-1$
481                 s += newLine + "locals:"; //$NON-NLS-1$
482                 for (int i = 0; i < localIndex; i++)
483                         s += newLine + "\t" + locals[i].toString(); //$NON-NLS-1$
484                 s += newLine + "startIndex = " + startIndex; //$NON-NLS-1$
485                 s += newLine + "isConstructorCall = " + isConstructorCall; //$NON-NLS-1$
486                 s += newLine + "initializedField = " + initializedField; //$NON-NLS-1$
487                 s += newLine + "lastVisibleFieldID = " + lastVisibleFieldID; //$NON-NLS-1$
488                 s += newLine + "referenceContext = " + referenceContext; //$NON-NLS-1$
489                 return s;
490         }
491
492 }