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
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,
25 * representing its outermost blockscope. Note also that such a scope will be
26 * provided to enclose field initializers subscopes as well.
28 public class MethodScope extends BlockScope {
30 public ReferenceContext referenceContext;
32 public boolean isStatic; // method modifier or initializer one
34 // fields used during name resolution
35 public static final int NotInFieldDecl = -1; // must be a negative value
37 public boolean isConstructorCall = false;
39 public FieldBinding initializedField; // the field being initialized
41 public int fieldDeclarationIndex = NotInFieldDecl;
44 public int analysisIndex; // for setting flow-analysis id
46 public boolean isPropagatingInnerClassEmulation;
48 // for local variables table attributes
49 public int lastIndex = 0;
51 public long[] definiteInits = new long[4];
53 public long[][] extraDefiniteInits = new long[4][];
56 public SyntheticArgumentBinding[] extraSyntheticArguments;
58 public MethodScope(ClassScope parent, ReferenceContext context,
61 super(METHOD_SCOPE, parent);
62 locals = new LocalVariableBinding[5];
63 this.referenceContext = context;
64 this.isStatic = isStatic;
71 private void checkAndSetModifiersForConstructor(MethodBinding methodBinding) {
73 int modifiers = methodBinding.modifiers;
74 if ((modifiers & AccAlternateModifierProblem) != 0)
75 problemReporter().duplicateModifierForMethod(
76 methodBinding.declaringClass,
77 (AbstractMethodDeclaration) referenceContext);
79 if (((ConstructorDeclaration) referenceContext).isDefaultConstructor) {
80 if (methodBinding.declaringClass.isPublic())
81 modifiers |= AccPublic;
82 else if (methodBinding.declaringClass.isProtected())
83 modifiers |= AccProtected;
86 // after this point, tests on the 16 bits reserved.
87 int realModifiers = modifiers & AccJustFlag;
89 // check for abnormal modifiers
90 int unexpectedModifiers = ~(AccPublic | AccPrivate | AccProtected);// |
92 if ((realModifiers & unexpectedModifiers) != 0)
93 problemReporter().illegalModifierForMethod(
94 methodBinding.declaringClass,
95 (AbstractMethodDeclaration) referenceContext);
97 // (((AbstractMethodDeclaration) referenceContext).modifiers &
99 // // must check the parse node explicitly
100 // problemReporter().illegalModifierForMethod(
101 // methodBinding.declaringClass,
102 // (AbstractMethodDeclaration) referenceContext);
104 // check for incompatible modifiers in the visibility bits, isolate the
106 int accessorBits = realModifiers
107 & (AccPublic | AccProtected | AccPrivate);
108 if ((accessorBits & (accessorBits - 1)) != 0) {
109 problemReporter().illegalVisibilityModifierCombinationForMethod(
110 methodBinding.declaringClass,
111 (AbstractMethodDeclaration) referenceContext);
113 // need to keep the less restrictive
114 if ((accessorBits & AccPublic) != 0) {
115 if ((accessorBits & AccProtected) != 0)
116 modifiers ^= AccProtected;
117 if ((accessorBits & AccPrivate) != 0)
118 modifiers ^= AccPrivate;
120 if ((accessorBits & AccProtected) != 0)
121 if ((accessorBits & AccPrivate) != 0)
122 modifiers ^= AccPrivate;
125 // if the receiver's declaring class is a private nested type, then make
126 // sure the receiver is not private (causes problems for inner type
128 if (methodBinding.declaringClass.isPrivate())
129 if ((modifiers & AccPrivate) != 0)
130 modifiers ^= AccPrivate;
132 methodBinding.modifiers = modifiers;
138 private void checkAndSetModifiersForMethod(MethodBinding methodBinding) {
140 int modifiers = methodBinding.modifiers;
141 if ((modifiers & AccAlternateModifierProblem) != 0)
142 problemReporter().duplicateModifierForMethod(
143 methodBinding.declaringClass,
144 (AbstractMethodDeclaration) referenceContext);
146 // after this point, tests on the 16 bits reserved.
147 int realModifiers = modifiers & AccJustFlag;
149 // set the requested modifiers for a method in an interface
150 if (methodBinding.declaringClass.isInterface()) {
151 if ((realModifiers & ~(AccPublic | AccAbstract)) != 0)
152 problemReporter().illegalModifierForInterfaceMethod(
153 methodBinding.declaringClass,
154 (AbstractMethodDeclaration) referenceContext);
158 // check for abnormal modifiers
159 int unexpectedModifiers = ~(AccPublic | AccPrivate | AccProtected
160 | AccAbstract | AccStatic | AccFinal);
164 if ((realModifiers & unexpectedModifiers) != 0)
165 problemReporter().illegalModifierForMethod(
166 methodBinding.declaringClass,
167 (AbstractMethodDeclaration) referenceContext);
169 // check for incompatible modifiers in the visibility bits, isolate the
171 int accessorBits = realModifiers
172 & (AccPublic | AccProtected | AccPrivate);
173 if ((accessorBits & (accessorBits - 1)) != 0) {
174 problemReporter().illegalVisibilityModifierCombinationForMethod(
175 methodBinding.declaringClass,
176 (AbstractMethodDeclaration) referenceContext);
178 // need to keep the less restrictive
179 if ((accessorBits & AccPublic) != 0) {
180 if ((accessorBits & AccProtected) != 0)
181 modifiers ^= AccProtected;
182 if ((accessorBits & AccPrivate) != 0)
183 modifiers ^= AccPrivate;
185 if ((accessorBits & AccProtected) != 0)
186 if ((accessorBits & AccPrivate) != 0)
187 modifiers ^= AccPrivate;
190 // check for modifiers incompatible with abstract modifier
191 if ((modifiers & AccAbstract) != 0) {
192 int incompatibleWithAbstract = AccPrivate | AccStatic | AccFinal;// |
198 if ((modifiers & incompatibleWithAbstract) != 0)
199 problemReporter().illegalAbstractModifierCombinationForMethod(
200 methodBinding.declaringClass,
201 (AbstractMethodDeclaration) referenceContext);
202 if (!methodBinding.declaringClass.isAbstract())
203 problemReporter().abstractMethodInAbstractClass(
204 (SourceTypeBinding) methodBinding.declaringClass,
205 (AbstractMethodDeclaration) referenceContext);
209 * DISABLED for backward compatibility with javac (if enabled should
210 * also mark private methods as final) // methods from a final class are
211 * final : 8.4.3.3 if (methodBinding.declaringClass.isFinal()) modifiers |=
214 // native methods cannot also be tagged as strictfp
215 // if ((modifiers & AccNative) != 0 && (modifiers & AccStrictfp) != 0)
216 // problemReporter().nativeMethodsCannotBeStrictfp(
217 // methodBinding.declaringClass,
218 // (AbstractMethodDeclaration) referenceContext);
219 // static members are only authorized in a static member or top level
221 if (((realModifiers & AccStatic) != 0)
222 && methodBinding.declaringClass.isNestedType()
223 && !methodBinding.declaringClass.isStatic())
224 problemReporter().unexpectedStaticModifierForMethod(
225 methodBinding.declaringClass,
226 (AbstractMethodDeclaration) referenceContext);
228 methodBinding.modifiers = modifiers;
232 * Compute variable positions in scopes given an initial position offset
233 * ignoring unused local variables.
235 * Deal with arguments here, locals and subscopes are processed in
238 // public void computeLocalVariablePositions(int initOffset, CodeStream
241 // boolean isReportingUnusedArgument = false;
243 // if (referenceContext instanceof AbstractMethodDeclaration) {
244 // AbstractMethodDeclaration methodDecl =
245 // (AbstractMethodDeclaration)referenceContext;
246 // MethodBinding method = methodDecl.binding;
247 // CompilerOptions options = compilationUnitScope().environment.options;
248 // if (!(method.isAbstract()
249 // || (method.isImplementing() &&
250 // !options.reportUnusedParameterWhenImplementingAbstract)
251 // || (method.isOverriding() && !method.isImplementing() &&
252 // !options.reportUnusedParameterWhenOverridingConcrete)
253 // || method.isMain())) {
254 // isReportingUnusedArgument = true;
257 // this.offset = initOffset;
258 // this.maxOffset = initOffset;
260 // // manage arguments
261 // int ilocal = 0, maxLocals = this.localIndex;
262 // while (ilocal < maxLocals) {
263 // LocalVariableBinding local = locals[ilocal];
264 // if (local == null || !local.isArgument) break; // done with arguments
266 // // do not report fake used variable
267 // if (isReportingUnusedArgument
268 // && local.useFlag == LocalVariableBinding.UNUSED
269 // && ((local.declaration.bits & ASTNode.IsLocalDeclarationReachableMASK) !=
270 // 0)) { // declaration is reachable
271 // this.problemReporter().unusedArgument(local.declaration);
274 // // record user-defined argument for attribute generation
275 // codeStream.record(local);
277 // // assign variable position
278 // local.resolvedPosition = this.offset;
280 // if ((local.type == LongBinding) || (local.type == DoubleBinding)) {
285 // // check for too many arguments/local variables
286 // if (this.offset > 0xFF) { // no more than 255 words of arguments
287 // this.problemReporter().noMoreAvailableSpaceForArgument(local,
288 // local.declaration);
293 // // sneak in extra argument before other local variables
294 // if (extraSyntheticArguments != null) {
295 // for (int iarg = 0, maxArguments = extraSyntheticArguments.length; iarg <
296 // maxArguments; iarg++){
297 // SyntheticArgumentBinding argument = extraSyntheticArguments[iarg];
298 // argument.resolvedPosition = this.offset;
299 // if ((argument.type == LongBinding) || (argument.type == DoubleBinding)){
304 // if (this.offset > 0xFF) { // no more than 255 words of arguments
305 // this.problemReporter().noMoreAvailableSpaceForArgument(argument,
306 // (ASTNode)this.referenceContext);
310 // this.computeLocalVariablePositions(ilocal, this.offset, codeStream);
313 * Error management: keep null for all the errors that prevent the method to
314 * be created otherwise return a correct method binding (but without the
315 * element that caused the problem) : ie : Incorrect thrown exception
317 MethodBinding createMethod(AbstractMethodDeclaration method) {
319 // is necessary to ensure error reporting
320 this.referenceContext = method;
322 SourceTypeBinding declaringClass = referenceType().binding;
323 int modifiers = method.modifiers | AccUnresolved;
324 if (method.isConstructor()) {
325 method.binding = new MethodBinding(modifiers, null, null,
327 checkAndSetModifiersForConstructor(method.binding);
329 if (declaringClass.isInterface())
330 modifiers |= AccPublic | AccAbstract;
331 method.binding = new MethodBinding(modifiers, method.selector,
332 null, null, null, declaringClass);
333 checkAndSetModifiersForMethod(method.binding);
336 this.isStatic = method.binding.isStatic();
337 return method.binding;
341 * Overridden to detect the error case inside an explicit constructor call:
343 * class X { int i; X myX; X(X x) { this(i, myX.i, x.i); // same for super
344 * calls... only the first 2 field accesses are errors } }
346 public FieldBinding findField(TypeBinding receiverType, char[] fieldName,
347 InvocationSite invocationSite) {
349 FieldBinding field = super.findField(receiverType, fieldName,
353 if (!field.isValidBinding())
354 return field; // answer the error field
355 if (field.isStatic())
356 return field; // static fields are always accessible
358 if (!isConstructorCall || receiverType != enclosingSourceType())
361 if (invocationSite instanceof SingleNameReference)
362 return new ProblemFieldBinding(field.declaringClass, fieldName,
363 NonStaticReferenceInConstructorInvocation);
364 if (invocationSite instanceof QualifiedNameReference) {
365 // look to see if the field is the first binding
366 QualifiedNameReference name = (QualifiedNameReference) invocationSite;
367 if (name.binding == null)
368 // only true when the field is the fieldbinding at the beginning
370 return new ProblemFieldBinding(field.declaringClass, fieldName,
371 NonStaticReferenceInConstructorInvocation);
376 public boolean isInsideInitializer() {
378 return (referenceContext instanceof TypeDeclaration);
381 public boolean isInsideInitializerOrConstructor() {
383 return (referenceContext instanceof TypeDeclaration)
384 || (referenceContext instanceof ConstructorDeclaration);
388 * Answer the problem reporter to use for raising new problems.
390 * Note that as a side-effect, this updates the current reference context
391 * (unit, type or method) in case the problem handler decides it is
392 * necessary to abort.
394 public ProblemReporter problemReporter() {
396 MethodScope outerMethodScope;
397 if ((outerMethodScope = outerMostMethodScope()) == this) {
398 ProblemReporter problemReporter = referenceCompilationUnit().problemReporter;
399 problemReporter.referenceContext = referenceContext;
400 return problemReporter;
402 return outerMethodScope.problemReporter();
406 public final int recordInitializationStates(FlowInfo flowInfo) {
408 if (!flowInfo.isReachable())
411 UnconditionalFlowInfo unconditionalFlowInfo = flowInfo
412 .unconditionalInits();
413 long[] extraInits = unconditionalFlowInfo.extraDefiniteInits;
414 long inits = unconditionalFlowInfo.definiteInits;
415 checkNextEntry: for (int i = lastIndex; --i >= 0;) {
416 if (definiteInits[i] == inits) {
417 long[] otherInits = extraDefiniteInits[i];
418 if ((extraInits != null) && (otherInits != null)) {
419 if (extraInits.length == otherInits.length) {
421 for (j = 0, max = extraInits.length; j < max; j++) {
422 if (extraInits[j] != otherInits[j]) {
423 continue checkNextEntry;
429 if ((extraInits == null) && (otherInits == null)) {
437 if (definiteInits.length == lastIndex) {
439 System.arraycopy(definiteInits, 0,
440 (definiteInits = new long[lastIndex + 20]), 0, lastIndex);
441 System.arraycopy(extraDefiniteInits, 0,
442 (extraDefiniteInits = new long[lastIndex + 20][]), 0,
445 definiteInits[lastIndex] = inits;
446 if (extraInits != null) {
447 extraDefiniteInits[lastIndex] = new long[extraInits.length];
448 System.arraycopy(extraInits, 0, extraDefiniteInits[lastIndex], 0,
455 * Answer the reference type of this scope.
457 * It is the nearest enclosing type of this scope.
459 public TypeDeclaration referenceType() {
461 return (TypeDeclaration) ((ClassScope) parent).referenceContext;
464 String basicToString(int tab) {
466 String newLine = "\n"; //$NON-NLS-1$
467 for (int i = tab; --i >= 0;)
468 newLine += "\t"; //$NON-NLS-1$
470 String s = newLine + "--- Method Scope ---"; //$NON-NLS-1$
471 newLine += "\t"; //$NON-NLS-1$
472 s += newLine + "locals:"; //$NON-NLS-1$
473 for (int i = 0; i < localIndex; i++)
474 s += newLine + "\t" + locals[i].toString(); //$NON-NLS-1$
475 s += newLine + "startIndex = " + startIndex; //$NON-NLS-1$
476 s += newLine + "isConstructorCall = " + isConstructorCall; //$NON-NLS-1$
477 s += newLine + "initializedField = " + initializedField; //$NON-NLS-1$
478 s += newLine + "fieldDeclarationIndex = " + fieldDeclarationIndex; //$NON-NLS-1$
479 s += newLine + "referenceContext = " + referenceContext; //$NON-NLS-1$