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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.lookup;
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.classfmt.ClassFileConstants;
20 import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
21 import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
22 import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo;
23 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
24 import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
25 import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
28 * Particular block scope used for methods, constructors or clinits, representing
29 * its outermost blockscope. Note also that such a scope will be provided to enclose
30 * field initializers subscopes as well.
32 public class MethodScope extends BlockScope {
34 public ReferenceContext referenceContext;
35 public boolean isStatic; // method modifier or initializer one
37 //fields used during name resolution
38 public boolean isConstructorCall = false;
39 public FieldBinding initializedField; // the field being initialized
40 public int lastVisibleFieldID = -1; // the ID of the last field which got declared
41 // note that #initializedField can be null AND lastVisibleFieldID >= 0, when processing instance field initializers.
44 public int analysisIndex; // for setting flow-analysis id
45 public boolean isPropagatingInnerClassEmulation;
47 // for local variables table attributes
48 public int lastIndex = 0;
49 public long[] definiteInits = new long[4];
50 public long[][] extraDefiniteInits = new long[4][];
53 public SyntheticArgumentBinding[] extraSyntheticArguments;
55 public MethodScope(ClassScope parent, ReferenceContext context, boolean isStatic) {
57 super(METHOD_SCOPE, parent);
58 locals = new LocalVariableBinding[5];
59 this.referenceContext = context;
60 this.isStatic = isStatic;
66 private void checkAndSetModifiersForConstructor(MethodBinding methodBinding) {
68 int modifiers = methodBinding.modifiers;
69 if ((modifiers & AccAlternateModifierProblem) != 0)
70 problemReporter().duplicateModifierForMethod(
71 methodBinding.declaringClass,
72 (AbstractMethodDeclaration) referenceContext);
74 if (((ConstructorDeclaration) referenceContext).isDefaultConstructor) {
75 if (methodBinding.declaringClass.isPublic())
76 modifiers |= AccPublic;
77 else if (methodBinding.declaringClass.isProtected())
78 modifiers |= AccProtected;
81 // after this point, tests on the 16 bits reserved.
82 int realModifiers = modifiers & AccJustFlag;
84 // check for abnormal modifiers
85 int unexpectedModifiers =
86 ~(AccPublic | AccPrivate | AccProtected | AccStrictfp);
87 if ((realModifiers & unexpectedModifiers) != 0)
88 problemReporter().illegalModifierForMethod((AbstractMethodDeclaration) referenceContext);
90 (((AbstractMethodDeclaration) referenceContext).modifiers & AccStrictfp) != 0)
91 // must check the parse node explicitly
92 problemReporter().illegalModifierForMethod((AbstractMethodDeclaration) referenceContext);
94 // check for incompatible modifiers in the visibility bits, isolate the visibility bits
95 int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate);
96 if ((accessorBits & (accessorBits - 1)) != 0) {
97 problemReporter().illegalVisibilityModifierCombinationForMethod(
98 methodBinding.declaringClass,
99 (AbstractMethodDeclaration) referenceContext);
101 // need to keep the less restrictive
102 if ((accessorBits & AccPublic) != 0) {
103 if ((accessorBits & AccProtected) != 0)
104 modifiers &= ~AccProtected;
105 if ((accessorBits & AccPrivate) != 0)
106 modifiers &= ~AccPrivate;
108 if ((accessorBits & AccProtected) != 0)
109 if ((accessorBits & AccPrivate) != 0)
110 modifiers &= ~AccPrivate;
113 // 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)
114 if (methodBinding.declaringClass.isPrivate())
115 if ((modifiers & AccPrivate) != 0)
116 modifiers &= ~AccPrivate;
118 methodBinding.modifiers = modifiers;
121 /* Spec : 8.4.3 & 9.4
123 private void checkAndSetModifiersForMethod(MethodBinding methodBinding) {
125 int modifiers = methodBinding.modifiers;
126 if ((modifiers & AccAlternateModifierProblem) != 0)
127 problemReporter().duplicateModifierForMethod(
128 methodBinding.declaringClass,
129 (AbstractMethodDeclaration) referenceContext);
131 // after this point, tests on the 16 bits reserved.
132 int realModifiers = modifiers & AccJustFlag;
134 // set the requested modifiers for a method in an interface/annotation
135 if ((methodBinding.declaringClass.modifiers & AccInterface) != 0) {
136 if ((realModifiers & ~(AccPublic | AccAbstract)) != 0) {
137 if ((methodBinding.declaringClass.modifiers & AccAnnotation) != 0) {
138 problemReporter().illegalModifierForAnnotationMember((AbstractMethodDeclaration) referenceContext);
140 problemReporter().illegalModifierForInterfaceMethod((AbstractMethodDeclaration) referenceContext);
146 // check for abnormal modifiers
147 int unexpectedModifiers =
158 if ((realModifiers & unexpectedModifiers) != 0)
159 problemReporter().illegalModifierForMethod((AbstractMethodDeclaration) referenceContext);
161 // check for incompatible modifiers in the visibility bits, isolate the visibility bits
162 int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate);
163 if ((accessorBits & (accessorBits - 1)) != 0) {
164 problemReporter().illegalVisibilityModifierCombinationForMethod(
165 methodBinding.declaringClass,
166 (AbstractMethodDeclaration) referenceContext);
168 // need to keep the less restrictive
169 if ((accessorBits & AccPublic) != 0) {
170 if ((accessorBits & AccProtected) != 0)
171 modifiers &= ~AccProtected;
172 if ((accessorBits & AccPrivate) != 0)
173 modifiers &= ~AccPrivate;
175 if ((accessorBits & AccProtected) != 0)
176 if ((accessorBits & AccPrivate) != 0)
177 modifiers &= ~AccPrivate;
180 // check for modifiers incompatible with abstract modifier
181 if ((modifiers & AccAbstract) != 0) {
182 int incompatibleWithAbstract =
183 AccPrivate | AccStatic | AccFinal | AccSynchronized | AccNative | AccStrictfp;
184 if ((modifiers & incompatibleWithAbstract) != 0)
185 problemReporter().illegalAbstractModifierCombinationForMethod(
186 methodBinding.declaringClass,
187 (AbstractMethodDeclaration) referenceContext);
188 if (!methodBinding.declaringClass.isAbstract())
189 problemReporter().abstractMethodInAbstractClass(
190 (SourceTypeBinding) methodBinding.declaringClass,
191 (AbstractMethodDeclaration) referenceContext);
194 /* DISABLED for backward compatibility with javac (if enabled should also mark private methods as final)
195 // methods from a final class are final : 8.4.3.3
196 if (methodBinding.declaringClass.isFinal())
197 modifiers |= AccFinal;
199 // native methods cannot also be tagged as strictfp
200 if ((modifiers & AccNative) != 0 && (modifiers & AccStrictfp) != 0)
201 problemReporter().nativeMethodsCannotBeStrictfp(
202 methodBinding.declaringClass,
203 (AbstractMethodDeclaration) referenceContext);
205 // static members are only authorized in a static member or top level type
206 if (((realModifiers & AccStatic) != 0)
207 && methodBinding.declaringClass.isNestedType()
208 && !methodBinding.declaringClass.isStatic())
209 problemReporter().unexpectedStaticModifierForMethod(
210 methodBinding.declaringClass,
211 (AbstractMethodDeclaration) referenceContext);
213 methodBinding.modifiers = modifiers;
216 /* Compute variable positions in scopes given an initial position offset
217 * ignoring unused local variables.
219 * Deal with arguments here, locals and subscopes are processed in BlockScope method
221 public void computeLocalVariablePositions(int initOffset, CodeStream codeStream) {
223 boolean isReportingUnusedArgument = false;
225 if (referenceContext instanceof AbstractMethodDeclaration) {
226 AbstractMethodDeclaration methodDecl = (AbstractMethodDeclaration)referenceContext;
227 MethodBinding method = methodDecl.binding;
228 CompilerOptions options = compilationUnitScope().environment.options;
229 if (!(method.isAbstract()
230 || (method.isImplementing() && !options.reportUnusedParameterWhenImplementingAbstract)
231 || (method.isOverriding() && !method.isImplementing() && !options.reportUnusedParameterWhenOverridingConcrete)
232 || method.isMain())) {
233 isReportingUnusedArgument = true;
236 this.offset = initOffset;
237 this.maxOffset = initOffset;
240 int ilocal = 0, maxLocals = this.localIndex;
241 while (ilocal < maxLocals) {
242 LocalVariableBinding local = locals[ilocal];
243 if (local == null || !local.isArgument) break; // done with arguments
245 // do not report fake used variable
246 if (isReportingUnusedArgument
247 && local.useFlag == LocalVariableBinding.UNUSED
248 && ((local.declaration.bits & ASTNode.IsLocalDeclarationReachableMASK) != 0)) { // declaration is reachable
249 this.problemReporter().unusedArgument(local.declaration);
252 // record user-defined argument for attribute generation
253 codeStream.record(local);
255 // assign variable position
256 local.resolvedPosition = this.offset;
258 if ((local.type == LongBinding) || (local.type == DoubleBinding)) {
263 // check for too many arguments/local variables
264 if (this.offset > 0xFF) { // no more than 255 words of arguments
265 this.problemReporter().noMoreAvailableSpaceForArgument(local, local.declaration);
270 // sneak in extra argument before other local variables
271 if (extraSyntheticArguments != null) {
272 for (int iarg = 0, maxArguments = extraSyntheticArguments.length; iarg < maxArguments; iarg++){
273 SyntheticArgumentBinding argument = extraSyntheticArguments[iarg];
274 argument.resolvedPosition = this.offset;
275 if ((argument.type == LongBinding) || (argument.type == DoubleBinding)){
280 if (this.offset > 0xFF) { // no more than 255 words of arguments
281 this.problemReporter().noMoreAvailableSpaceForArgument(argument, (ASTNode)this.referenceContext);
285 this.computeLocalVariablePositions(ilocal, this.offset, codeStream);
289 * keep null for all the errors that prevent the method to be created
290 * otherwise return a correct method binding (but without the element
291 * that caused the problem) : ie : Incorrect thrown exception
293 MethodBinding createMethod(AbstractMethodDeclaration method) {
295 // is necessary to ensure error reporting
296 this.referenceContext = method;
298 SourceTypeBinding declaringClass = referenceType().binding;
299 int modifiers = method.modifiers | AccUnresolved;
300 if (method.isConstructor()) {
301 if (method.isDefaultConstructor())
302 modifiers |= AccIsDefaultConstructor;
303 method.binding = new MethodBinding(modifiers, null, null, declaringClass);
304 checkAndSetModifiersForConstructor(method.binding);
306 if ((declaringClass.modifiers & AccInterface) != 0) // interface or annotation type
307 modifiers |= AccPublic | AccAbstract;
309 new MethodBinding(modifiers, method.selector, null, null, null, declaringClass);
310 checkAndSetModifiersForMethod(method.binding);
312 this.isStatic = method.binding.isStatic();
314 Argument[] argTypes = method.arguments;
315 int argLength = argTypes == null ? 0 : argTypes.length;
316 if (argLength > 0 && environment().options.sourceLevel >= ClassFileConstants.JDK1_5) {
317 if (argTypes[--argLength].isVarArgs())
318 method.binding.modifiers |= AccVarargs;
319 while (--argLength >= 0) {
320 if (argTypes[argLength].isVarArgs())
321 problemReporter().illegalVararg(argTypes[argLength], method);
325 TypeParameter[] typeParameters = method.typeParameters();
326 // do not construct type variables if source < 1.5
327 if (typeParameters == null || environment().options.sourceLevel < ClassFileConstants.JDK1_5) {
328 method.binding.typeVariables = NoTypeVariables;
330 method.binding.typeVariables = createTypeVariables(typeParameters, method.binding);
331 method.binding.modifiers |= AccGenericSignature;
333 return method.binding;
336 /* Overridden to detect the error case inside an explicit constructor call:
342 this(i, myX.i, x.i); // same for super calls... only the first 2 field accesses are errors
346 public FieldBinding findField(
347 TypeBinding receiverType,
349 InvocationSite invocationSite,
350 boolean needResolve) {
352 FieldBinding field = super.findField(receiverType, fieldName, invocationSite, needResolve);
355 if (!field.isValidBinding())
356 return field; // answer the error field
357 if (field.isStatic())
358 return field; // static fields are always accessible
360 if (!isConstructorCall || receiverType != enclosingSourceType())
363 if (invocationSite instanceof SingleNameReference)
364 return new ProblemFieldBinding(
365 field, // closest match
366 field.declaringClass,
368 NonStaticReferenceInConstructorInvocation);
369 if (invocationSite instanceof QualifiedNameReference) {
370 // look to see if the field is the first binding
371 QualifiedNameReference name = (QualifiedNameReference) invocationSite;
372 if (name.binding == null)
373 // only true when the field is the fieldbinding at the beginning of name's tokens
374 return new ProblemFieldBinding(
375 field, // closest match
376 field.declaringClass,
378 NonStaticReferenceInConstructorInvocation);
383 public boolean isInsideConstructor() {
385 return (referenceContext instanceof ConstructorDeclaration);
388 public boolean isInsideInitializer() {
390 return (referenceContext instanceof TypeDeclaration);
393 public boolean isInsideInitializerOrConstructor() {
395 return (referenceContext instanceof TypeDeclaration)
396 || (referenceContext instanceof ConstructorDeclaration);
399 /* Answer the problem reporter to use for raising new problems.
401 * Note that as a side-effect, this updates the current reference context
402 * (unit, type or method) in case the problem handler decides it is necessary
405 public ProblemReporter problemReporter() {
407 MethodScope outerMethodScope;
408 if ((outerMethodScope = outerMostMethodScope()) == this) {
409 ProblemReporter problemReporter = referenceCompilationUnit().problemReporter;
410 problemReporter.referenceContext = referenceContext;
411 return problemReporter;
413 return outerMethodScope.problemReporter();
416 public final int recordInitializationStates(FlowInfo flowInfo) {
418 if (!flowInfo.isReachable()) return -1;
420 UnconditionalFlowInfo unconditionalFlowInfo = flowInfo.unconditionalInits();
421 long[] extraInits = unconditionalFlowInfo.extraDefiniteInits;
422 long inits = unconditionalFlowInfo.definiteInits;
423 checkNextEntry : for (int i = lastIndex; --i >= 0;) {
424 if (definiteInits[i] == inits) {
425 long[] otherInits = extraDefiniteInits[i];
426 if ((extraInits != null) && (otherInits != null)) {
427 if (extraInits.length == otherInits.length) {
429 for (j = 0, max = extraInits.length; j < max; j++) {
430 if (extraInits[j] != otherInits[j]) {
431 continue checkNextEntry;
437 if ((extraInits == null) && (otherInits == null)) {
445 if (definiteInits.length == lastIndex) {
450 (definiteInits = new long[lastIndex + 20]),
456 (extraDefiniteInits = new long[lastIndex + 20][]),
460 definiteInits[lastIndex] = inits;
461 if (extraInits != null) {
462 extraDefiniteInits[lastIndex] = new long[extraInits.length];
466 extraDefiniteInits[lastIndex],
473 /* Answer the reference method of this scope, or null if initialization scoope.
475 public AbstractMethodDeclaration referenceMethod() {
477 if (referenceContext instanceof AbstractMethodDeclaration) return (AbstractMethodDeclaration) referenceContext;
481 /* Answer the reference type of this scope.
483 * It is the nearest enclosing type of this scope.
485 public TypeDeclaration referenceType() {
487 return ((ClassScope) parent).referenceContext;
490 String basicToString(int tab) {
492 String newLine = "\n"; //$NON-NLS-1$
493 for (int i = tab; --i >= 0;)
494 newLine += "\t"; //$NON-NLS-1$
496 String s = newLine + "--- Method Scope ---"; //$NON-NLS-1$
497 newLine += "\t"; //$NON-NLS-1$
498 s += newLine + "locals:"; //$NON-NLS-1$
499 for (int i = 0; i < localIndex; i++)
500 s += newLine + "\t" + locals[i].toString(); //$NON-NLS-1$
501 s += newLine + "startIndex = " + startIndex; //$NON-NLS-1$
502 s += newLine + "isConstructorCall = " + isConstructorCall; //$NON-NLS-1$
503 s += newLine + "initializedField = " + initializedField; //$NON-NLS-1$
504 s += newLine + "lastVisibleFieldID = " + lastVisibleFieldID; //$NON-NLS-1$
505 s += newLine + "referenceContext = " + referenceContext; //$NON-NLS-1$