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.ConstructorDeclaration;
19 import net.sourceforge.phpeclipse.internal.compiler.ast.QualifiedNameReference;
20 import net.sourceforge.phpeclipse.internal.compiler.ast.SingleNameReference;
21 import net.sourceforge.phpeclipse.internal.compiler.ast.TypeDeclaration;
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 isStatic; // method modifier or initializer one
33 //fields used during name resolution
34 public static final int NotInFieldDecl = -1; //must be a negative value
35 public boolean isConstructorCall = false;
36 public int fieldDeclarationIndex = NotInFieldDecl;
39 public int analysisIndex; // for setting flow-analysis id
40 public boolean isPropagatingInnerClassEmulation;
42 // for local variables table attributes
43 public int lastIndex = 0;
44 public long[] definiteInits = new long[4];
45 public long[][] extraDefiniteInits = new long[4][];
48 public SyntheticArgumentBinding[] extraSyntheticArguments;
50 public MethodScope(ClassScope parent, ReferenceContext context, boolean isStatic) {
52 super(METHOD_SCOPE, parent);
53 locals = new LocalVariableBinding[5];
54 this.referenceContext = context;
55 this.isStatic = isStatic;
61 private void checkAndSetModifiersForConstructor(MethodBinding methodBinding) {
63 int modifiers = methodBinding.modifiers;
64 if ((modifiers & AccAlternateModifierProblem) != 0)
65 problemReporter().duplicateModifierForMethod(
66 methodBinding.declaringClass,
67 (AbstractMethodDeclaration) referenceContext);
69 if (((ConstructorDeclaration) referenceContext).isDefaultConstructor) {
70 if (methodBinding.declaringClass.isPublic())
71 modifiers |= AccPublic;
72 else if (methodBinding.declaringClass.isProtected())
73 modifiers |= AccProtected;
76 // after this point, tests on the 16 bits reserved.
77 int realModifiers = modifiers & AccJustFlag;
79 // check for abnormal modifiers
80 int unexpectedModifiers =
81 ~(AccPublic | AccPrivate | AccProtected);// | AccStrictfp);
82 if ((realModifiers & unexpectedModifiers) != 0)
83 problemReporter().illegalModifierForMethod(
84 methodBinding.declaringClass,
85 (AbstractMethodDeclaration) referenceContext);
87 // (((AbstractMethodDeclaration) referenceContext).modifiers & AccStrictfp) != 0)
88 // // must check the parse node explicitly
89 // problemReporter().illegalModifierForMethod(
90 // methodBinding.declaringClass,
91 // (AbstractMethodDeclaration) referenceContext);
93 // check for incompatible modifiers in the visibility bits, isolate the visibility bits
94 int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate);
95 if ((accessorBits & (accessorBits - 1)) != 0) {
96 problemReporter().illegalVisibilityModifierCombinationForMethod(
97 methodBinding.declaringClass,
98 (AbstractMethodDeclaration) referenceContext);
100 // need to keep the less restrictive
101 if ((accessorBits & AccPublic) != 0) {
102 if ((accessorBits & AccProtected) != 0)
103 modifiers ^= AccProtected;
104 if ((accessorBits & AccPrivate) != 0)
105 modifiers ^= AccPrivate;
107 if ((accessorBits & AccProtected) != 0)
108 if ((accessorBits & AccPrivate) != 0)
109 modifiers ^= AccPrivate;
112 // 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)
113 if (methodBinding.declaringClass.isPrivate())
114 if ((modifiers & AccPrivate) != 0)
115 modifiers ^= AccPrivate;
117 methodBinding.modifiers = modifiers;
120 /* Spec : 8.4.3 & 9.4
122 private void checkAndSetModifiersForMethod(MethodBinding methodBinding) {
124 int modifiers = methodBinding.modifiers;
125 if ((modifiers & AccAlternateModifierProblem) != 0)
126 problemReporter().duplicateModifierForMethod(
127 methodBinding.declaringClass,
128 (AbstractMethodDeclaration) referenceContext);
130 // after this point, tests on the 16 bits reserved.
131 int realModifiers = modifiers & AccJustFlag;
133 // set the requested modifiers for a method in an interface
134 if (methodBinding.declaringClass.isInterface()) {
135 if ((realModifiers & ~(AccPublic | AccAbstract)) != 0)
136 problemReporter().illegalModifierForInterfaceMethod(
137 methodBinding.declaringClass,
138 (AbstractMethodDeclaration) referenceContext);
142 // check for abnormal modifiers
143 int unexpectedModifiers =
154 if ((realModifiers & unexpectedModifiers) != 0)
155 problemReporter().illegalModifierForMethod(
156 methodBinding.declaringClass,
157 (AbstractMethodDeclaration) referenceContext);
159 // check for incompatible modifiers in the visibility bits, isolate the visibility bits
160 int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate);
161 if ((accessorBits & (accessorBits - 1)) != 0) {
162 problemReporter().illegalVisibilityModifierCombinationForMethod(
163 methodBinding.declaringClass,
164 (AbstractMethodDeclaration) referenceContext);
166 // need to keep the less restrictive
167 if ((accessorBits & AccPublic) != 0) {
168 if ((accessorBits & AccProtected) != 0)
169 modifiers ^= AccProtected;
170 if ((accessorBits & AccPrivate) != 0)
171 modifiers ^= AccPrivate;
173 if ((accessorBits & AccProtected) != 0)
174 if ((accessorBits & AccPrivate) != 0)
175 modifiers ^= AccPrivate;
178 // check for modifiers incompatible with abstract modifier
179 if ((modifiers & AccAbstract) != 0) {
180 int incompatibleWithAbstract =
181 AccPrivate | AccStatic | AccFinal;// | AccSynchronized | AccNative | AccStrictfp;
182 if ((modifiers & incompatibleWithAbstract) != 0)
183 problemReporter().illegalAbstractModifierCombinationForMethod(
184 methodBinding.declaringClass,
185 (AbstractMethodDeclaration) referenceContext);
186 if (!methodBinding.declaringClass.isAbstract())
187 problemReporter().abstractMethodInAbstractClass(
188 (SourceTypeBinding) methodBinding.declaringClass,
189 (AbstractMethodDeclaration) referenceContext);
192 /* DISABLED for backward compatibility with javac (if enabled should also mark private methods as final)
193 // methods from a final class are final : 8.4.3.3
194 if (methodBinding.declaringClass.isFinal())
195 modifiers |= AccFinal;
197 // native methods cannot also be tagged as strictfp
198 // if ((modifiers & AccNative) != 0 && (modifiers & AccStrictfp) != 0)
199 // problemReporter().nativeMethodsCannotBeStrictfp(
200 // methodBinding.declaringClass,
201 // (AbstractMethodDeclaration) referenceContext);
203 // static members are only authorized in a static member or top level type
204 if (((realModifiers & AccStatic) != 0)
205 && methodBinding.declaringClass.isNestedType()
206 && !methodBinding.declaringClass.isStatic())
207 problemReporter().unexpectedStaticModifierForMethod(
208 methodBinding.declaringClass,
209 (AbstractMethodDeclaration) referenceContext);
211 methodBinding.modifiers = modifiers;
214 /* Compute variable positions in scopes given an initial position offset
215 * ignoring unused local variables.
217 * Deal with arguments here, locals and subscopes are processed in BlockScope method
219 // public void computeLocalVariablePositions(int initOffset, CodeStream codeStream) {
221 // boolean isReportingUnusedArgument = false;
223 // if (referenceContext instanceof AbstractMethodDeclaration) {
224 // AbstractMethodDeclaration methodDecl = (AbstractMethodDeclaration)referenceContext;
225 // MethodBinding method = methodDecl.binding;
226 // CompilerOptions options = compilationUnitScope().environment.options;
227 // if (!(method.isAbstract()
228 // || (method.isImplementing() && !options.reportUnusedParameterWhenImplementingAbstract)
229 // || (method.isOverriding() && !method.isImplementing() && !options.reportUnusedParameterWhenOverridingConcrete)
230 // || method.isMain())) {
231 // isReportingUnusedArgument = true;
234 // this.offset = initOffset;
235 // this.maxOffset = initOffset;
237 // // manage arguments
238 // int ilocal = 0, maxLocals = this.localIndex;
239 // while (ilocal < maxLocals) {
240 // LocalVariableBinding local = locals[ilocal];
241 // if (local == null || !local.isArgument) break; // done with arguments
243 // // do not report fake used variable
244 // if (isReportingUnusedArgument
245 // && local.useFlag == LocalVariableBinding.UNUSED
246 // && ((local.declaration.bits & AstNode.IsLocalDeclarationReachableMASK) != 0)) { // declaration is reachable
247 // this.problemReporter().unusedArgument(local.declaration);
250 // // record user-defined argument for attribute generation
251 // codeStream.record(local);
253 // // assign variable position
254 // local.resolvedPosition = this.offset;
256 // if ((local.type == LongBinding) || (local.type == DoubleBinding)) {
261 // // check for too many arguments/local variables
262 // if (this.offset > 0xFF) { // no more than 255 words of arguments
263 // this.problemReporter().noMoreAvailableSpaceForArgument(local, local.declaration);
268 // // sneak in extra argument before other local variables
269 // if (extraSyntheticArguments != null) {
270 // for (int iarg = 0, maxArguments = extraSyntheticArguments.length; iarg < maxArguments; iarg++){
271 // SyntheticArgumentBinding argument = extraSyntheticArguments[iarg];
272 // argument.resolvedPosition = this.offset;
273 // if ((argument.type == LongBinding) || (argument.type == DoubleBinding)){
278 // if (this.offset > 0xFF) { // no more than 255 words of arguments
279 // this.problemReporter().noMoreAvailableSpaceForArgument(argument, (AstNode)this.referenceContext);
283 // this.computeLocalVariablePositions(ilocal, this.offset, codeStream);
287 * keep null for all the errors that prevent the method to be created
288 * otherwise return a correct method binding (but without the element
289 * that caused the problem) : ie : Incorrect thrown exception
291 MethodBinding createMethod(AbstractMethodDeclaration method) {
293 // is necessary to ensure error reporting
294 this.referenceContext = method;
296 SourceTypeBinding declaringClass = referenceType().binding;
297 int modifiers = method.modifiers | AccUnresolved;
298 if (method.isConstructor()) {
299 method.binding = new MethodBinding(modifiers, null, null, declaringClass);
300 checkAndSetModifiersForConstructor(method.binding);
302 if (declaringClass.isInterface())
303 modifiers |= AccPublic | AccAbstract;
305 new MethodBinding(modifiers, method.selector, null, null, null, declaringClass);
306 checkAndSetModifiersForMethod(method.binding);
309 this.isStatic = method.binding.isStatic();
310 return method.binding;
313 /* Overridden to detect the error case inside an explicit constructor call:
319 this(i, myX.i, x.i); // same for super calls... only the first 2 field accesses are errors
323 public FieldBinding findField(
324 TypeBinding receiverType,
326 InvocationSite invocationSite) {
328 FieldBinding field = super.findField(receiverType, fieldName, invocationSite);
331 if (!field.isValidBinding())
332 return field; // answer the error field
333 if (field.isStatic())
334 return field; // static fields are always accessible
336 if (!isConstructorCall || receiverType != enclosingSourceType())
339 if (invocationSite instanceof SingleNameReference)
340 return new ProblemFieldBinding(
341 field.declaringClass,
343 NonStaticReferenceInConstructorInvocation);
344 if (invocationSite instanceof QualifiedNameReference) {
345 // look to see if the field is the first binding
346 QualifiedNameReference name = (QualifiedNameReference) invocationSite;
347 if (name.binding == null)
348 // only true when the field is the fieldbinding at the beginning of name's tokens
349 return new ProblemFieldBinding(
350 field.declaringClass,
352 NonStaticReferenceInConstructorInvocation);
357 public boolean isInsideInitializer() {
359 return (referenceContext instanceof TypeDeclaration);
362 public boolean isInsideInitializerOrConstructor() {
364 return (referenceContext instanceof TypeDeclaration)
365 || (referenceContext instanceof ConstructorDeclaration);
368 /* Answer the problem reporter to use for raising new problems.
370 * Note that as a side-effect, this updates the current reference context
371 * (unit, type or method) in case the problem handler decides it is necessary
374 public ProblemReporter problemReporter() {
376 MethodScope outerMethodScope;
377 if ((outerMethodScope = outerMostMethodScope()) == this) {
378 ProblemReporter problemReporter = referenceCompilationUnit().problemReporter;
379 problemReporter.referenceContext = referenceContext;
380 return problemReporter;
382 return outerMethodScope.problemReporter();
386 public final int recordInitializationStates(FlowInfo flowInfo) {
388 if (!flowInfo.isReachable()) return -1;
390 UnconditionalFlowInfo unconditionalFlowInfo = flowInfo.unconditionalInits();
391 long[] extraInits = unconditionalFlowInfo.extraDefiniteInits;
392 long inits = unconditionalFlowInfo.definiteInits;
393 checkNextEntry : for (int i = lastIndex; --i >= 0;) {
394 if (definiteInits[i] == inits) {
395 long[] otherInits = extraDefiniteInits[i];
396 if ((extraInits != null) && (otherInits != null)) {
397 if (extraInits.length == otherInits.length) {
399 for (j = 0, max = extraInits.length; j < max; j++) {
400 if (extraInits[j] != otherInits[j]) {
401 continue checkNextEntry;
407 if ((extraInits == null) && (otherInits == null)) {
415 if (definiteInits.length == lastIndex) {
420 (definiteInits = new long[lastIndex + 20]),
426 (extraDefiniteInits = new long[lastIndex + 20][]),
430 definiteInits[lastIndex] = inits;
431 if (extraInits != null) {
432 extraDefiniteInits[lastIndex] = new long[extraInits.length];
436 extraDefiniteInits[lastIndex],
443 /* Answer the reference type of this scope.
445 * It is the nearest enclosing type of this scope.
447 public TypeDeclaration referenceType() {
449 return (TypeDeclaration) ((ClassScope) parent).referenceContext;
452 String basicToString(int tab) {
454 String newLine = "\n"; //$NON-NLS-1$
455 for (int i = tab; --i >= 0;)
456 newLine += "\t"; //$NON-NLS-1$
458 String s = newLine + "--- Method Scope ---"; //$NON-NLS-1$
459 newLine += "\t"; //$NON-NLS-1$
460 s += newLine + "locals:"; //$NON-NLS-1$
461 for (int i = 0; i < localIndex; i++)
462 s += newLine + "\t" + locals[i].toString(); //$NON-NLS-1$
463 s += newLine + "startIndex = " + startIndex; //$NON-NLS-1$
464 s += newLine + "isConstructorCall = " + isConstructorCall; //$NON-NLS-1$
465 s += newLine + "fieldDeclarationIndex = " + fieldDeclarationIndex; //$NON-NLS-1$
466 s += newLine + "referenceContext = " + referenceContext; //$NON-NLS-1$