Пример #1
0
  public void generatePostIncrement(
      BlockScope currentScope, CompoundAssignment postIncrement, boolean valueRequired) {
    switch (this.bits & ASTNode.RestrictiveFlagMASK) {
      case Binding.FIELD: // assigning to a field
        FieldBinding fieldBinding = (FieldBinding) this.binding;
        // https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682
        // check if postIncrement is the only usage of a private field
        reportOnlyUselesslyReadPrivateField(currentScope, fieldBinding, valueRequired);
        FieldBinding codegenField = fieldBinding.original();

        fieldStore(
            currentScope,
            codegenField,
            this.syntheticAccessors == null
                ? null
                : this.syntheticAccessors[SingleNameReference.WRITE],
            this.actualReceiverType,
            true /*implicit this*/,
            false);
        // no need for generic cast
        return;
      case Binding.LOCAL: // assigning to a local variable
        LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
        // https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682
        // check if postIncrement is the only usage of this local
        Reference.reportOnlyUselesslyReadLocal(currentScope, localBinding, valueRequired);
        if (localBinding.resolvedPosition == -1) {
          if (valueRequired) {
            // restart code gen
            localBinding.useFlag = LocalVariableBinding.USED;
            throw new AbortMethod(null, null);
          }
        }
    }
  }
Пример #2
0
 public void generateCode(BlockScope currentScope, boolean valueRequired) {
   if (this.constant != Constant.NotAConstant) {
     return;
   } else {
     switch (this.bits & ASTNode.RestrictiveFlagMASK) {
       case Binding.FIELD: // reading a field
         FieldBinding codegenField = ((FieldBinding) this.binding).original();
         Constant fieldConstant = codegenField.constant();
         if (fieldConstant != Constant.NotAConstant) {
           return;
         }
         if (codegenField.isStatic()) {
           if (!valueRequired
               // if no valueRequired, still need possible side-effects of <clinit> invocation,
               // if field belongs to different class
               && ((FieldBinding) this.binding).original().declaringClass
                   == this.actualReceiverType.erasure()
               && ((this.implicitConversion & TypeIds.UNBOXING) == 0)
               && this.genericCast == null) {
             // if no valueRequired, optimize out entire gen
             return;
           }
         } else {
           if (!valueRequired
               && (this.implicitConversion & TypeIds.UNBOXING) == 0
               && this.genericCast == null) {
             // if no valueRequired, optimize out entire gen
             return;
           }
         }
         break;
       case Binding.LOCAL: // reading a local
         LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
         if (localBinding.resolvedPosition == -1) {
           if (valueRequired) {
             // restart code gen
             localBinding.useFlag = LocalVariableBinding.USED;
             throw new AbortMethod(null, null);
           }
           return;
         }
         if (!valueRequired && (this.implicitConversion & TypeIds.UNBOXING) == 0) {
           // if no valueRequired, optimize out entire gen
           return;
         }
         break;
       default: // type
         return;
     }
   }
 }
Пример #3
0
 public FlowInfo analyseCode(
     BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
   switch (this.bits & ASTNode.RestrictiveFlagMASK) {
     case Binding.FIELD: // reading a field
       if (valueRequired
           || currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) {
         manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/);
       }
       // check if reading a final blank field
       FieldBinding fieldBinding = (FieldBinding) this.binding;
       if (fieldBinding.isBlankFinal()
           && currentScope.needBlankFinalFieldInitializationCheck(fieldBinding)) {
         FlowInfo fieldInits =
             flowContext.getInitsForFinalBlankInitializationCheck(
                 fieldBinding.declaringClass.original(), flowInfo);
         if (!fieldInits.isDefinitelyAssigned(fieldBinding)) {
           currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
         }
       }
       if (!fieldBinding.isStatic()) {
         // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318682
         currentScope.resetEnclosingMethodStaticFlag();
       }
       break;
     case Binding.LOCAL: // reading a local variable
       LocalVariableBinding localBinding;
       if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) this.binding)) {
         currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
       }
       if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
         localBinding.useFlag = LocalVariableBinding.USED;
       } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
         localBinding.useFlag = LocalVariableBinding.FAKE_USED;
       }
   }
   if (valueRequired) {
     manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
   }
   return flowInfo;
 }
Пример #4
0
  public FlowInfo analyseAssignment(
      BlockScope currentScope,
      FlowContext flowContext,
      FlowInfo flowInfo,
      Assignment assignment,
      boolean isCompound) {
    boolean isReachable = (flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0;
    // compound assignment extra work
    if (isCompound) { // check the variable part is initialized if blank final
      switch (this.bits & ASTNode.RestrictiveFlagMASK) {
        case Binding.FIELD: // reading a field
          FieldBinding fieldBinding = (FieldBinding) this.binding;
          if (fieldBinding.isBlankFinal()
              && currentScope.needBlankFinalFieldInitializationCheck(fieldBinding)) {
            FlowInfo fieldInits =
                flowContext.getInitsForFinalBlankInitializationCheck(
                    fieldBinding.declaringClass.original(), flowInfo);
            if (!fieldInits.isDefinitelyAssigned(fieldBinding)) {
              currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
            }
          }
          if (!fieldBinding.isStatic()) {
            // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318682
            currentScope.resetEnclosingMethodStaticFlag();
          }
          manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/);
          break;
        case Binding.LOCAL: // reading a local variable
          // check if assigning a final blank field
          LocalVariableBinding localBinding;
          if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) this.binding)) {
            currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
            // we could improve error msg here telling "cannot use compound assignment on final
            // local variable"
          }
          if (localBinding.useFlag != LocalVariableBinding.USED) {
            // https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682
            // access from compound assignment does not prevent "unused" warning, unless unboxing is
            // involved:
            if (isReachable && (this.implicitConversion & TypeIds.UNBOXING) != 0) {
              localBinding.useFlag = LocalVariableBinding.USED;
            } else {
              // use values < 0 to count the number of compound uses:
              if (localBinding.useFlag <= LocalVariableBinding.UNUSED) localBinding.useFlag--;
            }
          }
      }
    }
    if (assignment.expression != null) {
      flowInfo =
          assignment
              .expression
              .analyseCode(currentScope, flowContext, flowInfo)
              .unconditionalInits();
    }
    switch (this.bits & ASTNode.RestrictiveFlagMASK) {
      case Binding.FIELD: // assigning to a field
        manageSyntheticAccessIfNecessary(currentScope, flowInfo, false /*write-access*/);

        // check if assigning a final field
        FieldBinding fieldBinding = (FieldBinding) this.binding;
        if (fieldBinding.isFinal()) {
          // inside a context where allowed
          if (!isCompound
              && fieldBinding.isBlankFinal()
              && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
            if (flowInfo.isPotentiallyAssigned(fieldBinding)) {
              currentScope
                  .problemReporter()
                  .duplicateInitializationOfBlankFinalField(fieldBinding, this);
            } else {
              flowContext.recordSettingFinal(fieldBinding, this, flowInfo);
            }
            flowInfo.markAsDefinitelyAssigned(fieldBinding);
          } else {
            currentScope.problemReporter().cannotAssignToFinalField(fieldBinding, this);
          }
        }
        if (!fieldBinding.isStatic()) {
          // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318682
          currentScope.resetEnclosingMethodStaticFlag();
        }
        break;
      case Binding.LOCAL: // assigning to a local variable
        LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
        if (!flowInfo.isDefinitelyAssigned(localBinding)) { // for local variable debug attributes
          this.bits |= ASTNode.FirstAssignmentToLocal;
        } else {
          this.bits &= ~ASTNode.FirstAssignmentToLocal;
        }
        if (localBinding.isFinal()) {
          if ((this.bits & ASTNode.DepthMASK) == 0) {
            // tolerate assignment to final local in unreachable code (45674)
            if ((isReachable && isCompound) || !localBinding.isBlankFinal()) {
              currentScope.problemReporter().cannotAssignToFinalLocal(localBinding, this);
            } else if (flowInfo.isPotentiallyAssigned(localBinding)) {
              currentScope
                  .problemReporter()
                  .duplicateInitializationOfFinalLocal(localBinding, this);
            } else {
              flowContext.recordSettingFinal(localBinding, this, flowInfo);
            }
          } else {
            currentScope.problemReporter().cannotAssignToFinalOuterLocal(localBinding, this);
          }
        } else /* avoid double diagnostic */ if ((localBinding.tagBits & TagBits.IsArgument) != 0) {
          currentScope.problemReporter().parameterAssignment(localBinding, this);
        }
        flowInfo.markAsDefinitelyAssigned(localBinding);
    }
    manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
    return flowInfo;
  }
Пример #5
0
 /*
  * The APIs with an extra argument is used whenever there are two references to the same variable which
  * are optimized in one access: e.g "a = a + 1" optimized into "a++".
  */
 public void generateCompoundAssignment(
     BlockScope currentScope,
     MethodBinding writeAccessor,
     Expression expression,
     int operator,
     int assignmentImplicitConversion,
     boolean valueRequired) {
   switch (this.bits & ASTNode.RestrictiveFlagMASK) {
     case Binding.FIELD: // assigning to a field
       break;
     case Binding.LOCAL: // assigning to a local variable (cannot assign to outer local)
       LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
       // using incr bytecode if possible
       Constant assignConstant;
       switch (localBinding.type.id) {
         case T_JavaLangString:
           return;
         case T_int:
           assignConstant = expression.constant;
           if (localBinding.resolvedPosition == -1) {
             if (valueRequired) {
               /*
                * restart code gen because we either:
                * - need the value
                * - the constant can have potential side-effect
                */
               localBinding.useFlag = LocalVariableBinding.USED;
               throw new AbortMethod(null, null);
             } else if (assignConstant == Constant.NotAConstant) {
               // we only need to generate the value of the expression's constant if it is not a
               // constant expression
               expression.generateCode(currentScope, false);
             }
             return;
           }
           if ((assignConstant != Constant.NotAConstant)
               && (assignConstant.typeID() != TypeIds.T_float)
               // only for integral types
               && (assignConstant.typeID()
                   != TypeIds.T_double)) { // TODO (philippe) is this test needed ?
             switch (operator) {
               case PLUS:
                 int increment = assignConstant.intValue();
                 if (increment != (short) increment) break; // not representable as a 16-bits value
                 return;
               case MINUS:
                 increment = -assignConstant.intValue();
                 if (increment != (short) increment) break; // not representable as a 16-bits value
                 return;
             }
           }
           // $FALL-THROUGH$
         default:
           if (localBinding.resolvedPosition == -1) {
             assignConstant = expression.constant;
             if (valueRequired) {
               /*
                * restart code gen because we either:
                * - need the value
                * - the constant can have potential side-effect
                */
               localBinding.useFlag = LocalVariableBinding.USED;
               throw new AbortMethod(null, null);
             } else if (assignConstant == Constant.NotAConstant) {
               // we only need to generate the value of the expression's constant if it is not a
               // constant expression
               expression.generateCode(currentScope, false);
             }
             return;
           }
       }
   }
   switch ((this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4) {
     case T_JavaLangString:
     case T_JavaLangObject:
     case T_undefined:
       // we enter here if the single name reference is a field of type java.lang.String or if the
       // type of the
       // operation is java.lang.Object
       // For example: o = o + ""; // where the compiled type of o is java.lang.Object.
       // no need for generic cast on previous #getfield since using Object string buffer methods.
       break;
     default:
       // promote the array reference to the suitable operation type
       // generate the increment value (will by itself  be promoted to the operation value)
       if (expression != IntLiteral.One) { // prefix operation
         expression.generateCode(currentScope, true);
       }
   }
   // store the result back into the variable
   switch (this.bits & ASTNode.RestrictiveFlagMASK) {
     case Binding.FIELD: // assigning to a field
       FieldBinding codegenField = ((FieldBinding) this.binding).original();
       fieldStore(
           currentScope,
           codegenField,
           writeAccessor,
           this.actualReceiverType,
           true /* implicit this*/,
           valueRequired);
       // no need for generic cast as value got dupped
       return;
     case Binding.LOCAL: // assigning to a local variable
       LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
       if (valueRequired) {
         switch (localBinding.type.id) {
           case TypeIds.T_long:
           case TypeIds.T_double:
             break;
           default:
             break;
         }
       }
   }
 }