KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > lookup > MethodScope


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-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.classfmt.ClassFileConstants;
15 import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
16 import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
17 import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo;
18 import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
19 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
20
21 /**
22  * Particular block scope used for methods, constructors or clinits, representing
23  * its outermost blockscope. Note also that such a scope will be provided to enclose
24  * field initializers subscopes as well.
25  */

26 public class MethodScope extends BlockScope {
27
28     public ReferenceContext referenceContext;
29     public boolean isStatic; // method modifier or initializer one
30

31     //fields used during name resolution
32
public boolean isConstructorCall = false;
33     public FieldBinding initializedField; // the field being initialized
34
public int lastVisibleFieldID = -1; // the ID of the last field which got declared
35
// note that #initializedField can be null AND lastVisibleFieldID >= 0, when processing instance field initializers.
36

37     // flow analysis
38
public int analysisIndex; // for setting flow-analysis id
39
public boolean isPropagatingInnerClassEmulation;
40
41     // for local variables table attributes
42
public int lastIndex = 0;
43     public long[] definiteInits = new long[4];
44     public long[][] extraDefiniteInits = new long[4][];
45
46     // annotation support
47
public boolean insideTypeAnnotation = false;
48     
49     // inner-emulation
50
public SyntheticArgumentBinding[] extraSyntheticArguments;
51     
52     public MethodScope(ClassScope parent, ReferenceContext context, boolean isStatic) {
53
54         super(METHOD_SCOPE, parent);
55         locals = new LocalVariableBinding[5];
56         this.referenceContext = context;
57         this.isStatic = isStatic;
58         this.startIndex = 0;
59     }
60
61     /* Spec : 8.4.3 & 9.4
62      */

63     private void checkAndSetModifiersForConstructor(MethodBinding methodBinding) {
64         
65         int modifiers = methodBinding.modifiers;
66         final ReferenceBinding declaringClass = methodBinding.declaringClass;
67         if ((modifiers & ExtraCompilerModifiers.AccAlternateModifierProblem) != 0)
68             problemReporter().duplicateModifierForMethod(declaringClass, (AbstractMethodDeclaration) referenceContext);
69
70         if ((((ConstructorDeclaration) referenceContext).bits & ASTNode.IsDefaultConstructor) != 0) {
71             // certain flags are propagated from declaring class onto constructor
72
final int DECLARING_FLAGS = ClassFileConstants.AccEnum|ClassFileConstants.AccPublic|ClassFileConstants.AccProtected;
73             final int VISIBILITY_FLAGS = ClassFileConstants.AccPrivate|ClassFileConstants.AccPublic|ClassFileConstants.AccProtected;
74             int flags;
75             if ((flags = declaringClass.modifiers & DECLARING_FLAGS) != 0) {
76                 if ((flags & ClassFileConstants.AccEnum) != 0) {
77                     modifiers &= ~VISIBILITY_FLAGS;
78                     modifiers |= ClassFileConstants.AccPrivate; // default constructor is implicitly private in enum
79
} else {
80                     modifiers &= ~VISIBILITY_FLAGS;
81                     modifiers |= flags; // propagate public/protected
82
}
83             }
84         }
85
86         // after this point, tests on the 16 bits reserved.
87
int realModifiers = modifiers & ExtraCompilerModifiers.AccJustFlag;
88
89         // check for abnormal modifiers
90
final int UNEXPECTED_MODIFIERS = ~(ClassFileConstants.AccPublic | ClassFileConstants.AccPrivate | ClassFileConstants.AccProtected | ClassFileConstants.AccStrictfp);
91         if (declaringClass.isEnum() && (((ConstructorDeclaration) referenceContext).bits & ASTNode.IsDefaultConstructor) == 0) {
92             final int UNEXPECTED_ENUM_CONSTR_MODIFIERS = ~(ClassFileConstants.AccPrivate | ClassFileConstants.AccStrictfp);
93             if ((realModifiers & UNEXPECTED_ENUM_CONSTR_MODIFIERS) != 0) {
94                 problemReporter().illegalModifierForEnumConstructor((AbstractMethodDeclaration) referenceContext);
95                 modifiers &= ~ExtraCompilerModifiers.AccJustFlag | ~UNEXPECTED_ENUM_CONSTR_MODIFIERS;
96             } else if ((((AbstractMethodDeclaration) referenceContext).modifiers & ClassFileConstants.AccStrictfp) != 0) {
97                 // must check the parse node explicitly
98
problemReporter().illegalModifierForMethod((AbstractMethodDeclaration) referenceContext);
99             }
100             modifiers |= ClassFileConstants.AccPrivate; // enum constructor is implicitly private
101
} else if ((realModifiers & UNEXPECTED_MODIFIERS) != 0) {
102             problemReporter().illegalModifierForMethod((AbstractMethodDeclaration) referenceContext);
103             modifiers &= ~ExtraCompilerModifiers.AccJustFlag | ~UNEXPECTED_MODIFIERS;
104         } else if ((((AbstractMethodDeclaration) referenceContext).modifiers & ClassFileConstants.AccStrictfp) != 0) {
105             // must check the parse node explicitly
106
problemReporter().illegalModifierForMethod((AbstractMethodDeclaration) referenceContext);
107         }
108
109         // check for incompatible modifiers in the visibility bits, isolate the visibility bits
110
int accessorBits = realModifiers & (ClassFileConstants.AccPublic | ClassFileConstants.AccProtected | ClassFileConstants.AccPrivate);
111         if ((accessorBits & (accessorBits - 1)) != 0) {
112             problemReporter().illegalVisibilityModifierCombinationForMethod(declaringClass, (AbstractMethodDeclaration) referenceContext);
113
114             // need to keep the less restrictive so disable Protected/Private as necessary
115
if ((accessorBits & ClassFileConstants.AccPublic) != 0) {
116                 if ((accessorBits & ClassFileConstants.AccProtected) != 0)
117                     modifiers &= ~ClassFileConstants.AccProtected;
118                 if ((accessorBits & ClassFileConstants.AccPrivate) != 0)
119                     modifiers &= ~ClassFileConstants.AccPrivate;
120             } else if ((accessorBits & ClassFileConstants.AccProtected) != 0 && (accessorBits & ClassFileConstants.AccPrivate) != 0) {
121                 modifiers &= ~ClassFileConstants.AccPrivate;
122             }
123         }
124
125 // // 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)
126
// if (declaringClass.isPrivate() && (modifiers & ClassFileConstants.AccPrivate) != 0)
127
// modifiers &= ~ClassFileConstants.AccPrivate;
128

129         methodBinding.modifiers = modifiers;
130     }
131     
132     /* Spec : 8.4.3 & 9.4
133      */

134     private void checkAndSetModifiersForMethod(MethodBinding methodBinding) {
135         
136         int modifiers = methodBinding.modifiers;
137         final ReferenceBinding declaringClass = methodBinding.declaringClass;
138         if ((modifiers & ExtraCompilerModifiers.AccAlternateModifierProblem) != 0)
139             problemReporter().duplicateModifierForMethod(declaringClass, (AbstractMethodDeclaration) referenceContext);
140
141         // after this point, tests on the 16 bits reserved.
142
int realModifiers = modifiers & ExtraCompilerModifiers.AccJustFlag;
143
144         // set the requested modifiers for a method in an interface/annotation
145
if (declaringClass.isInterface()) {
146             if ((realModifiers & ~(ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract)) != 0) {
147                 if ((declaringClass.modifiers & ClassFileConstants.AccAnnotation) != 0)
148                     problemReporter().illegalModifierForAnnotationMember((AbstractMethodDeclaration) referenceContext);
149                 else
150                     problemReporter().illegalModifierForInterfaceMethod((AbstractMethodDeclaration) referenceContext);
151             }
152             return;
153         }
154
155         // check for abnormal modifiers
156
final int UNEXPECTED_MODIFIERS = ~(ClassFileConstants.AccPublic | ClassFileConstants.AccPrivate | ClassFileConstants.AccProtected
157             | ClassFileConstants.AccAbstract | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal | ClassFileConstants.AccSynchronized | ClassFileConstants.AccNative | ClassFileConstants.AccStrictfp);
158         if ((realModifiers & UNEXPECTED_MODIFIERS) != 0) {
159             problemReporter().illegalModifierForMethod((AbstractMethodDeclaration) referenceContext);
160             modifiers &= ~ExtraCompilerModifiers.AccJustFlag | ~UNEXPECTED_MODIFIERS;
161         }
162
163         // check for incompatible modifiers in the visibility bits, isolate the visibility bits
164
int accessorBits = realModifiers & (ClassFileConstants.AccPublic | ClassFileConstants.AccProtected | ClassFileConstants.AccPrivate);
165         if ((accessorBits & (accessorBits - 1)) != 0) {
166             problemReporter().illegalVisibilityModifierCombinationForMethod(declaringClass, (AbstractMethodDeclaration) referenceContext);
167
168             // need to keep the less restrictive so disable Protected/Private as necessary
169
if ((accessorBits & ClassFileConstants.AccPublic) != 0) {
170                 if ((accessorBits & ClassFileConstants.AccProtected) != 0)
171                     modifiers &= ~ClassFileConstants.AccProtected;
172                 if ((accessorBits & ClassFileConstants.AccPrivate) != 0)
173                     modifiers &= ~ClassFileConstants.AccPrivate;
174             } else if ((accessorBits & ClassFileConstants.AccProtected) != 0 && (accessorBits & ClassFileConstants.AccPrivate) != 0) {
175                 modifiers &= ~ClassFileConstants.AccPrivate;
176             }
177         }
178
179         // check for modifiers incompatible with abstract modifier
180
if ((modifiers & ClassFileConstants.AccAbstract) != 0) {
181             int incompatibleWithAbstract = ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal | ClassFileConstants.AccSynchronized | ClassFileConstants.AccNative | ClassFileConstants.AccStrictfp;
182             if ((modifiers & incompatibleWithAbstract) != 0)
183                 problemReporter().illegalAbstractModifierCombinationForMethod(declaringClass, (AbstractMethodDeclaration) referenceContext);
184             if (!methodBinding.declaringClass.isAbstract())
185                 problemReporter().abstractMethodInAbstractClass((SourceTypeBinding) declaringClass, (AbstractMethodDeclaration) referenceContext);
186         }
187
188         /* DISABLED for backward compatibility with javac (if enabled should also mark private methods as final)
189         // methods from a final class are final : 8.4.3.3
190         if (methodBinding.declaringClass.isFinal())
191             modifiers |= AccFinal;
192         */

193         // native methods cannot also be tagged as strictfp
194
if ((modifiers & ClassFileConstants.AccNative) != 0 && (modifiers & ClassFileConstants.AccStrictfp) != 0)
195             problemReporter().nativeMethodsCannotBeStrictfp(declaringClass, (AbstractMethodDeclaration) referenceContext);
196
197         // static members are only authorized in a static member or top level type
198
if (((realModifiers & ClassFileConstants.AccStatic) != 0) && declaringClass.isNestedType() && !declaringClass.isStatic())
199             problemReporter().unexpectedStaticModifierForMethod(declaringClass, (AbstractMethodDeclaration) referenceContext);
200
201         methodBinding.modifiers = modifiers;
202     }
203     
204     /* Compute variable positions in scopes given an initial position offset
205      * ignoring unused local variables.
206      *
207      * Deal with arguments here, locals and subscopes are processed in BlockScope method
208      */

209     public void computeLocalVariablePositions(int initOffset, CodeStream codeStream) {
210
211         boolean isReportingUnusedArgument = false;
212
213         if (referenceContext instanceof AbstractMethodDeclaration) {
214             AbstractMethodDeclaration methodDecl = (AbstractMethodDeclaration)referenceContext;
215             MethodBinding method = methodDecl.binding;
216             if (!(method.isAbstract()
217                     || (method.isImplementing() && !compilerOptions().reportUnusedParameterWhenImplementingAbstract)
218                     || (method.isOverriding() && !method.isImplementing() && !compilerOptions().reportUnusedParameterWhenOverridingConcrete)
219                     || method.isMain())) {
220                 isReportingUnusedArgument = true;
221             }
222         }
223         this.offset = initOffset;
224         this.maxOffset = initOffset;
225
226         // manage arguments
227
int ilocal = 0, maxLocals = this.localIndex;
228         while (ilocal < maxLocals) {
229             LocalVariableBinding local = locals[ilocal];
230             if (local == null || ((local.tagBits & TagBits.IsArgument) == 0)) break; // done with arguments
231

232             // do not report fake used variable
233
if (isReportingUnusedArgument
234                     && local.useFlag == LocalVariableBinding.UNUSED
235                     && ((local.declaration.bits & ASTNode.IsLocalDeclarationReachable) != 0)) { // declaration is reachable
236
this.problemReporter().unusedArgument(local.declaration);
237             }
238
239             // record user-defined argument for attribute generation
240
codeStream.record(local);
241
242             // assign variable position
243
local.resolvedPosition = this.offset;
244
245             if ((local.type == TypeBinding.LONG) || (local.type == TypeBinding.DOUBLE)) {
246                 this.offset += 2;
247             } else {
248                 this.offset++;
249             }
250             // check for too many arguments/local variables
251
if (this.offset > 0xFF) { // no more than 255 words of arguments
252
this.problemReporter().noMoreAvailableSpaceForArgument(local, local.declaration);
253             }
254             ilocal++;
255         }
256         
257         // sneak in extra argument before other local variables
258
if (extraSyntheticArguments != null) {
259             for (int iarg = 0, maxArguments = extraSyntheticArguments.length; iarg < maxArguments; iarg++){
260                 SyntheticArgumentBinding argument = extraSyntheticArguments[iarg];
261                 argument.resolvedPosition = this.offset;
262                 if ((argument.type == TypeBinding.LONG) || (argument.type == TypeBinding.DOUBLE)){
263                     this.offset += 2;
264                 } else {
265                     this.offset++;
266                 }
267                 if (this.offset > 0xFF) { // no more than 255 words of arguments
268
this.problemReporter().noMoreAvailableSpaceForArgument(argument, (ASTNode)this.referenceContext);
269                 }
270             }
271         }
272         this.computeLocalVariablePositions(ilocal, this.offset, codeStream);
273     }
274
275     /* Error management:
276      * keep null for all the errors that prevent the method to be created
277      * otherwise return a correct method binding (but without the element
278      * that caused the problem) : ie : Incorrect thrown exception
279      */

280     MethodBinding createMethod(AbstractMethodDeclaration method) {
281
282         // is necessary to ensure error reporting
283
this.referenceContext = method;
284         method.scope = this;
285         SourceTypeBinding declaringClass = referenceType().binding;
286         int modifiers = method.modifiers | ExtraCompilerModifiers.AccUnresolved;
287         if (method.isConstructor()) {
288             if (method.isDefaultConstructor())
289                 modifiers |= ExtraCompilerModifiers.AccIsDefaultConstructor;
290             method.binding = new MethodBinding(modifiers, null, null, declaringClass);
291             checkAndSetModifiersForConstructor(method.binding);
292         } else {
293             if (declaringClass.isInterface()) // interface or annotation type
294
modifiers |= ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract;
295             method.binding =
296                 new MethodBinding(modifiers, method.selector, null, null, null, declaringClass);
297             checkAndSetModifiersForMethod(method.binding);
298         }
299         this.isStatic = method.binding.isStatic();
300
301         Argument[] argTypes = method.arguments;
302         int argLength = argTypes == null ? 0 : argTypes.length;
303         if (argLength > 0 && compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
304             if (argTypes[--argLength].isVarArgs())
305                 method.binding.modifiers |= ClassFileConstants.AccVarargs;
306             while (--argLength >= 0) {
307                 if (argTypes[argLength].isVarArgs())
308                     problemReporter().illegalVararg(argTypes[argLength], method);
309             }
310         }
311         
312         TypeParameter[] typeParameters = method.typeParameters();
313         // do not construct type variables if source < 1.5
314
if (typeParameters == null || compilerOptions().sourceLevel < ClassFileConstants.JDK1_5) {
315             method.binding.typeVariables = Binding.NO_TYPE_VARIABLES;
316         } else {
317             method.binding.typeVariables = createTypeVariables(typeParameters, method.binding);
318             method.binding.modifiers |= ExtraCompilerModifiers.AccGenericSignature;
319         }
320         return method.binding;
321     }
322
323     /* Overridden to detect the error case inside an explicit constructor call:
324     
325     class X {
326         int i;
327         X myX;
328         X(X x) {
329             this(i, myX.i, x.i); // same for super calls... only the first 2 field accesses are errors
330         }
331     }
332     */

333     public FieldBinding findField(
334         TypeBinding receiverType,
335         char[] fieldName,
336         InvocationSite invocationSite,
337         boolean needResolve) {
338
339         FieldBinding field = super.findField(receiverType, fieldName, invocationSite, needResolve);
340         if (field == null)
341             return null;
342         if (!field.isValidBinding())
343             return field; // answer the error field
344
if (field.isStatic())
345             return field; // static fields are always accessible
346

347         if (!isConstructorCall || receiverType != enclosingSourceType())
348             return field;
349
350         if (invocationSite instanceof SingleNameReference)
351             return new ProblemFieldBinding(
352                 field, // closest match
353
field.declaringClass,
354                 fieldName,
355                 ProblemReasons.NonStaticReferenceInConstructorInvocation);
356         if (invocationSite instanceof QualifiedNameReference) {
357             // look to see if the field is the first binding
358
QualifiedNameReference name = (QualifiedNameReference) invocationSite;
359             if (name.binding == null)
360                 // only true when the field is the fieldbinding at the beginning of name's tokens
361
return new ProblemFieldBinding(
362                     field, // closest match
363
field.declaringClass,
364                     fieldName,
365                     ProblemReasons.NonStaticReferenceInConstructorInvocation);
366         }
367         return field;
368     }
369
370     public boolean isInsideConstructor() {
371
372         return (referenceContext instanceof ConstructorDeclaration);
373     }
374     
375     public boolean isInsideInitializer() {
376
377         return (referenceContext instanceof TypeDeclaration);
378     }
379
380     public boolean isInsideInitializerOrConstructor() {
381
382         return (referenceContext instanceof TypeDeclaration)
383             || (referenceContext instanceof ConstructorDeclaration);
384     }
385
386     /* Answer the problem reporter to use for raising new problems.
387      *
388      * Note that as a side-effect, this updates the current reference context
389      * (unit, type or method) in case the problem handler decides it is necessary
390      * to abort.
391      */

392     public ProblemReporter problemReporter() {
393
394         MethodScope outerMethodScope;
395         if ((outerMethodScope = outerMostMethodScope()) == this) {
396             ProblemReporter problemReporter = referenceCompilationUnit().problemReporter;
397             problemReporter.referenceContext = referenceContext;
398             return problemReporter;
399         }
400         return outerMethodScope.problemReporter();
401     }
402
403     public final int recordInitializationStates(FlowInfo flowInfo) {
404
405         if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) return -1;
406
407         UnconditionalFlowInfo unconditionalFlowInfo = flowInfo.unconditionalInitsWithoutSideEffect();
408         long[] extraInits = unconditionalFlowInfo.extra == null ?
409                 null : unconditionalFlowInfo.extra[0];
410         long inits = unconditionalFlowInfo.definiteInits;
411         checkNextEntry : for (int i = lastIndex; --i >= 0;) {
412             if (definiteInits[i] == inits) {
413                 long[] otherInits = extraDefiniteInits[i];
414                 if ((extraInits != null) && (otherInits != null)) {
415                     if (extraInits.length == otherInits.length) {
416                         int j, max;
417                         for (j = 0, max = extraInits.length; j < max; j++) {
418                             if (extraInits[j] != otherInits[j]) {
419                                 continue checkNextEntry;
420                             }
421                         }
422                         return i;
423                     }
424                 } else {
425                     if ((extraInits == null) && (otherInits == null)) {
426                         return i;
427                     }
428                 }
429             }
430         }
431
432         // add a new entry
433
if (definiteInits.length == lastIndex) {
434             // need a resize
435
System.arraycopy(
436                 definiteInits,
437                 0,
438                 (definiteInits = new long[lastIndex + 20]),
439                 0,
440                 lastIndex);
441             System.arraycopy(
442                 extraDefiniteInits,
443                 0,
444                 (extraDefiniteInits = new long[lastIndex + 20][]),
445                 0,
446                 lastIndex);
447         }
448         definiteInits[lastIndex] = inits;
449         if (extraInits != null) {
450             extraDefiniteInits[lastIndex] = new long[extraInits.length];
451             System.arraycopy(
452                 extraInits,
453                 0,
454                 extraDefiniteInits[lastIndex],
455                 0,
456                 extraInits.length);
457         }
458         return lastIndex++;
459     }
460
461     /* Answer the reference method of this scope, or null if initialization scoope.
462     */

463     public AbstractMethodDeclaration referenceMethod() {
464
465         if (referenceContext instanceof AbstractMethodDeclaration) return (AbstractMethodDeclaration) referenceContext;
466         return null;
467     }
468
469     /* Answer the reference type of this scope.
470     *
471     * It is the nearest enclosing type of this scope.
472     */

473     public TypeDeclaration referenceType() {
474
475         return ((ClassScope) parent).referenceContext;
476     }
477
478     String JavaDoc basicToString(int tab) {
479
480         String JavaDoc newLine = "\n"; //$NON-NLS-1$
481
for (int i = tab; --i >= 0;)
482             newLine += "\t"; //$NON-NLS-1$
483

484         String JavaDoc s = newLine + "--- Method Scope ---"; //$NON-NLS-1$
485
newLine += "\t"; //$NON-NLS-1$
486
s += newLine + "locals:"; //$NON-NLS-1$
487
for (int i = 0; i < localIndex; i++)
488             s += newLine + "\t" + locals[i].toString(); //$NON-NLS-1$
489
s += newLine + "startIndex = " + startIndex; //$NON-NLS-1$
490
s += newLine + "isConstructorCall = " + isConstructorCall; //$NON-NLS-1$
491
s += newLine + "initializedField = " + initializedField; //$NON-NLS-1$
492
s += newLine + "lastVisibleFieldID = " + lastVisibleFieldID; //$NON-NLS-1$
493
s += newLine + "referenceContext = " + referenceContext; //$NON-NLS-1$
494
return s;
495     }
496
497 }
498
Popular Tags