public TypeBinding resolveType(BlockScope scope) {
    this.constant = Constant.NotAConstant;
    TypeBinding expressionType = this.expression.resolveType(scope);
    TypeBinding checkedType = this.type.resolveType(scope, true /* check bounds*/);
    if (expressionType == null || checkedType == null) return null;

    if (!checkedType.isReifiable()) {
      scope.problemReporter().illegalInstanceOfGenericType(checkedType, this);
    } else if ((expressionType != TypeBinding.NULL
            && expressionType.isBaseType()) // disallow autoboxing
        || !checkCastTypesCompatibility(scope, checkedType, expressionType, null)) {
      scope.problemReporter().notCompatibleTypesError(this, expressionType, checkedType);
    }
    return this.resolvedType = TypeBinding.BOOLEAN;
  }
 public void resolve(BlockScope scope) {
   this.assertExpression.resolveTypeExpecting(scope, TypeBinding.BOOLEAN);
   if (this.exceptionArgument != null) {
     TypeBinding exceptionArgumentType = this.exceptionArgument.resolveType(scope);
     if (exceptionArgumentType != null) {
       int id = exceptionArgumentType.id;
       switch (id) {
         case T_void:
           scope.problemReporter().illegalVoidExpression(this.exceptionArgument);
           // $FALL-THROUGH$
         default:
           id = T_JavaLangObject;
           // $FALL-THROUGH$
         case T_boolean:
         case T_byte:
         case T_char:
         case T_short:
         case T_double:
         case T_float:
         case T_int:
         case T_long:
         case T_JavaLangString:
           this.exceptionArgument.implicitConversion = (id << 4) + id;
       }
     }
   }
 }
 /**
  * @see
  *     org.eclipse.jdt.internal.compiler.ast.BinaryExpression#resolveType(org.eclipse.jdt.internal.compiler.lookup.BlockScope)
  */
 public TypeBinding resolveType(BlockScope scope) {
   TypeBinding result = super.resolveType(scope);
   // check whether comparing identical expressions
   Binding leftDirect = Expression.getDirectBinding(this.left);
   if (leftDirect != null && leftDirect == Expression.getDirectBinding(this.right)) {
     if (!(this.right instanceof Assignment))
       scope.problemReporter().comparingIdenticalExpressions(this);
   }
   return result;
 }
 // Report an error if necessary (if even more unreachable than previously reported
 // complaintLevel = 0 if was reachable up until now, 1 if fake reachable (deadcode), 2 if fatal
 // unreachable (error)
 public int complainIfUnreachable(
     FlowInfo flowInfo, BlockScope scope, int previousComplaintLevel, boolean endOfBlock) {
   if ((flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0) {
     if ((flowInfo.reachMode() & FlowInfo.UNREACHABLE_OR_DEAD) != 0)
       this.bits &= ~ASTNode.IsReachable;
     if (flowInfo == FlowInfo.DEAD_END) {
       if (previousComplaintLevel < COMPLAINED_UNREACHABLE) {
         scope.problemReporter().unreachableCode(this);
         if (endOfBlock) scope.checkUnclosedCloseables(flowInfo, null, null, null);
       }
       return COMPLAINED_UNREACHABLE;
     } else {
       if (previousComplaintLevel < COMPLAINED_FAKE_REACHABLE) {
         scope.problemReporter().fakeReachable(this);
         if (endOfBlock) scope.checkUnclosedCloseables(flowInfo, null, null, null);
       }
       return COMPLAINED_FAKE_REACHABLE;
     }
   }
   return previousComplaintLevel;
 }
Example #5
0
  // Report an error if necessary
  public boolean complainIfUnreachable(
      FlowInfo flowInfo, BlockScope scope, boolean didAlreadyComplain) {

    if ((flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0) {
      this.bits &= ~ASTNode.IsReachableMASK;
      boolean reported = flowInfo == FlowInfo.DEAD_END;
      if (!didAlreadyComplain && reported) {
        scope.problemReporter().unreachableCode(this);
      }
      return reported; // keep going for fake reachable
    }
    return false;
  }
 public void checkCapturedLocalInitializationIfNecessary(
     ReferenceBinding checkedType, BlockScope currentScope, FlowInfo flowInfo) {
   if (((checkedType.tagBits & (TagBits.AnonymousTypeMask | TagBits.LocalTypeMask))
           == TagBits.LocalTypeMask)
       && !currentScope.isDefinedInType(checkedType)) { // only check external allocations
     NestedTypeBinding nestedType = (NestedTypeBinding) checkedType;
     SyntheticArgumentBinding[] syntheticArguments = nestedType.syntheticOuterLocalVariables();
     if (syntheticArguments != null)
       for (int i = 0, count = syntheticArguments.length; i < count; i++) {
         SyntheticArgumentBinding syntheticArgument = syntheticArguments[i];
         LocalVariableBinding targetLocal;
         if ((targetLocal = syntheticArgument.actualOuterLocalVariable) == null) continue;
         if (targetLocal.declaration != null && !flowInfo.isDefinitelyAssigned(targetLocal)) {
           currentScope.problemReporter().uninitializedLocalVariable(targetLocal, this);
         }
       }
   }
 }
 public void checkTypeArgumentRedundancy(
     ParameterizedTypeBinding allocationType,
     ReferenceBinding enclosingType,
     TypeBinding[] argumentTypes,
     final BlockScope scope) {
   ProblemReporter reporter = scope.problemReporter();
   if ((reporter.computeSeverity(IProblem.RedundantSpecificationOfTypeArguments)
           == ProblemSeverities.Ignore)
       || scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_7) return;
   if (allocationType.arguments == null) return; // raw binding
   if (this.genericTypeArguments != null)
     return; // diamond can't occur with explicit type args for constructor
   if (argumentTypes == Binding.NO_PARAMETERS
       && this.typeExpected instanceof ParameterizedTypeBinding) {
     ParameterizedTypeBinding expected = (ParameterizedTypeBinding) this.typeExpected;
     if (expected.arguments != null
         && allocationType.arguments.length == expected.arguments.length) {
       // check the case when no ctor takes no params and inference uses the expected type directly
       // eg. X<String> x = new X<String>()
       int i;
       for (i = 0; i < allocationType.arguments.length; i++) {
         if (allocationType.arguments[i] != expected.arguments[i]) break;
       }
       if (i == allocationType.arguments.length) {
         reporter.redundantSpecificationOfTypeArguments(this.type, allocationType.arguments);
         return;
       }
     }
   }
   TypeBinding[] inferredTypes =
       inferElidedTypes(allocationType.genericType(), enclosingType, argumentTypes, scope);
   if (inferredTypes == null) {
     return;
   }
   for (int i = 0; i < inferredTypes.length; i++) {
     if (inferredTypes[i] != allocationType.arguments[i]) return;
   }
   reporter.redundantSpecificationOfTypeArguments(this.type, allocationType.arguments);
 }
 /** Check null-ness of 'var' against a possible null annotation */
 protected int checkAssignmentAgainstNullAnnotation(
     BlockScope currentScope,
     FlowContext flowContext,
     VariableBinding var,
     int nullStatus,
     Expression expression,
     TypeBinding providedType) {
   int severity = 0;
   if ((var.tagBits & TagBits.AnnotationNonNull) != 0 && nullStatus != FlowInfo.NON_NULL) {
     flowContext.recordNullityMismatch(
         currentScope, expression, providedType, var.type, nullStatus);
     return FlowInfo.NON_NULL;
   } else if ((severity = findNullTypeAnnotationMismatch(var.type, providedType)) > 0) {
     currentScope
         .problemReporter()
         .nullityMismatchingTypeAnnotation(
             expression, providedType, var.type, severity == 1, currentScope.environment());
   } else if ((var.tagBits & TagBits.AnnotationNullable) != 0
       && nullStatus == FlowInfo.UNKNOWN) { // provided a legacy type?
     return FlowInfo.POTENTIALLY_NULL; // -> use more specific info from the annotation
   }
   return nullStatus;
 }
  public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
    if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) return;
    // if constructor from parameterized type got found, use the original constructor at codegen
    // time
    MethodBinding codegenBinding = this.binding.original();

    ReferenceBinding declaringClass;
    if (codegenBinding.isPrivate()
        && currentScope.enclosingSourceType() != (declaringClass = codegenBinding.declaringClass)) {

      // from 1.4 on, local type constructor can lose their private flag to ease emulation
      if ((declaringClass.tagBits & TagBits.IsLocalType) != 0
          && currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) {
        // constructor will not be dumped as private, no emulation required thus
        codegenBinding.tagBits |= TagBits.ClearPrivateModifier;
      } else {
        this.syntheticAccessor =
            ((SourceTypeBinding) declaringClass)
                .addSyntheticMethod(codegenBinding, isSuperAccess());
        currentScope.problemReporter().needToEmulateMethodAccess(codegenBinding, this);
      }
    }
  }
  public TypeBinding resolveType(BlockScope scope) {

    // Build an array type reference using the current dimensions
    // The parser does not check for the fact that dimension may be null
    // only at the -end- like new int [4][][]. The parser allows new int[][4][]
    // so this must be checked here......(this comes from a reduction to LL1 grammar)

    TypeBinding referenceType = type.resolveType(scope, true /* check bounds*/);

    // will check for null after dimensions are checked
    constant = Constant.NotAConstant;
    if (referenceType == VoidBinding) {
      scope.problemReporter().cannotAllocateVoidArray(this);
      referenceType = null;
    }

    // check the validity of the dimension syntax (and test for all null dimensions)
    int explicitDimIndex = -1;
    loop:
    for (int i = dimensions.length; --i >= 0; ) {
      if (dimensions[i] != null) {
        if (explicitDimIndex < 0) explicitDimIndex = i;
      } else if (explicitDimIndex > 0) {
        // should not have an empty dimension before an non-empty one
        scope.problemReporter().incorrectLocationForNonEmptyDimension(this, explicitDimIndex);
        break loop;
      }
    }

    // explicitDimIndex < 0 says if all dimensions are nulled
    // when an initializer is given, no dimension must be specified
    if (initializer == null) {
      if (explicitDimIndex < 0) {
        scope.problemReporter().mustDefineDimensionsOrInitializer(this);
      }
      // allow new List<?>[5] - only check for generic array when no initializer, since also checked
      // inside initializer resolution
      if (referenceType != null && !referenceType.isReifiable()) {
        scope.problemReporter().illegalGenericArray(referenceType, this);
      }
    } else if (explicitDimIndex >= 0) {
      scope.problemReporter().cannotDefineDimensionsAndInitializer(this);
    }

    // dimensions resolution
    for (int i = 0; i <= explicitDimIndex; i++) {
      if (dimensions[i] != null) {
        TypeBinding dimensionType = dimensions[i].resolveTypeExpecting(scope, IntBinding);
        if (dimensionType != null) {
          dimensions[i].computeConversion(scope, IntBinding, dimensionType);
        }
      }
    }

    // building the array binding
    if (referenceType != null) {
      if (dimensions.length > 255) {
        scope.problemReporter().tooManyDimensions(this);
      }
      this.resolvedType = scope.createArrayType(referenceType, dimensions.length);

      // check the initializer
      if (initializer != null) {
        if ((initializer.resolveTypeExpecting(scope, this.resolvedType)) != null)
          initializer.binding = (ArrayBinding) this.resolvedType;
      }
    }
    return this.resolvedType;
  }
  public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {

    Constant cst = this.left.optimizedBooleanConstant();
    boolean isLeftOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true;
    boolean isLeftOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false;

    if (isLeftOptimizedFalse) {
      // FALSE || anything
      // need to be careful of scenario:
      //		(x || y) || !z, if passing the left info to the right, it would be swapped by the !
      FlowInfo mergedInfo =
          this.left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
      flowContext.expireNullCheckedFieldInfo();
      mergedInfo = this.right.analyseCode(currentScope, flowContext, mergedInfo);
      flowContext.expireNullCheckedFieldInfo();
      this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
      return mergedInfo;
    }

    FlowInfo leftInfo = this.left.analyseCode(currentScope, flowContext, flowInfo);
    flowContext.expireNullCheckedFieldInfo();

    // need to be careful of scenario:
    //		(x || y) || !z, if passing the left info to the right, it would be swapped by the !
    FlowInfo rightInfo = leftInfo.initsWhenFalse().unconditionalCopy();
    this.rightInitStateIndex = currentScope.methodScope().recordInitializationStates(rightInfo);

    int previousMode = rightInfo.reachMode();
    if (isLeftOptimizedTrue) {
      if ((rightInfo.reachMode() & FlowInfo.UNREACHABLE) == 0) {
        currentScope.problemReporter().fakeReachable(this.right);
        rightInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);
      }
    }
    rightInfo = this.right.analyseCode(currentScope, flowContext, rightInfo);
    flowContext.expireNullCheckedFieldInfo();
    if ((this.left.implicitConversion & TypeIds.UNBOXING) != 0) {
      this.left.checkNPE(currentScope, flowContext, flowInfo);
    }
    if ((this.right.implicitConversion & TypeIds.UNBOXING) != 0) {
      this.right.checkNPE(currentScope, flowContext, flowInfo);
    }
    // The definitely null variables in right info when true should not be missed out while merging
    // https://bugs.eclipse.org/bugs/show_bug.cgi?id=299900
    FlowInfo leftInfoWhenTrueForMerging =
        leftInfo
            .initsWhenTrue()
            .unconditionalCopy()
            .addPotentialInitializationsFrom(rightInfo.unconditionalInitsWithoutSideEffect());
    FlowInfo mergedInfo =
        FlowInfo.conditional(
            // merging two true initInfos for such a negative case: if ((t && (b = t)) || f) r = b;
            // // b may not have been initialized
            leftInfoWhenTrueForMerging
                .unconditionalInits()
                .mergedWith(
                    rightInfo.safeInitsWhenTrue().setReachMode(previousMode).unconditionalInits()),
            rightInfo.initsWhenFalse());
    this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
    return mergedInfo;
  }
Example #12
0
  public void resolve(BlockScope upperScope) {

    // special scope for secret locals optimization.
    this.scope = new BlockScope(upperScope);

    BlockScope tryScope = new BlockScope(scope);
    BlockScope finallyScope = null;

    if (finallyBlock != null) {
      if (finallyBlock.isEmptyBlock()) {
        if ((finallyBlock.bits & UndocumentedEmptyBlockMASK) != 0) {
          scope
              .problemReporter()
              .undocumentedEmptyBlock(finallyBlock.sourceStart, finallyBlock.sourceEnd);
        }
      } else {
        finallyScope = new BlockScope(scope, false); // don't add it yet to parent scope

        // provision for returning and forcing the finally block to run
        MethodScope methodScope = scope.methodScope();

        // the type does not matter as long as it is not a base type
        if (!upperScope.compilerOptions().inlineJsrBytecode) {
          this.returnAddressVariable =
              new LocalVariableBinding(
                  SecretReturnName, upperScope.getJavaLangObject(), AccDefault, false);
          finallyScope.addLocalVariable(returnAddressVariable);
          this.returnAddressVariable.setConstant(NotAConstant); // not inlinable
        }
        this.subRoutineStartLabel = new Label();

        this.anyExceptionVariable =
            new LocalVariableBinding(
                SecretAnyHandlerName, scope.getJavaLangThrowable(), AccDefault, false);
        finallyScope.addLocalVariable(this.anyExceptionVariable);
        this.anyExceptionVariable.setConstant(NotAConstant); // not inlinable

        if (!methodScope.isInsideInitializer()) {
          MethodBinding methodBinding =
              ((AbstractMethodDeclaration) methodScope.referenceContext).binding;
          if (methodBinding != null) {
            TypeBinding methodReturnType = methodBinding.returnType;
            if (methodReturnType.id != T_void) {
              this.secretReturnValue =
                  new LocalVariableBinding(
                      SecretLocalDeclarationName, methodReturnType, AccDefault, false);
              finallyScope.addLocalVariable(this.secretReturnValue);
              this.secretReturnValue.setConstant(NotAConstant); // not inlinable
            }
          }
        }
        finallyBlock.resolveUsing(finallyScope);
        // force the finally scope to have variable positions shifted after its try scope and catch
        // ones
        finallyScope.shiftScopes =
            new BlockScope[catchArguments == null ? 1 : catchArguments.length + 1];
        finallyScope.shiftScopes[0] = tryScope;
      }
    }
    this.tryBlock.resolveUsing(tryScope);

    // arguments type are checked against JavaLangThrowable in resolveForCatch(..)
    if (this.catchBlocks != null) {
      int length = this.catchArguments.length;
      TypeBinding[] argumentTypes = new TypeBinding[length];
      boolean catchHasError = false;
      for (int i = 0; i < length; i++) {
        BlockScope catchScope = new BlockScope(scope);
        if (finallyScope != null) {
          finallyScope.shiftScopes[i + 1] = catchScope;
        }
        // side effect on catchScope in resolveForCatch(..)
        if ((argumentTypes[i] = catchArguments[i].resolveForCatch(catchScope)) == null) {
          catchHasError = true;
        }
        catchBlocks[i].resolveUsing(catchScope);
      }
      if (catchHasError) {
        return;
      }
      // Verify that the catch clause are ordered in the right way:
      // more specialized first.
      this.caughtExceptionTypes = new ReferenceBinding[length];
      for (int i = 0; i < length; i++) {
        caughtExceptionTypes[i] = (ReferenceBinding) argumentTypes[i];
        for (int j = 0; j < i; j++) {
          if (caughtExceptionTypes[i].isCompatibleWith(argumentTypes[j])) {
            scope
                .problemReporter()
                .wrongSequenceOfExceptionTypesError(
                    this, caughtExceptionTypes[i], i, argumentTypes[j]);
          }
        }
      }
    } else {
      caughtExceptionTypes = new ReferenceBinding[0];
    }

    if (finallyScope != null) {
      // add finallyScope as last subscope, so it can be shifted behind try/catch subscopes.
      // the shifting is necessary to achieve no overlay in between the finally scope and its
      // sibling in term of local variable positions.
      this.scope.addSubscope(finallyScope);
    }
  }
  public TypeBinding resolveType(BlockScope scope) {
    // Propagate the type checking to the arguments, and check if the constructor is defined.
    this.constant = Constant.NotAConstant;
    if (this.type == null) {
      // initialization of an enum constant
      this.resolvedType = scope.enclosingReceiverType();
    } else {
      this.resolvedType = this.type.resolveType(scope, true /* check bounds*/);
      checkParameterizedAllocation:
      {
        if (this.type
            instanceof ParameterizedQualifiedTypeReference) { // disallow new X<String>.Y<Integer>()
          ReferenceBinding currentType = (ReferenceBinding) this.resolvedType;
          if (currentType == null) return currentType;
          do {
            // isStatic() is answering true for toplevel types
            if ((currentType.modifiers & ClassFileConstants.AccStatic) != 0)
              break checkParameterizedAllocation;
            if (currentType.isRawType()) break checkParameterizedAllocation;
          } while ((currentType = currentType.enclosingType()) != null);
          ParameterizedQualifiedTypeReference qRef =
              (ParameterizedQualifiedTypeReference) this.type;
          for (int i = qRef.typeArguments.length - 2; i >= 0; i--) {
            if (qRef.typeArguments[i] != null) {
              scope
                  .problemReporter()
                  .illegalQualifiedParameterizedTypeAllocation(this.type, this.resolvedType);
              break;
            }
          }
        }
      }
    }
    // will check for null after args are resolved

    final boolean isDiamond = this.type != null && (this.type.bits & ASTNode.IsDiamond) != 0;
    // resolve type arguments (for generic constructor call)
    if (this.typeArguments != null) {
      int length = this.typeArguments.length;
      boolean argHasError = scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_5;
      this.genericTypeArguments = new TypeBinding[length];
      for (int i = 0; i < length; i++) {
        TypeReference typeReference = this.typeArguments[i];
        if ((this.genericTypeArguments[i] =
                typeReference.resolveType(scope, true /* check bounds*/))
            == null) {
          argHasError = true;
        }
        if (argHasError && typeReference instanceof Wildcard) {
          scope.problemReporter().illegalUsageOfWildcard(typeReference);
        }
      }
      if (isDiamond) {
        scope.problemReporter().diamondNotWithExplicitTypeArguments(this.typeArguments);
        return null;
      }
      if (argHasError) {
        if (this.arguments != null) { // still attempt to resolve arguments
          for (int i = 0, max = this.arguments.length; i < max; i++) {
            this.arguments[i].resolveType(scope);
          }
        }
        return null;
      }
    }

    // buffering the arguments' types
    boolean argsContainCast = false;
    TypeBinding[] argumentTypes = Binding.NO_PARAMETERS;
    if (this.arguments != null) {
      boolean argHasError = false;
      int length = this.arguments.length;
      argumentTypes = new TypeBinding[length];
      for (int i = 0; i < length; i++) {
        Expression argument = this.arguments[i];
        if (argument instanceof CastExpression) {
          argument.bits |= DisableUnnecessaryCastCheck; // will check later on
          argsContainCast = true;
        }
        if ((argumentTypes[i] = argument.resolveType(scope)) == null) {
          argHasError = true;
        }
      }
      if (argHasError) {
        /* https://bugs.eclipse.org/bugs/show_bug.cgi?id=345359, if arguments have errors, completely bail out in the <> case.
          No meaningful type resolution is possible since inference of the elided types is fully tied to argument types. Do
          not return the partially resolved type.
        */
        if (isDiamond) {
          return null; // not the partially cooked this.resolvedType
        }
        if (this.resolvedType instanceof ReferenceBinding) {
          // record a best guess, for clients who need hint about possible constructor match
          TypeBinding[] pseudoArgs = new TypeBinding[length];
          for (int i = length; --i >= 0; ) {
            pseudoArgs[i] =
                argumentTypes[i] == null
                    ? TypeBinding.NULL
                    : argumentTypes[i]; // replace args with errors with null type
          }
          this.binding =
              scope.findMethod(
                  (ReferenceBinding) this.resolvedType, TypeConstants.INIT, pseudoArgs, this);
          if (this.binding != null && !this.binding.isValidBinding()) {
            MethodBinding closestMatch = ((ProblemMethodBinding) this.binding).closestMatch;
            // record the closest match, for clients who may still need hint about possible method
            // match
            if (closestMatch != null) {
              if (closestMatch.original().typeVariables
                  != Binding.NO_TYPE_VARIABLES) { // generic method
                // shouldn't return generic method outside its context, rather convert it to raw
                // method (175409)
                closestMatch =
                    scope
                        .environment()
                        .createParameterizedGenericMethod(
                            closestMatch.original(), (RawTypeBinding) null);
              }
              this.binding = closestMatch;
              MethodBinding closestMatchOriginal = closestMatch.original();
              if (closestMatchOriginal.isOrEnclosedByPrivateType()
                  && !scope.isDefinedInMethod(closestMatchOriginal)) {
                // ignore cases where method is used from within inside itself (e.g. direct
                // recursions)
                closestMatchOriginal.modifiers |= ExtraCompilerModifiers.AccLocallyUsed;
              }
            }
          }
        }
        return this.resolvedType;
      }
    }
    if (this.resolvedType == null || !this.resolvedType.isValidBinding()) {
      return null;
    }

    // null type denotes fake allocation for enum constant inits
    if (this.type != null && !this.resolvedType.canBeInstantiated()) {
      scope.problemReporter().cannotInstantiate(this.type, this.resolvedType);
      return this.resolvedType;
    }
    if (isDiamond) {
      TypeBinding[] inferredTypes =
          inferElidedTypes(
              ((ParameterizedTypeBinding) this.resolvedType).genericType(),
              null,
              argumentTypes,
              scope);
      if (inferredTypes == null) {
        scope.problemReporter().cannotInferElidedTypes(this);
        return this.resolvedType = null;
      }
      this.resolvedType =
          this.type.resolvedType =
              scope
                  .environment()
                  .createParameterizedType(
                      ((ParameterizedTypeBinding) this.resolvedType).genericType(),
                      inferredTypes,
                      ((ParameterizedTypeBinding) this.resolvedType).enclosingType());
    }
    ReferenceBinding allocationType = (ReferenceBinding) this.resolvedType;
    if (!(this.binding = scope.getConstructor(allocationType, argumentTypes, this))
        .isValidBinding()) {
      if (this.binding.declaringClass == null) {
        this.binding.declaringClass = allocationType;
      }
      if (this.type != null && !this.type.resolvedType.isValidBinding()) {
        return null;
      }
      scope.problemReporter().invalidConstructor(this, this.binding);
      return this.resolvedType;
    }
    if ((this.binding.tagBits & TagBits.HasMissingType) != 0) {
      scope.problemReporter().missingTypeInConstructor(this, this.binding);
    }
    if (isMethodUseDeprecated(this.binding, scope, true))
      scope.problemReporter().deprecatedMethod(this.binding, this);
    if (checkInvocationArguments(
        scope,
        null,
        allocationType,
        this.binding,
        this.arguments,
        argumentTypes,
        argsContainCast,
        this)) {
      this.bits |= ASTNode.Unchecked;
    }
    if (this.typeArguments != null
        && this.binding.original().typeVariables == Binding.NO_TYPE_VARIABLES) {
      scope
          .problemReporter()
          .unnecessaryTypeArgumentsForMethodInvocation(
              this.binding, this.genericTypeArguments, this.typeArguments);
    }
    if (!isDiamond && this.resolvedType.isParameterizedTypeWithActualArguments()) {
      checkTypeArgumentRedundancy(
          (ParameterizedTypeBinding) this.resolvedType, null, argumentTypes, scope);
    }
    final CompilerOptions compilerOptions = scope.compilerOptions();
    if (compilerOptions.isAnnotationBasedNullAnalysisEnabled
        && (this.binding.tagBits & TagBits.IsNullnessKnown) == 0) {
      new ImplicitNullAnnotationVerifier(
              scope.environment(), compilerOptions.inheritNullAnnotations)
          .checkImplicitNullAnnotations(this.binding, null /*srcMethod*/, false, scope);
    }
    return allocationType;
  }
  public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
    if (!valueRequired) currentScope.problemReporter().unusedObjectAllocation(this);

    int pc = codeStream.position;
    MethodBinding codegenBinding = this.binding.original();
    ReferenceBinding allocatedType = codegenBinding.declaringClass;

    codeStream.new_(allocatedType);
    boolean isUnboxing = (this.implicitConversion & TypeIds.UNBOXING) != 0;
    if (valueRequired || isUnboxing) {
      codeStream.dup();
    }
    // better highlight for allocation: display the type individually
    if (this.type != null) { // null for enum constant body
      codeStream.recordPositionsFrom(pc, this.type.sourceStart);
    } else {
      // push enum constant name and ordinal
      codeStream.ldc(String.valueOf(this.enumConstant.name));
      codeStream.generateInlinedValue(this.enumConstant.binding.id);
    }

    // handling innerclass instance allocation - enclosing instance arguments
    if (allocatedType.isNestedType()) {
      codeStream.generateSyntheticEnclosingInstanceValues(
          currentScope, allocatedType, enclosingInstance(), this);
    }
    // generate the arguments for constructor
    generateArguments(this.binding, this.arguments, currentScope, codeStream);
    // handling innerclass instance allocation - outer local arguments
    if (allocatedType.isNestedType()) {
      codeStream.generateSyntheticOuterArgumentValues(currentScope, allocatedType, this);
    }
    // invoke constructor
    if (this.syntheticAccessor == null) {
      codeStream.invoke(
          Opcodes.OPC_invokespecial, codegenBinding, null /* default declaringClass */);
    } else {
      // synthetic accessor got some extra arguments appended to its signature, which need values
      for (int i = 0,
              max = this.syntheticAccessor.parameters.length - codegenBinding.parameters.length;
          i < max;
          i++) {
        codeStream.aconst_null();
      }
      codeStream.invoke(
          Opcodes.OPC_invokespecial, this.syntheticAccessor, null /* default declaringClass */);
    }
    if (valueRequired) {
      codeStream.generateImplicitConversion(this.implicitConversion);
    } else if (isUnboxing) {
      // conversion only generated if unboxing
      codeStream.generateImplicitConversion(this.implicitConversion);
      switch (postConversionType(currentScope).id) {
        case T_long:
        case T_double:
          codeStream.pop2();
          break;
        default:
          codeStream.pop();
      }
    }
    codeStream.recordPositionsFrom(pc, this.sourceStart);
  }
Example #15
0
  public TypeBinding resolveTypeExpecting(BlockScope scope, TypeBinding expectedType) {
    // Array initializers can only occur on the right hand side of an assignment
    // expression, therefore the expected type contains the valid information
    // concerning the type that must be enforced by the elements of the array initializer.

    // this method is recursive... (the test on isArrayType is the stop case)

    this.constant = Constant.NotAConstant;

    if (expectedType instanceof ArrayBinding) {
      // allow new List<?>[5]
      if ((this.bits & IsAnnotationDefaultValue)
          == 0) { // annotation default value need only to be commensurate JLS9.7
        // allow new List<?>[5] - only check for generic array when no initializer, since also
        // checked inside initializer resolution
        TypeBinding leafComponentType = expectedType.leafComponentType();
        if (!leafComponentType.isReifiable()) {
          scope.problemReporter().illegalGenericArray(leafComponentType, this);
        }
      }
      this.resolvedType = this.binding = (ArrayBinding) expectedType;
      if (this.expressions == null) return this.binding;
      TypeBinding elementType = this.binding.elementsType();
      for (int i = 0, length = this.expressions.length; i < length; i++) {
        Expression expression = this.expressions[i];
        expression.setExpectedType(elementType);
        TypeBinding expressionType =
            expression instanceof ArrayInitializer
                ? expression.resolveTypeExpecting(scope, elementType)
                : expression.resolveType(scope);
        if (expressionType == null) continue;

        // Compile-time conversion required?
        if (elementType
            != expressionType) // must call before computeConversion() and typeMismatchError()
        scope.compilationUnitScope().recordTypeConversion(elementType, expressionType);

        if (expression.isConstantValueOfTypeAssignableToType(expressionType, elementType)
            || expressionType.isCompatibleWith(elementType)) {
          expression.computeConversion(scope, elementType, expressionType);
        } else if (scope.isBoxingCompatibleWith(expressionType, elementType)
            || (expressionType.isBaseType() // narrowing then boxing ?
                && scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5 // autoboxing
                && !elementType.isBaseType()
                && expression.isConstantValueOfTypeAssignableToType(
                    expressionType, scope.environment().computeBoxingType(elementType)))) {
          expression.computeConversion(scope, elementType, expressionType);
        } else {
          scope.problemReporter().typeMismatchError(expressionType, elementType, expression, null);
        }
      }
      return this.binding;
    }

    // infer initializer type for error reporting based on first element
    TypeBinding leafElementType = null;
    int dim = 1;
    if (this.expressions == null) {
      leafElementType = scope.getJavaLangObject();
    } else {
      Expression expression = this.expressions[0];
      while (expression != null && expression instanceof ArrayInitializer) {
        dim++;
        Expression[] subExprs = ((ArrayInitializer) expression).expressions;
        if (subExprs == null) {
          leafElementType = scope.getJavaLangObject();
          expression = null;
          break;
        }
        expression = ((ArrayInitializer) expression).expressions[0];
      }
      if (expression != null) {
        leafElementType = expression.resolveType(scope);
      }
      // fault-tolerance - resolve other expressions as well
      for (int i = 1, length = this.expressions.length; i < length; i++) {
        expression = this.expressions[i];
        if (expression != null) {
          expression.resolveType(scope);
        }
      }
    }
    if (leafElementType != null) {
      this.resolvedType = scope.createArrayType(leafElementType, dim);
      if (expectedType != null)
        scope.problemReporter().typeMismatchError(this.resolvedType, expectedType, this, null);
    }
    return null;
  }
 /** Analysing arguments of MessageSend, ExplicitConstructorCall, AllocationExpression. */
 protected void analyseArguments(
     BlockScope currentScope,
     FlowContext flowContext,
     FlowInfo flowInfo,
     MethodBinding methodBinding,
     Expression[] arguments) {
   // compare actual null-status against parameter annotations of the called method:
   if (arguments != null) {
     CompilerOptions compilerOptions = currentScope.compilerOptions();
     boolean considerTypeAnnotations =
         compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8
             && compilerOptions.isAnnotationBasedNullAnalysisEnabled;
     boolean hasJDK15NullAnnotations = methodBinding.parameterNonNullness != null;
     int numParamsToCheck = methodBinding.parameters.length;
     if (considerTypeAnnotations || hasJDK15NullAnnotations) {
       // check if varargs need special treatment:
       boolean passThrough = false;
       if (methodBinding.isVarargs()) {
         int varArgPos = numParamsToCheck - 1;
         // this if-block essentially copied from generateArguments(..):
         if (numParamsToCheck == arguments.length) {
           TypeBinding varArgsType = methodBinding.parameters[varArgPos];
           TypeBinding lastType = arguments[varArgPos].resolvedType;
           if (lastType == TypeBinding.NULL
               || (varArgsType.dimensions() == lastType.dimensions()
                   && lastType.isCompatibleWith(varArgsType)))
             passThrough = true; // pass directly as-is
         }
         if (!passThrough)
           numParamsToCheck--; // with non-passthrough varargs last param is fed from individual
         // args -> don't check
       }
     }
     if (considerTypeAnnotations) {
       for (int i = 0; i < numParamsToCheck; i++) {
         TypeBinding expectedType = methodBinding.parameters[i];
         Expression argument = arguments[i];
         // prefer check based on type annotations:
         int severity = findNullTypeAnnotationMismatch(expectedType, argument.resolvedType);
         if (severity > 0) {
           // immediate reporting:
           currentScope
               .problemReporter()
               .nullityMismatchingTypeAnnotation(
                   argument,
                   argument.resolvedType,
                   expectedType,
                   severity == 1,
                   currentScope.environment());
           // next check flow-based null status against null JDK15-style annotations:
         } else if (hasJDK15NullAnnotations
             && methodBinding.parameterNonNullness[i] == Boolean.TRUE) {
           int nullStatus =
               argument.nullStatus(
                   flowInfo,
                   flowContext); // slight loss of precision: should also use the null info from
           // the receiver.
           if (nullStatus != FlowInfo.NON_NULL) // if required non-null is not provided
           flowContext.recordNullityMismatch(
                 currentScope, argument, argument.resolvedType, expectedType, nullStatus);
         }
       }
     } else if (hasJDK15NullAnnotations) {
       for (int i = 0; i < numParamsToCheck; i++) {
         if (methodBinding.parameterNonNullness[i] == Boolean.TRUE) {
           TypeBinding expectedType = methodBinding.parameters[i];
           Expression argument = arguments[i];
           int nullStatus =
               argument.nullStatus(
                   flowInfo,
                   flowContext); // slight loss of precision: should also use the null info from
           // the receiver.
           if (nullStatus != FlowInfo.NON_NULL) // if required non-null is not provided
           flowContext.recordNullityMismatch(
                 currentScope, argument, argument.resolvedType, expectedType, nullStatus);
         }
       }
     }
   }
 }
  public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
    this.preAssertInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo);

    Constant cst = this.assertExpression.optimizedBooleanConstant();
    if ((this.assertExpression.implicitConversion & TypeIds.UNBOXING) != 0) {
      this.assertExpression.checkNPE(currentScope, flowContext, flowInfo);
    }
    boolean isOptimizedTrueAssertion = cst != Constant.NotAConstant && cst.booleanValue() == true;
    boolean isOptimizedFalseAssertion = cst != Constant.NotAConstant && cst.booleanValue() == false;

    flowContext.tagBits |= FlowContext.HIDE_NULL_COMPARISON_WARNING;
    FlowInfo conditionFlowInfo =
        this.assertExpression.analyseCode(currentScope, flowContext, flowInfo.copy());
    flowContext.extendTimeToLiveForNullCheckedField(1); // survive this assert as a Statement
    flowContext.tagBits &= ~FlowContext.HIDE_NULL_COMPARISON_WARNING;
    UnconditionalFlowInfo assertWhenTrueInfo =
        conditionFlowInfo.initsWhenTrue().unconditionalInits();
    FlowInfo assertInfo = conditionFlowInfo.initsWhenFalse();
    if (isOptimizedTrueAssertion) {
      assertInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);
    }

    if (this.exceptionArgument != null) {
      // only gets evaluated when escaping - results are not taken into account
      FlowInfo exceptionInfo =
          this.exceptionArgument.analyseCode(currentScope, flowContext, assertInfo.copy());

      if (isOptimizedTrueAssertion) {
        currentScope.problemReporter().fakeReachable(this.exceptionArgument);
      } else {
        flowContext.checkExceptionHandlers(
            currentScope.getJavaLangAssertionError(), this, exceptionInfo, currentScope);
      }
    }

    if (!isOptimizedTrueAssertion) {
      // add the assert support in the clinit
      manageSyntheticAccessIfNecessary(currentScope, flowInfo);
    }
    // account for potential AssertionError:
    flowContext.recordAbruptExit();
    if (isOptimizedFalseAssertion) {
      return flowInfo; // if assertions are enabled, the following code will be unreachable
      // change this if we need to carry null analysis results of the assert
      // expression downstream
    } else {
      CompilerOptions compilerOptions = currentScope.compilerOptions();
      if (!compilerOptions.includeNullInfoFromAsserts) {
        // keep just the initializations info, don't include assert's null info
        // merge initialization info's and then add back the null info from flowInfo to
        // make sure that the empty null info of assertInfo doesnt change flowInfo's null info.
        return ((flowInfo.nullInfoLessUnconditionalCopy())
                .mergedWith(assertInfo.nullInfoLessUnconditionalCopy()))
            .addNullInfoFrom(flowInfo);
      }
      return flowInfo
          .mergedWith(assertInfo.nullInfoLessUnconditionalCopy())
          .addInitializationsFrom(assertWhenTrueInfo.discardInitializationInfo());
      // keep the merge from the initial code for the definite assignment
      // analysis, tweak the null part to influence nulls downstream
    }
  }
Example #18
0
  public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {

    // Consider the try block and catch block so as to compute the intersection of initializations
    // and
    // the minimum exit relative depth amongst all of them. Then consider the subroutine, and append
    // its
    // initialization to the try/catch ones, if the subroutine completes normally. If the subroutine
    // does not
    // complete, then only keep this result for the rest of the analysis

    // process the finally block (subroutine) - create a context for the subroutine

    preTryInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo);

    if (anyExceptionVariable != null) {
      anyExceptionVariable.useFlag = LocalVariableBinding.USED;
    }
    if (returnAddressVariable != null) { // TODO (philippe) if subroutine is escaping, unused
      returnAddressVariable.useFlag = LocalVariableBinding.USED;
    }
    InsideSubRoutineFlowContext insideSubContext;
    FinallyFlowContext finallyContext;
    UnconditionalFlowInfo subInfo;
    if (subRoutineStartLabel == null) {
      // no finally block
      insideSubContext = null;
      finallyContext = null;
      subInfo = null;
    } else {
      // analyse finally block first
      insideSubContext = new InsideSubRoutineFlowContext(flowContext, this);
      subInfo =
          finallyBlock
              .analyseCode(
                  currentScope,
                  finallyContext = new FinallyFlowContext(flowContext, finallyBlock),
                  flowInfo.copy().unconditionalInits().discardNullRelatedInitializations())
              .unconditionalInits();
      if (subInfo == FlowInfo.DEAD_END) {
        isSubRoutineEscaping = true;
        scope.problemReporter().finallyMustCompleteNormally(finallyBlock);
      }
      this.subRoutineInits = subInfo;
    }
    // process the try block in a context handling the local exceptions.
    ExceptionHandlingFlowContext handlingContext =
        new ExceptionHandlingFlowContext(
            insideSubContext == null ? flowContext : insideSubContext,
            tryBlock,
            caughtExceptionTypes,
            scope,
            flowInfo.unconditionalInits());

    FlowInfo tryInfo;
    if (tryBlock.isEmptyBlock()) {
      tryInfo = flowInfo;
      tryBlockExit = false;
    } else {
      tryInfo = tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy());
      tryBlockExit = !tryInfo.isReachable();
    }

    // check unreachable catch blocks
    handlingContext.complainIfUnusedExceptionHandlers(scope, this);

    // process the catch blocks - computing the minimal exit depth amongst try/catch
    if (catchArguments != null) {
      int catchCount;
      catchExits = new boolean[catchCount = catchBlocks.length];
      for (int i = 0; i < catchCount; i++) {
        // keep track of the inits that could potentially have led to this exception handler (for
        // final assignments diagnosis)
        FlowInfo catchInfo =
            flowInfo
                .copy()
                .unconditionalInits()
                .addPotentialInitializationsFrom(
                    handlingContext.initsOnException(caughtExceptionTypes[i]).unconditionalInits())
                .addPotentialInitializationsFrom(tryInfo.unconditionalInits())
                .addPotentialInitializationsFrom(handlingContext.initsOnReturn);

        // catch var is always set
        LocalVariableBinding catchArg = catchArguments[i].binding;
        FlowContext catchContext = insideSubContext == null ? flowContext : insideSubContext;
        catchInfo.markAsDefinitelyAssigned(catchArg);
        catchInfo.markAsDefinitelyNonNull(catchArg);
        /*
        "If we are about to consider an unchecked exception handler, potential inits may have occured inside
        the try block that need to be detected , e.g.
        try { x = 1; throwSomething();} catch(Exception e){ x = 2} "
        "(uncheckedExceptionTypes notNil and: [uncheckedExceptionTypes at: index])
        ifTrue: [catchInits addPotentialInitializationsFrom: tryInits]."
        */
        if (tryBlock.statements == null) {
          catchInfo.setReachMode(FlowInfo.UNREACHABLE);
        }
        catchInfo = catchBlocks[i].analyseCode(currentScope, catchContext, catchInfo);
        catchExits[i] = !catchInfo.isReachable();
        tryInfo = tryInfo.mergedWith(catchInfo.unconditionalInits());
      }
    }
    if (subRoutineStartLabel == null) {
      mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(tryInfo);
      return tryInfo;
    }

    // we also need to check potential multiple assignments of final variables inside the finally
    // block
    // need to include potential inits from returns inside the try/catch parts - 1GK2AOF
    finallyContext.complainOnDeferredChecks(
        tryInfo.isReachable()
            ? (tryInfo.addPotentialInitializationsFrom(insideSubContext.initsOnReturn))
            : insideSubContext.initsOnReturn,
        currentScope);
    if (subInfo == FlowInfo.DEAD_END) {
      mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(subInfo);
      return subInfo;
    } else {
      FlowInfo mergedInfo = tryInfo.addInitializationsFrom(subInfo);
      mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
      return mergedInfo;
    }
  }
  public TypeBinding resolveType(BlockScope scope) {

    this.constant = Constant.NotAConstant;
    if ((this.targetType = this.type.resolveType(scope, true /* check bounds*/)) == null)
      return null;

    /* https://bugs.eclipse.org/bugs/show_bug.cgi?id=320463
      https://bugs.eclipse.org/bugs/show_bug.cgi?id=312076
      JLS3 15.8.2 forbids the type named in the class literal expression from being a parameterized type.
      And the grammar in 18.1 disallows (where X and Y are some concrete types) constructs of the form
      Outer<X>.class, Outer<X>.Inner.class, Outer.Inner<X>.class, Outer<X>.Inner<Y>.class etc.
      Corollary wise, we should resolve the type of the class literal expression to be a raw type as
      class literals exist only for the raw underlying type.
    */
    LookupEnvironment environment = scope.environment();
    this.targetType =
        environment.convertToRawType(
            this.targetType, true /* force conversion of enclosing types*/);

    if (this.targetType.isArrayType()) {
      ArrayBinding arrayBinding = (ArrayBinding) this.targetType;
      TypeBinding leafComponentType = arrayBinding.leafComponentType;
      if (leafComponentType == TypeBinding.VOID) {
        scope.problemReporter().cannotAllocateVoidArray(this);
        return null;
      } else if (leafComponentType.isTypeVariable()) {
        scope
            .problemReporter()
            .illegalClassLiteralForTypeVariable((TypeVariableBinding) leafComponentType, this);
      }
    } else if (this.targetType.isTypeVariable()) {
      scope
          .problemReporter()
          .illegalClassLiteralForTypeVariable((TypeVariableBinding) this.targetType, this);
    }
    // {ObjectTeams: do we need a RoleClassLiteralAccess?
    if (this.targetType instanceof ReferenceBinding) {
      ReferenceBinding targetRef = (ReferenceBinding) this.targetType;
      if (targetRef.isRole()) {
        if (this.verbatim) {
          this.targetType =
              RoleTypeCreator.maybeWrapUnqualifiedRoleType(scope, this.targetType, this);
        } else {
          SourceTypeBinding site = scope.enclosingSourceType();
          if (scope.methodScope().isStatic // role class literal needs team instance
              && !site.isRole() // static role method are OK.
              && !RoleTypeBinding.isRoleWithExplicitAnchor(this.targetType)) // t.R.class?
          {
            scope.problemReporter().roleClassLiteralLacksTeamInstance(this, targetRef);
            return null;
          }
          ReferenceBinding teamBinding;
          if (RoleTypeBinding.isRoleWithExplicitAnchor(targetRef))
            teamBinding = targetRef.enclosingType();
          else teamBinding = TeamModel.findEnclosingTeamContainingRole(site, targetRef);
          if (teamBinding == null)
            scope.problemReporter().externalizedRoleClassLiteral(this, targetRef);
          else {
            TypeBinding methodType =
                RoleClassLiteralAccess.ensureGetClassMethod(
                    teamBinding.getTeamModel(),
                    targetRef.roleModel); // not affected by visibility check (for resilience)
            this.roleClassLiteralAccess = new RoleClassLiteralAccess(this, methodType);
            this.resolvedType = this.roleClassLiteralAccess.resolveType(scope);
          }
          return this.resolvedType;
        }
      }
    }
    // SH}
    ReferenceBinding classType = scope.getJavaLangClass();
    // https://bugs.eclipse.org/bugs/show_bug.cgi?id=328689
    if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
      // Integer.class --> Class<Integer>, perform boxing of base types (int.class -->
      // Class<Integer>)
      TypeBinding boxedType = null;
      if (this.targetType.id == T_void) {
        boxedType = environment.getResolvedType(JAVA_LANG_VOID, scope);
      } else {
        boxedType = scope.boxing(this.targetType);
      }
      if (environment.usesNullTypeAnnotations())
        boxedType =
            environment.createAnnotatedType(
                boxedType, new AnnotationBinding[] {environment.getNonNullAnnotation()});
      this.resolvedType =
          environment.createParameterizedType(
              classType, new TypeBinding[] {boxedType}, null /*not a member*/);
    } else {
      this.resolvedType = classType;
    }
    return this.resolvedType;
  }