Exemplo n.º 1
0
  /**
   * Complain if assigned expression is cast, but not actually used as such, e.g. Object o = (List)
   * object;
   */
  public static void checkNeedForAssignedCast(
      BlockScope scope, TypeBinding expectedType, CastExpression rhs) {
    CompilerOptions compilerOptions = scope.compilerOptions();
    if (compilerOptions.getSeverity(CompilerOptions.UnnecessaryTypeCheck)
        == ProblemSeverities.Ignore) return;

    TypeBinding castedExpressionType = rhs.expression.resolvedType;
    //	int i = (byte) n; // cast still had side effect
    // double d = (float) n; // cast to float is unnecessary
    if (castedExpressionType == null || rhs.resolvedType.isBaseType()) return;
    // if (castedExpressionType.id == T_null) return; // tolerate null expression cast
    if (castedExpressionType.isCompatibleWith(expectedType, scope)) {
      if (scope.environment().usesNullTypeAnnotations()) {
        // are null annotations compatible, too?
        if (NullAnnotationMatching.analyse(expectedType, castedExpressionType, -1).isAnyMismatch())
          return; // already reported unchecked cast (nullness), say no more.
      }
      scope.problemReporter().unnecessaryCast(rhs);
    }
  }
 public void finalizeProblems() {
   if (this.suppressWarningsCount == 0) return;
   int removed = 0;
   CategorizedProblem[] problems = this.compilationResult.problems;
   int problemCount = this.compilationResult.problemCount;
   IrritantSet[] foundIrritants = new IrritantSet[this.suppressWarningsCount];
   CompilerOptions options = this.scope.compilerOptions();
   boolean hasMandatoryErrors = false;
   nextProblem:
   for (int iProblem = 0, length = problemCount; iProblem < length; iProblem++) {
     CategorizedProblem problem = problems[iProblem];
     int problemID = problem.getID();
     int irritant = ProblemReporter.getIrritant(problemID);
     boolean isError = problem.isError();
     if (isError) {
       if (irritant == 0) {
         // tolerate unused warning tokens when mandatory errors
         hasMandatoryErrors = true;
         continue;
       }
       if (!options.suppressOptionalErrors) {
         continue;
       }
     }
     int start = problem.getSourceStart();
     int end = problem.getSourceEnd();
     nextSuppress:
     for (int iSuppress = 0, suppressCount = this.suppressWarningsCount;
         iSuppress < suppressCount;
         iSuppress++) {
       long position = this.suppressWarningScopePositions[iSuppress];
       int startSuppress = (int) (position >>> 32);
       int endSuppress = (int) position;
       if (start < startSuppress) continue nextSuppress;
       if (end > endSuppress) continue nextSuppress;
       if (!this.suppressWarningIrritants[iSuppress].isSet(irritant)) continue nextSuppress;
       // discard suppressed warning
       removed++;
       problems[iProblem] = null;
       this.compilationResult.removeProblem(problem);
       if (foundIrritants[iSuppress] == null) {
         foundIrritants[iSuppress] = new IrritantSet(irritant);
       } else {
         foundIrritants[iSuppress].set(irritant);
       }
       continue nextProblem;
     }
   }
   // compact remaining problems
   if (removed > 0) {
     for (int i = 0, index = 0; i < problemCount; i++) {
       CategorizedProblem problem;
       if ((problem = problems[i]) != null) {
         if (i > index) {
           problems[index++] = problem;
         } else {
           index++;
         }
       }
     }
   }
   // flag SuppressWarnings which had no effect (only if no (mandatory) error got detected within
   // unit
   if (!hasMandatoryErrors) {
     int severity = options.getSeverity(CompilerOptions.UnusedWarningToken);
     if (severity != ProblemSeverities.Ignore) {
       boolean unusedWarningTokenIsWarning = (severity & ProblemSeverities.Error) == 0;
       for (int iSuppress = 0, suppressCount = this.suppressWarningsCount;
           iSuppress < suppressCount;
           iSuppress++) {
         Annotation annotation = this.suppressWarningAnnotations[iSuppress];
         if (annotation == null) continue; // implicit annotation
         IrritantSet irritants = this.suppressWarningIrritants[iSuppress];
         if (unusedWarningTokenIsWarning && irritants.areAllSet())
           continue; // @SuppressWarnings("all") also suppresses unused warning token
         if (irritants != foundIrritants[iSuppress]) { // mismatch, some warning tokens were unused
           MemberValuePair[] pairs = annotation.memberValuePairs();
           pairLoop:
           for (int iPair = 0, pairCount = pairs.length; iPair < pairCount; iPair++) {
             MemberValuePair pair = pairs[iPair];
             if (CharOperation.equals(pair.name, TypeConstants.VALUE)) {
               Expression value = pair.value;
               if (value instanceof ArrayInitializer) {
                 ArrayInitializer initializer = (ArrayInitializer) value;
                 Expression[] inits = initializer.expressions;
                 if (inits != null) {
                   for (int iToken = 0, tokenCount = inits.length; iToken < tokenCount; iToken++) {
                     Constant cst = inits[iToken].constant;
                     if (cst != Constant.NotAConstant
                         && cst.typeID() == TypeIds.T_JavaLangString) {
                       IrritantSet tokenIrritants =
                           CompilerOptions.warningTokenToIrritants(cst.stringValue());
                       if (tokenIrritants != null
                           && !tokenIrritants
                               .areAllSet() // no complaint against @SuppressWarnings("all")
                           && options.isAnyEnabled(
                               tokenIrritants) // if irritant is effectively enabled
                           && (foundIrritants[iSuppress] == null
                               || !foundIrritants[iSuppress].isAnySet(
                                   tokenIrritants))) { // if irritant had no matching problem
                         if (unusedWarningTokenIsWarning) {
                           int start = value.sourceStart, end = value.sourceEnd;
                           nextSuppress:
                           for (int jSuppress = iSuppress - 1; jSuppress >= 0; jSuppress--) {
                             long position = this.suppressWarningScopePositions[jSuppress];
                             int startSuppress = (int) (position >>> 32);
                             int endSuppress = (int) position;
                             if (start < startSuppress) continue nextSuppress;
                             if (end > endSuppress) continue nextSuppress;
                             if (this.suppressWarningIrritants[jSuppress].areAllSet())
                               break pairLoop; // suppress all?
                           }
                         }
                         this.scope.problemReporter().unusedWarningToken(inits[iToken]);
                       }
                     }
                   }
                 }
               } else {
                 Constant cst = value.constant;
                 if (cst != Constant.NotAConstant && cst.typeID() == T_JavaLangString) {
                   IrritantSet tokenIrritants =
                       CompilerOptions.warningTokenToIrritants(cst.stringValue());
                   if (tokenIrritants != null
                       && !tokenIrritants
                           .areAllSet() // no complaint against @SuppressWarnings("all")
                       && options.isAnyEnabled(
                           tokenIrritants) // if irritant is effectively enabled
                       && (foundIrritants[iSuppress] == null
                           || !foundIrritants[iSuppress].isAnySet(
                               tokenIrritants))) { // if irritant had no matching problem
                     if (unusedWarningTokenIsWarning) {
                       int start = value.sourceStart, end = value.sourceEnd;
                       nextSuppress:
                       for (int jSuppress = iSuppress - 1; jSuppress >= 0; jSuppress--) {
                         long position = this.suppressWarningScopePositions[jSuppress];
                         int startSuppress = (int) (position >>> 32);
                         int endSuppress = (int) position;
                         if (start < startSuppress) continue nextSuppress;
                         if (end > endSuppress) continue nextSuppress;
                         if (this.suppressWarningIrritants[jSuppress].areAllSet())
                           break pairLoop; // suppress all?
                       }
                     }
                     this.scope.problemReporter().unusedWarningToken(value);
                   }
                 }
               }
               break pairLoop;
             }
           }
         }
       }
     }
   }
 }
Exemplo n.º 3
0
  public TypeBinding resolveType(BlockScope scope) {
    // Answer the signature return type
    // Base type promotion

    this.constant = Constant.NotAConstant;
    boolean receiverCast = false, argsContainCast = false;
    if (this.receiver instanceof CastExpression) {
      this.receiver.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on
      receiverCast = true;
    }
    this.actualReceiverType = this.receiver.resolveType(scope);
    boolean receiverIsType =
        this.receiver instanceof NameReference
            && (((NameReference) this.receiver).bits & Binding.TYPE) != 0;
    if (receiverCast && this.actualReceiverType != null) {
      // due to change of declaring class with receiver type, only identity cast should be notified
      if (((CastExpression) this.receiver).expression.resolvedType == this.actualReceiverType) {
        scope.problemReporter().unnecessaryCast((CastExpression) this.receiver);
      }
    }
    // resolve type arguments (for generic constructor call)
    if (this.typeArguments != null) {
      int length = this.typeArguments.length;
      boolean argHasError =
          scope.compilerOptions().sourceLevel
              < ClassFileConstants.JDK1_5; // typeChecks all arguments
      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 (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;
      }
    }
    // will check for null after args are resolved
    TypeBinding[] argumentTypes = Binding.NO_PARAMETERS;
    if (this.arguments != null) {
      boolean argHasError = false; // typeChecks all arguments
      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 |= ASTNode.DisableUnnecessaryCastCheck; // will check later on
          argsContainCast = true;
        }
        if ((argumentTypes[i] = argument.resolveType(scope)) == null) {
          argHasError = true;
        }
      }
      if (argHasError) {
        if (this.actualReceiverType instanceof ReferenceBinding) {
          //  record a best guess, for clients who need hint about possible method 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 =
              this.receiver.isImplicitThis()
                  ? scope.getImplicitMethod(this.selector, pseudoArgs, this)
                  : scope.findMethod(
                      (ReferenceBinding) this.actualReceiverType, this.selector, 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 null;
      }
    }
    if (this.actualReceiverType == null) {
      return null;
    }
    // base type cannot receive any message
    if (this.actualReceiverType.isBaseType()) {
      scope.problemReporter().errorNoMethodFor(this, this.actualReceiverType, argumentTypes);
      return null;
    }
    this.binding =
        this.receiver.isImplicitThis()
            ? scope.getImplicitMethod(this.selector, argumentTypes, this)
            : scope.getMethod(this.actualReceiverType, this.selector, argumentTypes, this);
    if (!this.binding.isValidBinding()) {
      if (this.binding.declaringClass == null) {
        if (this.actualReceiverType instanceof ReferenceBinding) {
          this.binding.declaringClass = (ReferenceBinding) this.actualReceiverType;
        } else {
          scope.problemReporter().errorNoMethodFor(this, this.actualReceiverType, argumentTypes);
          return null;
        }
      }
      // https://bugs.eclipse.org/bugs/show_bug.cgi?id=245007 avoid secondary errors in case of
      // missing super type for anonymous classes ...
      ReferenceBinding declaringClass = this.binding.declaringClass;
      boolean avoidSecondary =
          declaringClass != null
              && declaringClass.isAnonymousType()
              && declaringClass.superclass() instanceof MissingTypeBinding;
      if (!avoidSecondary) scope.problemReporter().invalidMethod(this, this.binding);
      MethodBinding closestMatch = ((ProblemMethodBinding) this.binding).closestMatch;
      switch (this.binding.problemId()) {
        case ProblemReasons.Ambiguous:
          break; // no resilience on ambiguous
        case ProblemReasons.NotVisible:
        case ProblemReasons.NonStaticReferenceInConstructorInvocation:
        case ProblemReasons.NonStaticReferenceInStaticContext:
        case ProblemReasons.ReceiverTypeNotVisible:
        case ProblemReasons.ParameterBoundMismatch:
          // only steal returnType in cases listed above
          if (closestMatch != null) this.resolvedType = closestMatch.returnType;
          break;
      }
      // record the closest match, for clients who may still need hint about possible method match
      if (closestMatch != 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 != null
              && (this.resolvedType.tagBits & TagBits.HasMissingType) == 0)
          ? this.resolvedType
          : null;
    }
    final CompilerOptions compilerOptions = scope.compilerOptions();
    if (compilerOptions.complianceLevel <= ClassFileConstants.JDK1_6
        && this.binding.isPolymorphic()) {
      scope.problemReporter().polymorphicMethodNotBelow17(this);
      return null;
    }

    if (((this.bits & ASTNode.InsideExpressionStatement) != 0) && this.binding.isPolymorphic()) {
      // we only set the return type to be void if this method invocation is used inside an
      // expression statement
      this.binding =
          scope
              .environment()
              .updatePolymorphicMethodReturnType(
                  (PolymorphicMethodBinding) this.binding, TypeBinding.VOID);
    }
    if ((this.binding.tagBits & TagBits.HasMissingType) != 0) {
      scope.problemReporter().missingTypeInMethod(this, this.binding);
    }
    if (!this.binding.isStatic()) {
      // the "receiver" must not be a type
      if (receiverIsType) {
        scope.problemReporter().mustUseAStaticMethod(this, this.binding);
        if (this.actualReceiverType.isRawType()
            && (this.receiver.bits & ASTNode.IgnoreRawTypeCheck) == 0
            && compilerOptions.getSeverity(CompilerOptions.RawTypeReference)
                != ProblemSeverities.Ignore) {
          scope.problemReporter().rawTypeReference(this.receiver, this.actualReceiverType);
        }
      } else {
        // handle indirect inheritance thru variable secondary bound
        // receiver may receive generic cast, as part of implicit conversion
        TypeBinding oldReceiverType = this.actualReceiverType;
        this.actualReceiverType =
            this.actualReceiverType.getErasureCompatibleType(this.binding.declaringClass);
        this.receiver.computeConversion(scope, this.actualReceiverType, this.actualReceiverType);
        if (this.actualReceiverType != oldReceiverType
            && this.receiver.postConversionType(scope)
                != this
                    .actualReceiverType) { // record need for explicit cast at codegen since
                                           // receiver could not handle it
          this.bits |= NeedReceiverGenericCast;
        }
      }
    } else {
      // static message invoked through receiver? legal but unoptimal (optional warning).
      if (!(this.receiver.isImplicitThis() || this.receiver.isSuper() || receiverIsType)) {
        scope.problemReporter().nonStaticAccessToStaticMethod(this, this.binding);
      }
      if (!this.receiver.isImplicitThis()
          && this.binding.declaringClass != this.actualReceiverType) {
        scope.problemReporter().indirectAccessToStaticMethod(this, this.binding);
      }
    }
    if (checkInvocationArguments(
        scope,
        this.receiver,
        this.actualReceiverType,
        this.binding,
        this.arguments,
        argumentTypes,
        argsContainCast,
        this)) {
      this.bits |= ASTNode.Unchecked;
    }

    // -------message send that are known to fail at compile time-----------
    if (this.binding.isAbstract()) {
      if (this.receiver.isSuper()) {
        scope.problemReporter().cannotDireclyInvokeAbstractMethod(this, this.binding);
      }
      // abstract private methods cannot occur nor abstract static............
    }
    if (isMethodUseDeprecated(this.binding, scope, true))
      scope.problemReporter().deprecatedMethod(this.binding, this);

    // from 1.5 source level on, array#clone() returns the array type (but binding still shows
    // Object)
    if (this.binding == scope.environment().arrayClone
        && compilerOptions.sourceLevel >= ClassFileConstants.JDK1_5) {
      this.resolvedType = this.actualReceiverType;
    } else {
      TypeBinding returnType;
      if ((this.bits & ASTNode.Unchecked) != 0 && this.genericTypeArguments == null) {
        // https://bugs.eclipse.org/bugs/show_bug.cgi?id=277643, align with javac on JLS 15.12.2.6
        returnType = this.binding.returnType;
        if (returnType != null) {
          returnType = scope.environment().convertToRawType(returnType.erasure(), true);
        }
      } else {
        returnType = this.binding.returnType;
        if (returnType != null) {
          returnType = returnType.capture(scope, this.sourceEnd);
        }
      }
      this.resolvedType = returnType;
    }
    if (this.receiver.isSuper()
        && compilerOptions.getSeverity(CompilerOptions.OverridingMethodWithoutSuperInvocation)
            != ProblemSeverities.Ignore) {
      final ReferenceContext referenceContext = scope.methodScope().referenceContext;
      if (referenceContext instanceof AbstractMethodDeclaration) {
        final AbstractMethodDeclaration abstractMethodDeclaration =
            (AbstractMethodDeclaration) referenceContext;
        MethodBinding enclosingMethodBinding = abstractMethodDeclaration.binding;
        if (enclosingMethodBinding.isOverriding()
            && CharOperation.equals(this.binding.selector, enclosingMethodBinding.selector)
            && this.binding.areParametersEqual(enclosingMethodBinding)) {
          abstractMethodDeclaration.bits |= ASTNode.OverridingMethodWithSupercall;
        }
      }
    }
    if (this.typeArguments != null
        && this.binding.original().typeVariables == Binding.NO_TYPE_VARIABLES) {
      scope
          .problemReporter()
          .unnecessaryTypeArgumentsForMethodInvocation(
              this.binding, this.genericTypeArguments, this.typeArguments);
    }
    return (this.resolvedType.tagBits & TagBits.HasMissingType) == 0 ? this.resolvedType : null;
  }