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.flow.FlowInfo;
14 import net.sourceforge.phpdt.internal.compiler.flow.UnconditionalFlowInfo;
15 import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext;
16 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
17 import net.sourceforge.phpeclipse.internal.compiler.ast.AbstractMethodDeclaration;
18 import net.sourceforge.phpeclipse.internal.compiler.ast.AstNode;
19 import net.sourceforge.phpeclipse.internal.compiler.ast.ConstructorDeclaration;
20 import net.sourceforge.phpeclipse.internal.compiler.ast.QualifiedNameReference;
21 import net.sourceforge.phpeclipse.internal.compiler.ast.SingleNameReference;
22 import net.sourceforge.phpeclipse.internal.compiler.ast.TypeDeclaration;
25 * Particular block scope used for methods, constructors or clinits, representing
26 * its outermost blockscope. Note also that such a scope will be provided to enclose
27 * field initializers subscopes as well.
29 public class MethodScope extends BlockScope {
31 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
36 public boolean isConstructorCall = false;
37 public int fieldDeclarationIndex = NotInFieldDecl;
40 public int analysisIndex; // for setting flow-analysis id
41 public boolean isPropagatingInnerClassEmulation;
43 // for local variables table attributes
44 public int lastIndex = 0;
45 public long[] definiteInits = new long[4];
46 public long[][] extraDefiniteInits = new long[4][];
49 public SyntheticArgumentBinding[] extraSyntheticArguments;
51 public MethodScope(ClassScope parent, ReferenceContext context, boolean isStatic) {
53 super(METHOD_SCOPE, parent);
54 locals = new LocalVariableBinding[5];
55 this.referenceContext = context;
56 this.isStatic = isStatic;
62 private void checkAndSetModifiersForConstructor(MethodBinding methodBinding) {
64 int modifiers = methodBinding.modifiers;
65 if ((modifiers & AccAlternateModifierProblem) != 0)
66 problemReporter().duplicateModifierForMethod(
67 methodBinding.declaringClass,
68 (AbstractMethodDeclaration) referenceContext);
70 if (((ConstructorDeclaration) referenceContext).isDefaultConstructor) {
71 if (methodBinding.declaringClass.isPublic())
72 modifiers |= AccPublic;
73 else if (methodBinding.declaringClass.isProtected())
74 modifiers |= AccProtected;
77 // after this point, tests on the 16 bits reserved.
78 int realModifiers = modifiers & AccJustFlag;
80 // check for abnormal modifiers
81 int unexpectedModifiers =
82 ~(AccPublic | AccPrivate | AccProtected);// | AccStrictfp);
83 if ((realModifiers & unexpectedModifiers) != 0)
84 problemReporter().illegalModifierForMethod(
85 methodBinding.declaringClass,
86 (AbstractMethodDeclaration) referenceContext);
88 // (((AbstractMethodDeclaration) referenceContext).modifiers & AccStrictfp) != 0)
89 // // must check the parse node explicitly
90 // problemReporter().illegalModifierForMethod(
91 // methodBinding.declaringClass,
92 // (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
135 if (methodBinding.declaringClass.isInterface()) {
136 if ((realModifiers & ~(AccPublic | AccAbstract)) != 0)
137 problemReporter().illegalModifierForInterfaceMethod(
138 methodBinding.declaringClass,
139 (AbstractMethodDeclaration) referenceContext);
143 // check for abnormal modifiers
144 int unexpectedModifiers =
155 if ((realModifiers & unexpectedModifiers) != 0)
156 problemReporter().illegalModifierForMethod(
157 methodBinding.declaringClass,
158 (AbstractMethodDeclaration) referenceContext);
160 // check for incompatible modifiers in the visibility bits, isolate the visibility bits
161 int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate);
162 if ((accessorBits & (accessorBits - 1)) != 0) {
163 problemReporter().illegalVisibilityModifierCombinationForMethod(
164 methodBinding.declaringClass,
165 (AbstractMethodDeclaration) referenceContext);
167 // need to keep the less restrictive
168 if ((accessorBits & AccPublic) != 0) {
169 if ((accessorBits & AccProtected) != 0)
170 modifiers ^= AccProtected;
171 if ((accessorBits & AccPrivate) != 0)
172 modifiers ^= AccPrivate;
174 if ((accessorBits & AccProtected) != 0)
175 if ((accessorBits & AccPrivate) != 0)
176 modifiers ^= AccPrivate;
179 // check for modifiers incompatible with abstract modifier
180 if ((modifiers & AccAbstract) != 0) {
181 int incompatibleWithAbstract =
182 AccPrivate | AccStatic | AccFinal;// | AccSynchronized | AccNative | AccStrictfp;
183 if ((modifiers & incompatibleWithAbstract) != 0)
184 problemReporter().illegalAbstractModifierCombinationForMethod(
185 methodBinding.declaringClass,
186 (AbstractMethodDeclaration) referenceContext);
187 if (!methodBinding.declaringClass.isAbstract())
188 problemReporter().abstractMethodInAbstractClass(
189 (SourceTypeBinding) methodBinding.declaringClass,
190 (AbstractMethodDeclaration) referenceContext);
193 /* DISABLED for backward compatibility with javac (if enabled should also mark private methods as final)
194 // methods from a final class are final : 8.4.3.3
195 if (methodBinding.declaringClass.isFinal())
196 modifiers |= AccFinal;
198 // native methods cannot also be tagged as strictfp
199 // if ((modifiers & AccNative) != 0 && (modifiers & AccStrictfp) != 0)
200 // problemReporter().nativeMethodsCannotBeStrictfp(
201 // methodBinding.declaringClass,
202 // (AbstractMethodDeclaration) referenceContext);
204 // static members are only authorized in a static member or top level type
205 if (((realModifiers & AccStatic) != 0)
206 && methodBinding.declaringClass.isNestedType()
207 && !methodBinding.declaringClass.isStatic())
208 problemReporter().unexpectedStaticModifierForMethod(
209 methodBinding.declaringClass,
210 (AbstractMethodDeclaration) referenceContext);
212 methodBinding.modifiers = modifiers;
215 /* Compute variable positions in scopes given an initial position offset
216 * ignoring unused local variables.
218 * Deal with arguments here, locals and subscopes are processed in BlockScope method
220 // public void computeLocalVariablePositions(int initOffset, CodeStream codeStream) {
222 // boolean isReportingUnusedArgument = false;
224 // if (referenceContext instanceof AbstractMethodDeclaration) {
225 // AbstractMethodDeclaration methodDecl = (AbstractMethodDeclaration)referenceContext;
226 // MethodBinding method = methodDecl.binding;
227 // CompilerOptions options = compilationUnitScope().environment.options;
228 // if (!(method.isAbstract()
229 // || (method.isImplementing() && !options.reportUnusedParameterWhenImplementingAbstract)
230 // || (method.isOverriding() && !method.isImplementing() && !options.reportUnusedParameterWhenOverridingConcrete)
231 // || method.isMain())) {
232 // isReportingUnusedArgument = true;
235 // this.offset = initOffset;
236 // this.maxOffset = initOffset;
238 // // manage arguments
239 // int ilocal = 0, maxLocals = this.localIndex;
240 // while (ilocal < maxLocals) {
241 // LocalVariableBinding local = locals[ilocal];
242 // if (local == null || !local.isArgument) break; // done with arguments
244 // // do not report fake used variable
245 // if (isReportingUnusedArgument
246 // && local.useFlag == LocalVariableBinding.UNUSED
247 // && ((local.declaration.bits & AstNode.IsLocalDeclarationReachableMASK) != 0)) { // declaration is reachable
248 // this.problemReporter().unusedArgument(local.declaration);
251 // // record user-defined argument for attribute generation
252 // codeStream.record(local);
254 // // assign variable position
255 // local.resolvedPosition = this.offset;
257 // if ((local.type == LongBinding) || (local.type == DoubleBinding)) {
262 // // check for too many arguments/local variables
263 // if (this.offset > 0xFF) { // no more than 255 words of arguments
264 // this.problemReporter().noMoreAvailableSpaceForArgument(local, local.declaration);
269 // // sneak in extra argument before other local variables
270 // if (extraSyntheticArguments != null) {
271 // for (int iarg = 0, maxArguments = extraSyntheticArguments.length; iarg < maxArguments; iarg++){
272 // SyntheticArgumentBinding argument = extraSyntheticArguments[iarg];
273 // argument.resolvedPosition = this.offset;
274 // if ((argument.type == LongBinding) || (argument.type == DoubleBinding)){
279 // if (this.offset > 0xFF) { // no more than 255 words of arguments
280 // this.problemReporter().noMoreAvailableSpaceForArgument(argument, (AstNode)this.referenceContext);
284 // this.computeLocalVariablePositions(ilocal, this.offset, codeStream);
288 * keep null for all the errors that prevent the method to be created
289 * otherwise return a correct method binding (but without the element
290 * that caused the problem) : ie : Incorrect thrown exception
292 MethodBinding createMethod(AbstractMethodDeclaration method) {
294 // is necessary to ensure error reporting
295 this.referenceContext = method;
297 SourceTypeBinding declaringClass = referenceType().binding;
298 int modifiers = method.modifiers | AccUnresolved;
299 if (method.isConstructor()) {
300 method.binding = new MethodBinding(modifiers, null, null, declaringClass);
301 checkAndSetModifiersForConstructor(method.binding);
303 if (declaringClass.isInterface())
304 modifiers |= AccPublic | AccAbstract;
306 new MethodBinding(modifiers, method.selector, null, null, null, declaringClass);
307 checkAndSetModifiersForMethod(method.binding);
310 this.isStatic = method.binding.isStatic();
311 return method.binding;
314 /* Overridden to detect the error case inside an explicit constructor call:
320 this(i, myX.i, x.i); // same for super calls... only the first 2 field accesses are errors
324 public FieldBinding findField(
325 TypeBinding receiverType,
327 InvocationSite invocationSite) {
329 FieldBinding field = super.findField(receiverType, fieldName, invocationSite);
332 if (!field.isValidBinding())
333 return field; // answer the error field
334 if (field.isStatic())
335 return field; // static fields are always accessible
337 if (!isConstructorCall || receiverType != enclosingSourceType())
340 if (invocationSite instanceof SingleNameReference)
341 return new ProblemFieldBinding(
342 field.declaringClass,
344 NonStaticReferenceInConstructorInvocation);
345 if (invocationSite instanceof QualifiedNameReference) {
346 // look to see if the field is the first binding
347 QualifiedNameReference name = (QualifiedNameReference) invocationSite;
348 if (name.binding == null)
349 // only true when the field is the fieldbinding at the beginning of name's tokens
350 return new ProblemFieldBinding(
351 field.declaringClass,
353 NonStaticReferenceInConstructorInvocation);
358 public boolean isInsideInitializer() {
360 return (referenceContext instanceof TypeDeclaration);
363 public boolean isInsideInitializerOrConstructor() {
365 return (referenceContext instanceof TypeDeclaration)
366 || (referenceContext instanceof ConstructorDeclaration);
369 /* Answer the problem reporter to use for raising new problems.
371 * Note that as a side-effect, this updates the current reference context
372 * (unit, type or method) in case the problem handler decides it is necessary
375 public ProblemReporter problemReporter() {
377 MethodScope outerMethodScope;
378 if ((outerMethodScope = outerMostMethodScope()) == this) {
379 ProblemReporter problemReporter = referenceCompilationUnit().problemReporter;
380 problemReporter.referenceContext = referenceContext;
381 return problemReporter;
383 return outerMethodScope.problemReporter();
387 public final int recordInitializationStates(FlowInfo flowInfo) {
389 if (!flowInfo.isReachable()) return -1;
391 UnconditionalFlowInfo unconditionalFlowInfo = flowInfo.unconditionalInits();
392 long[] extraInits = unconditionalFlowInfo.extraDefiniteInits;
393 long inits = unconditionalFlowInfo.definiteInits;
394 checkNextEntry : for (int i = lastIndex; --i >= 0;) {
395 if (definiteInits[i] == inits) {
396 long[] otherInits = extraDefiniteInits[i];
397 if ((extraInits != null) && (otherInits != null)) {
398 if (extraInits.length == otherInits.length) {
400 for (j = 0, max = extraInits.length; j < max; j++) {
401 if (extraInits[j] != otherInits[j]) {
402 continue checkNextEntry;
408 if ((extraInits == null) && (otherInits == null)) {
416 if (definiteInits.length == lastIndex) {
421 (definiteInits = new long[lastIndex + 20]),
427 (extraDefiniteInits = new long[lastIndex + 20][]),
431 definiteInits[lastIndex] = inits;
432 if (extraInits != null) {
433 extraDefiniteInits[lastIndex] = new long[extraInits.length];
437 extraDefiniteInits[lastIndex],
444 /* Answer the reference type of this scope.
446 * It is the nearest enclosing type of this scope.
448 public TypeDeclaration referenceType() {
450 return (TypeDeclaration) ((ClassScope) parent).referenceContext;
453 String basicToString(int tab) {
455 String newLine = "\n"; //$NON-NLS-1$
456 for (int i = tab; --i >= 0;)
457 newLine += "\t"; //$NON-NLS-1$
459 String s = newLine + "--- Method Scope ---"; //$NON-NLS-1$
460 newLine += "\t"; //$NON-NLS-1$
461 s += newLine + "locals:"; //$NON-NLS-1$
462 for (int i = 0; i < localIndex; i++)
463 s += newLine + "\t" + locals[i].toString(); //$NON-NLS-1$
464 s += newLine + "startIndex = " + startIndex; //$NON-NLS-1$
465 s += newLine + "isConstructorCall = " + isConstructorCall; //$NON-NLS-1$
466 s += newLine + "fieldDeclarationIndex = " + fieldDeclarationIndex; //$NON-NLS-1$
467 s += newLine + "referenceContext = " + referenceContext; //$NON-NLS-1$