1 /*******************************************************************************
2 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v0.5
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v05.html
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.lookup;
13 import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration;
14 import net.sourceforge.phpdt.internal.compiler.ast.ConstructorDeclaration;
15 import net.sourceforge.phpdt.internal.compiler.ast.QualifiedNameReference;
16 import net.sourceforge.phpdt.internal.compiler.ast.SingleNameReference;
17 import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration;
18 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
19 import net.sourceforge.phpdt.internal.compiler.flow.UnconditionalFlowInfo;
20 import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext;
21 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
24 * Particular block scope used for methods, constructors or clinits, representing
25 * its outermost blockscope. Note also that such a scope will be provided to enclose
26 * field initializers subscopes as well.
28 public class MethodScope extends BlockScope {
30 public ReferenceContext referenceContext;
31 public boolean needToCompactLocalVariables;
32 public boolean isStatic; // method modifier or initializer one
34 //fields used in the TC process (no real meaning)
35 public static final int NotInFieldDecl = -1; //must be a negative value
36 public boolean isConstructorCall = false; //modified on the fly by the TC
37 public int fieldDeclarationIndex = NotInFieldDecl;
38 //modified on the fly by the TC
40 public int analysisIndex; // for setting flow-analysis id
42 public boolean isPropagatingInnerClassEmulation;
44 // for local variables table attributes
45 public int lastIndex = 0;
46 public long[] definiteInits = new long[4];
47 public long[][] extraDefiniteInits = new long[4][];
51 ReferenceContext context,
54 super(METHOD_SCOPE, parent);
55 locals = new LocalVariableBinding[5];
56 this.referenceContext = context;
57 this.isStatic = isStatic;
63 private void checkAndSetModifiersForConstructor(MethodBinding methodBinding) {
65 int modifiers = methodBinding.modifiers;
66 if ((modifiers & AccAlternateModifierProblem) != 0)
67 problemReporter().duplicateModifierForMethod(
68 methodBinding.declaringClass,
69 (AbstractMethodDeclaration) referenceContext);
71 if (((ConstructorDeclaration) referenceContext).isDefaultConstructor) {
72 if (methodBinding.declaringClass.isPublic())
73 modifiers |= AccPublic;
74 else if (methodBinding.declaringClass.isProtected())
75 modifiers |= AccProtected;
78 // after this point, tests on the 16 bits reserved.
79 int realModifiers = modifiers & AccJustFlag;
81 // check for abnormal modifiers
82 int unexpectedModifiers =
83 ~(AccPublic | AccPrivate | AccProtected | AccStrictfp);
84 if ((realModifiers & unexpectedModifiers) != 0)
85 problemReporter().illegalModifierForMethod(
86 methodBinding.declaringClass,
87 (AbstractMethodDeclaration) referenceContext);
89 (((AbstractMethodDeclaration) referenceContext).modifiers & AccStrictfp) != 0)
90 // must check the parse node explicitly
91 problemReporter().illegalModifierForMethod(
92 methodBinding.declaringClass,
93 (AbstractMethodDeclaration) referenceContext);
95 // check for incompatible modifiers in the visibility bits, isolate the visibility bits
96 int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate);
97 if ((accessorBits & (accessorBits - 1)) != 0) {
98 problemReporter().illegalVisibilityModifierCombinationForMethod(
99 methodBinding.declaringClass,
100 (AbstractMethodDeclaration) referenceContext);
102 // need to keep the less restrictive
103 if ((accessorBits & AccPublic) != 0) {
104 if ((accessorBits & AccProtected) != 0)
105 modifiers ^= AccProtected;
106 if ((accessorBits & AccPrivate) != 0)
107 modifiers ^= AccPrivate;
109 if ((accessorBits & AccProtected) != 0)
110 if ((accessorBits & AccPrivate) != 0)
111 modifiers ^= AccPrivate;
114 // 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)
115 if (methodBinding.declaringClass.isPrivate())
116 if ((modifiers & AccPrivate) != 0)
117 modifiers ^= AccPrivate;
119 methodBinding.modifiers = modifiers;
122 /* Spec : 8.4.3 & 9.4
124 private void checkAndSetModifiersForMethod(MethodBinding methodBinding) {
126 int modifiers = methodBinding.modifiers;
127 if ((modifiers & AccAlternateModifierProblem) != 0)
128 problemReporter().duplicateModifierForMethod(
129 methodBinding.declaringClass,
130 (AbstractMethodDeclaration) referenceContext);
132 // after this point, tests on the 16 bits reserved.
133 int realModifiers = modifiers & AccJustFlag;
135 // set the requested modifiers for a method in an interface
136 if (methodBinding.declaringClass.isInterface()) {
137 if ((realModifiers & ~(AccPublic | AccAbstract)) != 0)
138 problemReporter().illegalModifierForInterfaceMethod(
139 methodBinding.declaringClass,
140 (AbstractMethodDeclaration) referenceContext);
144 // check for abnormal modifiers
145 int unexpectedModifiers =
156 if ((realModifiers & unexpectedModifiers) != 0)
157 problemReporter().illegalModifierForMethod(
158 methodBinding.declaringClass,
159 (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;
217 * keep null for all the errors that prevent the method to be created
218 * otherwise return a correct method binding (but without the element
219 * that caused the problem) : ie : Incorrect thrown exception
221 MethodBinding createMethod(AbstractMethodDeclaration method) {
223 // is necessary to ensure error reporting
224 this.referenceContext = method;
226 SourceTypeBinding declaringClass = referenceType().binding;
227 int modifiers = method.modifiers | AccUnresolved;
228 if (method.isConstructor()) {
229 method.binding = new MethodBinding(modifiers, null, null, declaringClass);
230 checkAndSetModifiersForConstructor(method.binding);
232 if (declaringClass.isInterface())
233 modifiers |= AccPublic | AccAbstract;
235 new MethodBinding(modifiers, method.selector, null, null, null, declaringClass);
236 checkAndSetModifiersForMethod(method.binding);
239 this.isStatic = method.binding.isStatic();
240 return method.binding;
243 /* Overridden to detect the error case inside an explicit constructor call:
249 this(i, myX.i, x.i); // same for super calls... only the first 2 field accesses are errors
253 public FieldBinding findField(
254 TypeBinding receiverType,
256 InvocationSite invocationSite) {
258 FieldBinding field = super.findField(receiverType, fieldName, invocationSite);
261 if (!field.isValidBinding())
262 return field; // answer the error field
263 if (field.isStatic())
264 return field; // static fields are always accessible
266 if (!isConstructorCall || receiverType != enclosingSourceType())
269 if (invocationSite instanceof SingleNameReference)
270 return new ProblemFieldBinding(
271 field.declaringClass,
273 NonStaticReferenceInConstructorInvocation);
274 if (invocationSite instanceof QualifiedNameReference) {
275 // look to see if the field is the first binding
276 QualifiedNameReference name = (QualifiedNameReference) invocationSite;
277 if (name.binding == null)
278 // only true when the field is the fieldbinding at the beginning of name's tokens
279 return new ProblemFieldBinding(
280 field.declaringClass,
282 NonStaticReferenceInConstructorInvocation);
287 public boolean isInsideInitializer() {
289 return (referenceContext instanceof TypeDeclaration);
292 public boolean isInsideInitializerOrConstructor() {
294 return (referenceContext instanceof TypeDeclaration)
295 || (referenceContext instanceof ConstructorDeclaration);
298 /* Answer the problem reporter to use for raising new problems.
300 * Note that as a side-effect, this updates the current reference context
301 * (unit, type or method) in case the problem handler decides it is necessary
304 public ProblemReporter problemReporter() {
306 MethodScope outerMethodScope;
307 if ((outerMethodScope = outerMostMethodScope()) == this) {
308 ProblemReporter problemReporter = referenceCompilationUnit().problemReporter;
309 problemReporter.referenceContext = referenceContext;
310 return problemReporter;
312 return outerMethodScope.problemReporter();
316 public final int recordInitializationStates(FlowInfo flowInfo) {
318 if ((flowInfo == FlowInfo.DeadEnd) || (flowInfo.isFakeReachable())) {
321 UnconditionalFlowInfo unconditionalFlowInfo = flowInfo.unconditionalInits();
322 long[] extraInits = unconditionalFlowInfo.extraDefiniteInits;
323 long inits = unconditionalFlowInfo.definiteInits;
324 checkNextEntry : for (int i = lastIndex; --i >= 0;) {
325 if (definiteInits[i] == inits) {
326 long[] otherInits = extraDefiniteInits[i];
327 if ((extraInits != null) && (otherInits != null)) {
328 if (extraInits.length == otherInits.length) {
330 for (j = 0, max = extraInits.length; j < max; j++) {
331 if (extraInits[j] != otherInits[j]) {
332 continue checkNextEntry;
338 if ((extraInits == null) && (otherInits == null)) {
346 if (definiteInits.length == lastIndex) {
351 (definiteInits = new long[lastIndex + 20]),
357 (extraDefiniteInits = new long[lastIndex + 20][]),
361 definiteInits[lastIndex] = inits;
362 if (extraInits != null) {
363 extraDefiniteInits[lastIndex] = new long[extraInits.length];
367 extraDefiniteInits[lastIndex],
374 /* Answer the reference type of this scope.
376 * i.e. the nearest enclosing type of this scope.
378 public TypeDeclaration referenceType() {
380 return (TypeDeclaration) ((ClassScope) parent).referenceContext;
383 String basicToString(int tab) {
385 String newLine = "\n"; //$NON-NLS-1$
386 for (int i = tab; --i >= 0;)
387 newLine += "\t"; //$NON-NLS-1$
389 String s = newLine + "--- Method Scope ---"; //$NON-NLS-1$
390 newLine += "\t"; //$NON-NLS-1$
391 s += newLine + "locals:"; //$NON-NLS-1$
392 for (int i = 0; i < localIndex; i++)
393 s += newLine + "\t" + locals[i].toString(); //$NON-NLS-1$
394 s += newLine + "startIndex = " + startIndex; //$NON-NLS-1$
395 s += newLine + "isConstructorCall = " + isConstructorCall; //$NON-NLS-1$
396 s += newLine + "fieldDeclarationIndex = " + fieldDeclarationIndex; //$NON-NLS-1$