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.lookup.FieldBinding;
 
  15 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
 
  16 import net.sourceforge.phpdt.internal.compiler.flow.UnconditionalFlowInfo;
 
  17 import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext;
 
  18 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
 
  19 import net.sourceforge.phpeclipse.internal.compiler.ast.AbstractMethodDeclaration;
 
  20 import net.sourceforge.phpeclipse.internal.compiler.ast.ConstructorDeclaration;
 
  21 import net.sourceforge.phpeclipse.internal.compiler.ast.QualifiedNameReference;
 
  22 import net.sourceforge.phpeclipse.internal.compiler.ast.SingleNameReference;
 
  23 import net.sourceforge.phpeclipse.internal.compiler.ast.TypeDeclaration;
 
  26  * Particular block scope used for methods, constructors or clinits, representing
 
  27  * its outermost blockscope. Note also that such a scope will be provided to enclose
 
  28  * field initializers subscopes as well.
 
  30 public class MethodScope extends BlockScope {
 
  32         public ReferenceContext referenceContext;
 
  33         public boolean isStatic; // method modifier or initializer one
 
  35         //fields used during name resolution
 
  36         public static final int NotInFieldDecl = -1; //must be a negative value 
 
  37         public boolean isConstructorCall = false; 
 
  38         public FieldBinding initializedField; // the field being initialized
 
  39         public int fieldDeclarationIndex = NotInFieldDecl; 
 
  42         public int analysisIndex; // for setting flow-analysis id
 
  43         public boolean isPropagatingInnerClassEmulation;
 
  45         // for local variables table attributes
 
  46         public int lastIndex = 0;
 
  47         public long[] definiteInits = new long[4];
 
  48         public long[][] extraDefiniteInits = new long[4][];
 
  51         public SyntheticArgumentBinding[] extraSyntheticArguments;
 
  53         public MethodScope(ClassScope parent, ReferenceContext context, boolean isStatic) {
 
  55                 super(METHOD_SCOPE, parent);
 
  56                 locals = new LocalVariableBinding[5];
 
  57                 this.referenceContext = context;
 
  58                 this.isStatic = isStatic;
 
  64         private void checkAndSetModifiersForConstructor(MethodBinding methodBinding) {
 
  66                 int modifiers = methodBinding.modifiers;
 
  67                 if ((modifiers & AccAlternateModifierProblem) != 0)
 
  68                         problemReporter().duplicateModifierForMethod(
 
  69                                 methodBinding.declaringClass,
 
  70                                 (AbstractMethodDeclaration) referenceContext);
 
  72                 if (((ConstructorDeclaration) referenceContext).isDefaultConstructor) {
 
  73                         if (methodBinding.declaringClass.isPublic())
 
  74                                 modifiers |= AccPublic;
 
  75                         else if (methodBinding.declaringClass.isProtected())
 
  76                                 modifiers |= AccProtected;
 
  79                 // after this point, tests on the 16 bits reserved.
 
  80                 int realModifiers = modifiers & AccJustFlag;
 
  82                 // check for abnormal modifiers
 
  83                 int unexpectedModifiers =
 
  84                         ~(AccPublic | AccPrivate | AccProtected);// | AccStrictfp);
 
  85                 if ((realModifiers & unexpectedModifiers) != 0)
 
  86                         problemReporter().illegalModifierForMethod(
 
  87                                 methodBinding.declaringClass,
 
  88                                 (AbstractMethodDeclaration) referenceContext);
 
  90 //                      (((AbstractMethodDeclaration) referenceContext).modifiers & AccStrictfp) != 0)
 
  91 //                      // must check the parse node explicitly
 
  92 //                      problemReporter().illegalModifierForMethod(
 
  93 //                              methodBinding.declaringClass,
 
  94 //                              (AbstractMethodDeclaration) referenceContext);
 
  96                 // check for incompatible modifiers in the visibility bits, isolate the visibility bits
 
  97                 int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate);
 
  98                 if ((accessorBits & (accessorBits - 1)) != 0) {
 
  99                         problemReporter().illegalVisibilityModifierCombinationForMethod(
 
 100                                 methodBinding.declaringClass,
 
 101                                 (AbstractMethodDeclaration) referenceContext);
 
 103                         // need to keep the less restrictive
 
 104                         if ((accessorBits & AccPublic) != 0) {
 
 105                                 if ((accessorBits & AccProtected) != 0)
 
 106                                         modifiers ^= AccProtected;
 
 107                                 if ((accessorBits & AccPrivate) != 0)
 
 108                                         modifiers ^= AccPrivate;
 
 110                         if ((accessorBits & AccProtected) != 0)
 
 111                                 if ((accessorBits & AccPrivate) != 0)
 
 112                                         modifiers ^= AccPrivate;
 
 115                 // 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)
 
 116                 if (methodBinding.declaringClass.isPrivate())
 
 117                         if ((modifiers & AccPrivate) != 0)
 
 118                                 modifiers ^= AccPrivate;
 
 120                 methodBinding.modifiers = modifiers;
 
 123         /* Spec : 8.4.3 & 9.4
 
 125         private void checkAndSetModifiersForMethod(MethodBinding methodBinding) {
 
 127                 int modifiers = methodBinding.modifiers;
 
 128                 if ((modifiers & AccAlternateModifierProblem) != 0)
 
 129                         problemReporter().duplicateModifierForMethod(
 
 130                                 methodBinding.declaringClass,
 
 131                                 (AbstractMethodDeclaration) referenceContext);
 
 133                 // after this point, tests on the 16 bits reserved.
 
 134                 int realModifiers = modifiers & AccJustFlag;
 
 136                 // set the requested modifiers for a method in an interface
 
 137                 if (methodBinding.declaringClass.isInterface()) {
 
 138                         if ((realModifiers & ~(AccPublic | AccAbstract)) != 0)
 
 139                                 problemReporter().illegalModifierForInterfaceMethod(
 
 140                                         methodBinding.declaringClass,
 
 141                                         (AbstractMethodDeclaration) referenceContext);
 
 145                 // check for abnormal modifiers
 
 146                 int unexpectedModifiers =
 
 157                 if ((realModifiers & unexpectedModifiers) != 0)
 
 158                         problemReporter().illegalModifierForMethod(
 
 159                                 methodBinding.declaringClass,
 
 160                                 (AbstractMethodDeclaration) referenceContext);
 
 162                 // check for incompatible modifiers in the visibility bits, isolate the visibility bits
 
 163                 int accessorBits = realModifiers & (AccPublic | AccProtected | AccPrivate);
 
 164                 if ((accessorBits & (accessorBits - 1)) != 0) {
 
 165                         problemReporter().illegalVisibilityModifierCombinationForMethod(
 
 166                                 methodBinding.declaringClass,
 
 167                                 (AbstractMethodDeclaration) referenceContext);
 
 169                         // need to keep the less restrictive
 
 170                         if ((accessorBits & AccPublic) != 0) {
 
 171                                 if ((accessorBits & AccProtected) != 0)
 
 172                                         modifiers ^= AccProtected;
 
 173                                 if ((accessorBits & AccPrivate) != 0)
 
 174                                         modifiers ^= AccPrivate;
 
 176                         if ((accessorBits & AccProtected) != 0)
 
 177                                 if ((accessorBits & AccPrivate) != 0)
 
 178                                         modifiers ^= AccPrivate;
 
 181                 // check for modifiers incompatible with abstract modifier
 
 182                 if ((modifiers & AccAbstract) != 0) {
 
 183                         int incompatibleWithAbstract =
 
 184                                 AccPrivate | AccStatic | AccFinal;// | AccSynchronized | AccNative | AccStrictfp;
 
 185                         if ((modifiers & incompatibleWithAbstract) != 0)
 
 186                                 problemReporter().illegalAbstractModifierCombinationForMethod(
 
 187                                         methodBinding.declaringClass,
 
 188                                         (AbstractMethodDeclaration) referenceContext);
 
 189                         if (!methodBinding.declaringClass.isAbstract())
 
 190                                 problemReporter().abstractMethodInAbstractClass(
 
 191                                         (SourceTypeBinding) methodBinding.declaringClass,
 
 192                                         (AbstractMethodDeclaration) referenceContext);
 
 195                 /* DISABLED for backward compatibility with javac (if enabled should also mark private methods as final)
 
 196                 // methods from a final class are final : 8.4.3.3 
 
 197                 if (methodBinding.declaringClass.isFinal())
 
 198                         modifiers |= AccFinal;
 
 200                 // native methods cannot also be tagged as strictfp
 
 201 //              if ((modifiers & AccNative) != 0 && (modifiers & AccStrictfp) != 0)
 
 202 //                      problemReporter().nativeMethodsCannotBeStrictfp(
 
 203 //                              methodBinding.declaringClass,
 
 204 //                              (AbstractMethodDeclaration) referenceContext);
 
 206                 // static members are only authorized in a static member or top level type
 
 207                 if (((realModifiers & AccStatic) != 0)
 
 208                         && methodBinding.declaringClass.isNestedType()
 
 209                         && !methodBinding.declaringClass.isStatic())
 
 210                         problemReporter().unexpectedStaticModifierForMethod(
 
 211                                 methodBinding.declaringClass,
 
 212                                 (AbstractMethodDeclaration) referenceContext);
 
 214                 methodBinding.modifiers = modifiers;
 
 217         /* Compute variable positions in scopes given an initial position offset
 
 218          * ignoring unused local variables.
 
 220          * Deal with arguments here, locals and subscopes are processed in BlockScope method
 
 222 //      public void computeLocalVariablePositions(int initOffset, CodeStream codeStream) {
 
 224 //              boolean isReportingUnusedArgument = false;
 
 226 //              if (referenceContext instanceof AbstractMethodDeclaration) {
 
 227 //                      AbstractMethodDeclaration methodDecl = (AbstractMethodDeclaration)referenceContext;
 
 228 //                      MethodBinding method = methodDecl.binding;
 
 229 //                      CompilerOptions options = compilationUnitScope().environment.options;
 
 230 //                      if (!(method.isAbstract()
 
 231 //                                      || (method.isImplementing() && !options.reportUnusedParameterWhenImplementingAbstract) 
 
 232 //                                      || (method.isOverriding() && !method.isImplementing() && !options.reportUnusedParameterWhenOverridingConcrete)
 
 233 //                                      || method.isMain())) {
 
 234 //                              isReportingUnusedArgument = true;
 
 237 //              this.offset = initOffset;
 
 238 //              this.maxOffset = initOffset;
 
 240 //              // manage arguments     
 
 241 //              int ilocal = 0, maxLocals = this.localIndex;    
 
 242 //              while (ilocal < maxLocals) {
 
 243 //                      LocalVariableBinding local = locals[ilocal];
 
 244 //                      if (local == null || !local.isArgument) break; // done with arguments
 
 246 //                      // do not report fake used variable
 
 247 //                      if (isReportingUnusedArgument
 
 248 //                                      && local.useFlag == LocalVariableBinding.UNUSED
 
 249 //                                      && ((local.declaration.bits & ASTNode.IsLocalDeclarationReachableMASK) != 0)) { // declaration is reachable
 
 250 //                              this.problemReporter().unusedArgument(local.declaration);
 
 253 //                      // record user-defined argument for attribute generation
 
 254 //                      codeStream.record(local); 
 
 256 //                      // assign variable position
 
 257 //                      local.resolvedPosition = this.offset;
 
 259 //                      if ((local.type == LongBinding) || (local.type == DoubleBinding)) {
 
 264 //                      // check for too many arguments/local variables
 
 265 //                      if (this.offset > 0xFF) { // no more than 255 words of arguments
 
 266 //                              this.problemReporter().noMoreAvailableSpaceForArgument(local, local.declaration);
 
 271 //              // sneak in extra argument before other local variables
 
 272 //              if (extraSyntheticArguments != null) {
 
 273 //                      for (int iarg = 0, maxArguments = extraSyntheticArguments.length; iarg < maxArguments; iarg++){
 
 274 //                              SyntheticArgumentBinding argument = extraSyntheticArguments[iarg];
 
 275 //                              argument.resolvedPosition = this.offset;
 
 276 //                              if ((argument.type == LongBinding) || (argument.type == DoubleBinding)){
 
 281 //                              if (this.offset > 0xFF) { // no more than 255 words of arguments
 
 282 //                                      this.problemReporter().noMoreAvailableSpaceForArgument(argument, (ASTNode)this.referenceContext); 
 
 286 //              this.computeLocalVariablePositions(ilocal, this.offset, codeStream);
 
 290          *              keep null for all the errors that prevent the method to be created
 
 291          *              otherwise return a correct method binding (but without the element
 
 292          *              that caused the problem) : ie : Incorrect thrown exception
 
 294         MethodBinding createMethod(AbstractMethodDeclaration method) {
 
 296                 // is necessary to ensure error reporting
 
 297                 this.referenceContext = method;
 
 299                 SourceTypeBinding declaringClass = referenceType().binding;
 
 300                 int modifiers = method.modifiers | AccUnresolved;
 
 301                 if (method.isConstructor()) {
 
 302                         method.binding = new MethodBinding(modifiers, null, null, declaringClass);
 
 303                         checkAndSetModifiersForConstructor(method.binding);
 
 305                         if (declaringClass.isInterface())
 
 306                                 modifiers |= AccPublic | AccAbstract;
 
 308                                 new MethodBinding(modifiers, method.selector, null, null, null, declaringClass);
 
 309                         checkAndSetModifiersForMethod(method.binding);
 
 312                 this.isStatic = method.binding.isStatic();
 
 313                 return method.binding;
 
 316         /* Overridden to detect the error case inside an explicit constructor call:
 
 322                         this(i, myX.i, x.i); // same for super calls... only the first 2 field accesses are errors
 
 326         public FieldBinding findField(
 
 327                 TypeBinding receiverType,
 
 329                 InvocationSite invocationSite) {
 
 331                 FieldBinding field = super.findField(receiverType, fieldName, invocationSite);
 
 334                 if (!field.isValidBinding())
 
 335                         return field; // answer the error field
 
 336                 if (field.isStatic())
 
 337                         return field; // static fields are always accessible
 
 339                 if (!isConstructorCall || receiverType != enclosingSourceType())
 
 342                 if (invocationSite instanceof SingleNameReference)
 
 343                         return new ProblemFieldBinding(
 
 344                                 field.declaringClass,
 
 346                                 NonStaticReferenceInConstructorInvocation);
 
 347                 if (invocationSite instanceof QualifiedNameReference) {
 
 348                         // look to see if the field is the first binding
 
 349                         QualifiedNameReference name = (QualifiedNameReference) invocationSite;
 
 350                         if (name.binding == null)
 
 351                                 // only true when the field is the fieldbinding at the beginning of name's tokens
 
 352                                 return new ProblemFieldBinding(
 
 353                                         field.declaringClass,
 
 355                                         NonStaticReferenceInConstructorInvocation);
 
 360         public boolean isInsideInitializer() {
 
 362                 return (referenceContext instanceof TypeDeclaration);
 
 365         public boolean isInsideInitializerOrConstructor() {
 
 367                 return (referenceContext instanceof TypeDeclaration)
 
 368                         || (referenceContext instanceof ConstructorDeclaration);
 
 371         /* Answer the problem reporter to use for raising new problems.
 
 373          * Note that as a side-effect, this updates the current reference context
 
 374          * (unit, type or method) in case the problem handler decides it is necessary
 
 377         public ProblemReporter problemReporter() {
 
 379                 MethodScope outerMethodScope;
 
 380                 if ((outerMethodScope = outerMostMethodScope()) == this) {
 
 381                         ProblemReporter problemReporter = referenceCompilationUnit().problemReporter;
 
 382                         problemReporter.referenceContext = referenceContext;
 
 383                         return problemReporter;
 
 385                         return outerMethodScope.problemReporter();
 
 389         public final int recordInitializationStates(FlowInfo flowInfo) {
 
 391                 if (!flowInfo.isReachable()) return -1;
 
 393                 UnconditionalFlowInfo unconditionalFlowInfo = flowInfo.unconditionalInits();
 
 394                 long[] extraInits = unconditionalFlowInfo.extraDefiniteInits;
 
 395                 long inits = unconditionalFlowInfo.definiteInits;
 
 396                 checkNextEntry : for (int i = lastIndex; --i >= 0;) {
 
 397                         if (definiteInits[i] == inits) {
 
 398                                 long[] otherInits = extraDefiniteInits[i];
 
 399                                 if ((extraInits != null) && (otherInits != null)) {
 
 400                                         if (extraInits.length == otherInits.length) {
 
 402                                                 for (j = 0, max = extraInits.length; j < max; j++) {
 
 403                                                         if (extraInits[j] != otherInits[j]) {
 
 404                                                                 continue checkNextEntry;
 
 410                                         if ((extraInits == null) && (otherInits == null)) {
 
 418                 if (definiteInits.length == lastIndex) {
 
 423                                 (definiteInits = new long[lastIndex + 20]),
 
 429                                 (extraDefiniteInits = new long[lastIndex + 20][]),
 
 433                 definiteInits[lastIndex] = inits;
 
 434                 if (extraInits != null) {
 
 435                         extraDefiniteInits[lastIndex] = new long[extraInits.length];
 
 439                                 extraDefiniteInits[lastIndex],
 
 446         /* Answer the reference type of this scope.
 
 448         * It is the nearest enclosing type of this scope.
 
 450         public TypeDeclaration referenceType() {
 
 452                 return (TypeDeclaration) ((ClassScope) parent).referenceContext;
 
 455         String basicToString(int tab) {
 
 457                 String newLine = "\n"; //$NON-NLS-1$
 
 458                 for (int i = tab; --i >= 0;)
 
 459                         newLine += "\t"; //$NON-NLS-1$
 
 461                 String s = newLine + "--- Method Scope ---"; //$NON-NLS-1$
 
 462                 newLine += "\t"; //$NON-NLS-1$
 
 463                 s += newLine + "locals:"; //$NON-NLS-1$
 
 464                 for (int i = 0; i < localIndex; i++)
 
 465                         s += newLine + "\t" + locals[i].toString(); //$NON-NLS-1$
 
 466                 s += newLine + "startIndex = " + startIndex; //$NON-NLS-1$
 
 467                 s += newLine + "isConstructorCall = " + isConstructorCall; //$NON-NLS-1$
 
 468                 s += newLine + "initializedField = " + initializedField; //$NON-NLS-1$
 
 469                 s += newLine + "fieldDeclarationIndex = " + fieldDeclarationIndex; //$NON-NLS-1$
 
 470                 s += newLine + "referenceContext = " + referenceContext; //$NON-NLS-1$