Example #1
0
  public void checkExceptionHandlers(
      TypeBinding[] raisedExceptions, ASTNode location, FlowInfo flowInfo, BlockScope scope) {
    // check that all the argument exception types are handled
    // JDK Compatible implementation - when an exception type is thrown,
    // all related catch blocks are marked as reachable... instead of those only
    // until the point where it is safely handled (Smarter - see comment at the end)
    int remainingCount; // counting the number of remaining unhandled exceptions
    int raisedCount; // total number of exceptions raised
    if ((raisedExceptions == null) || ((raisedCount = raisedExceptions.length) == 0)) return;
    remainingCount = raisedCount;

    // duplicate the array of raised exceptions since it will be updated
    // (null replaces any handled exception)
    System.arraycopy(
        raisedExceptions, 0, (raisedExceptions = new TypeBinding[raisedCount]), 0, raisedCount);
    FlowContext traversedContext = this;

    ArrayList abruptlyExitedLoops = null;
    while (traversedContext != null) {
      SubRoutineStatement sub;
      if (((sub = traversedContext.subroutine()) != null) && sub.isSubRoutineEscaping()) {
        // traversing a non-returning subroutine means that all unhandled
        // exceptions will actually never get sent...
        return;
      }
      // filter exceptions that are locally caught from the innermost enclosing
      // try statement to the outermost ones.
      if (traversedContext instanceof ExceptionHandlingFlowContext) {
        ExceptionHandlingFlowContext exceptionContext =
            (ExceptionHandlingFlowContext) traversedContext;
        ReferenceBinding[] caughtExceptions;
        if ((caughtExceptions = exceptionContext.handledExceptions) != Binding.NO_EXCEPTIONS) {
          int caughtCount = caughtExceptions.length;
          boolean[] locallyCaught = new boolean[raisedCount]; // at most

          for (int caughtIndex = 0; caughtIndex < caughtCount; caughtIndex++) {
            ReferenceBinding caughtException = caughtExceptions[caughtIndex];
            for (int raisedIndex = 0; raisedIndex < raisedCount; raisedIndex++) {
              TypeBinding raisedException;
              if ((raisedException = raisedExceptions[raisedIndex]) != null) {
                FlowInfo exceptionFlow = flowInfo;
                int state =
                    caughtException == null
                        ? Scope.EQUAL_OR_MORE_SPECIFIC /* any exception */
                        : Scope.compareTypes(raisedException, caughtException);
                if (abruptlyExitedLoops != null
                    && caughtException != null
                    && state != Scope.NOT_RELATED) {
                  for (int i = 0, abruptlyExitedLoopsCount = abruptlyExitedLoops.size();
                      i < abruptlyExitedLoopsCount;
                      i++) {
                    LoopingFlowContext loop = (LoopingFlowContext) abruptlyExitedLoops.get(i);
                    loop.recordCatchContextOfEscapingException(
                        exceptionContext, caughtException, flowInfo);
                  }
                  exceptionFlow =
                      FlowInfo.DEAD_END; // don't use flow info on first round, flow info will be
                  // evaluated during loopback simulation
                }
                switch (state) {
                  case Scope.EQUAL_OR_MORE_SPECIFIC:
                    exceptionContext.recordHandlingException(
                        caughtException,
                        exceptionFlow.unconditionalInits(),
                        raisedException,
                        raisedException, // precise exception that will be caught
                        location,
                        locallyCaught[raisedIndex]);
                    // was already definitely caught ?
                    if (!locallyCaught[raisedIndex]) {
                      locallyCaught[raisedIndex] = true;
                      // remember that this exception has been definitely caught
                      remainingCount--;
                    }
                    break;
                  case Scope.MORE_GENERIC:
                    exceptionContext.recordHandlingException(
                        caughtException,
                        exceptionFlow.unconditionalInits(),
                        raisedException,
                        caughtException,
                        location,
                        false);
                    // was not caught already per construction
                }
              }
            }
          }
          // remove locally caught exceptions from the remaining ones
          for (int i = 0; i < raisedCount; i++) {
            if (locallyCaught[i]) {
              raisedExceptions[i] = null; // removed from the remaining ones.
            }
          }
        }
        // method treatment for unchecked exceptions
        if (exceptionContext.isMethodContext) {
          for (int i = 0; i < raisedCount; i++) {
            TypeBinding raisedException;
            if ((raisedException = raisedExceptions[i]) != null) {
              if (raisedException.isUncheckedException(false)) {
                remainingCount--;
                raisedExceptions[i] = null;
              }
            }
          }
          boolean shouldMergeUnhandledException =
              exceptionContext instanceof ExceptionInferenceFlowContext;
          // anonymous constructors are allowed to throw any exceptions (their thrown exceptions
          // clause will be fixed up later as per JLS 8.6).
          if (exceptionContext.associatedNode instanceof AbstractMethodDeclaration) {
            AbstractMethodDeclaration method =
                (AbstractMethodDeclaration) exceptionContext.associatedNode;
            if (method.isConstructor() && method.binding.declaringClass.isAnonymousType())
              shouldMergeUnhandledException = true;
          }
          if (shouldMergeUnhandledException) {
            for (int i = 0; i < raisedCount; i++) {
              TypeBinding raisedException;
              if ((raisedException = raisedExceptions[i]) != null) {
                exceptionContext.mergeUnhandledException(raisedException);
              }
            }
            return; // no need to complain, will fix up constructor/lambda exceptions
          }
          break; // not handled anywhere, thus jump to error handling
        }
      } else if (traversedContext instanceof LoopingFlowContext) {
        if (abruptlyExitedLoops == null) {
          abruptlyExitedLoops = new ArrayList(5);
        }
        abruptlyExitedLoops.add(traversedContext);
      }
      if (remainingCount == 0) return;

      traversedContext.recordReturnFrom(flowInfo.unconditionalInits());

      if (traversedContext instanceof InsideSubRoutineFlowContext) {
        ASTNode node = traversedContext.associatedNode;
        if (node instanceof TryStatement) {
          TryStatement tryStatement = (TryStatement) node;
          flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits
        }
      }
      traversedContext = traversedContext.getLocalParent();
    }
    // if reaches this point, then there are some remaining unhandled exception types.
    nextReport:
    for (int i = 0; i < raisedCount; i++) {
      TypeBinding exception;
      if ((exception = raisedExceptions[i]) != null) {
        // only one complaint if same exception declared to be thrown more than once
        for (int j = 0; j < i; j++) {
          if (TypeBinding.equalsEquals(raisedExceptions[j], exception))
            continue nextReport; // already reported
        }
        scope.problemReporter().unhandledException(exception, location);
      }
    }
  }
Example #2
0
  /**
   * @param isExceptionOnAutoClose This is for checking exception handlers for exceptions raised
   *     during the auto close of resources inside a try with resources statement. (Relevant for
   *     source levels 1.7 and above only)
   */
  public void checkExceptionHandlers(
      TypeBinding raisedException,
      ASTNode location,
      FlowInfo flowInfo,
      BlockScope scope,
      boolean isExceptionOnAutoClose) {
    // LIGHT-VERSION OF THE EQUIVALENT WITH AN ARRAY OF EXCEPTIONS
    // check that all the argument exception types are handled
    // JDK Compatible implementation - when an exception type is thrown,
    // all related catch blocks are marked as reachable... instead of those only
    // until the point where it is safely handled (Smarter - see comment at the end)
    FlowContext traversedContext = this;
    ArrayList abruptlyExitedLoops = null;
    if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_7
        && location instanceof ThrowStatement) {
      Expression throwExpression = ((ThrowStatement) location).exception;
      LocalVariableBinding throwArgBinding = throwExpression.localVariableBinding();
      if (throwExpression
              instanceof SingleNameReference // https://bugs.eclipse.org/bugs/show_bug.cgi?id=350361
          && throwArgBinding instanceof CatchParameterBinding
          && throwArgBinding.isEffectivelyFinal()) {
        CatchParameterBinding parameter = (CatchParameterBinding) throwArgBinding;
        checkExceptionHandlers(parameter.getPreciseTypes(), location, flowInfo, scope);
        return;
      }
    }
    while (traversedContext != null) {
      SubRoutineStatement sub;
      if (((sub = traversedContext.subroutine()) != null) && sub.isSubRoutineEscaping()) {
        // traversing a non-returning subroutine means that all unhandled
        // exceptions will actually never get sent...
        return;
      }

      // filter exceptions that are locally caught from the innermost enclosing
      // try statement to the outermost ones.
      if (traversedContext instanceof ExceptionHandlingFlowContext) {
        ExceptionHandlingFlowContext exceptionContext =
            (ExceptionHandlingFlowContext) traversedContext;
        ReferenceBinding[] caughtExceptions;
        if ((caughtExceptions = exceptionContext.handledExceptions) != Binding.NO_EXCEPTIONS) {
          boolean definitelyCaught = false;
          for (int caughtIndex = 0, caughtCount = caughtExceptions.length;
              caughtIndex < caughtCount;
              caughtIndex++) {
            ReferenceBinding caughtException = caughtExceptions[caughtIndex];
            FlowInfo exceptionFlow = flowInfo;
            int state =
                caughtException == null
                    ? Scope.EQUAL_OR_MORE_SPECIFIC /* any exception */
                    : Scope.compareTypes(raisedException, caughtException);
            if (abruptlyExitedLoops != null
                && caughtException != null
                && state != Scope.NOT_RELATED) {
              for (int i = 0, abruptlyExitedLoopsCount = abruptlyExitedLoops.size();
                  i < abruptlyExitedLoopsCount;
                  i++) {
                LoopingFlowContext loop = (LoopingFlowContext) abruptlyExitedLoops.get(i);
                loop.recordCatchContextOfEscapingException(
                    exceptionContext, caughtException, flowInfo);
              }
              exceptionFlow =
                  FlowInfo
                      .DEAD_END; // don't use flow info on first round, flow info will be evaluated
              // during loopback simulation
            }
            switch (state) {
              case Scope.EQUAL_OR_MORE_SPECIFIC:
                exceptionContext.recordHandlingException(
                    caughtException,
                    exceptionFlow.unconditionalInits(),
                    raisedException,
                    raisedException, // precise exception that will be caught
                    location,
                    definitelyCaught);
                // was it already definitely caught ?
                definitelyCaught = true;
                break;
              case Scope.MORE_GENERIC:
                exceptionContext.recordHandlingException(
                    caughtException,
                    exceptionFlow.unconditionalInits(),
                    raisedException,
                    caughtException,
                    location,
                    false);
                // was not caught already per construction
            }
          }
          if (definitelyCaught) return;
        }
        // method treatment for unchecked exceptions
        if (exceptionContext.isMethodContext) {
          if (raisedException.isUncheckedException(false)) return;
          boolean shouldMergeUnhandledExceptions =
              exceptionContext instanceof ExceptionInferenceFlowContext;

          // anonymous constructors are allowed to throw any exceptions (their thrown exceptions
          // clause will be fixed up later as per JLS 8.6).
          if (exceptionContext.associatedNode instanceof AbstractMethodDeclaration) {
            AbstractMethodDeclaration method =
                (AbstractMethodDeclaration) exceptionContext.associatedNode;
            if (method.isConstructor() && method.binding.declaringClass.isAnonymousType())
              shouldMergeUnhandledExceptions = true;
          }
          if (shouldMergeUnhandledExceptions) {
            exceptionContext.mergeUnhandledException(raisedException);
            return; // no need to complain, will fix up constructor/lambda exceptions
          }
          break; // not handled anywhere, thus jump to error handling
        }
      } else if (traversedContext instanceof LoopingFlowContext) {
        if (abruptlyExitedLoops == null) {
          abruptlyExitedLoops = new ArrayList(5);
        }
        abruptlyExitedLoops.add(traversedContext);
      }

      traversedContext.recordReturnFrom(flowInfo.unconditionalInits());

      if (!isExceptionOnAutoClose) {
        if (traversedContext instanceof InsideSubRoutineFlowContext) {
          ASTNode node = traversedContext.associatedNode;
          if (node instanceof TryStatement) {
            TryStatement tryStatement = (TryStatement) node;
            flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits
          }
        }
      }
      traversedContext = traversedContext.getLocalParent();
    }
    // if reaches this point, then there are some remaining unhandled exception types.
    if (isExceptionOnAutoClose) {
      scope.problemReporter().unhandledExceptionFromAutoClose(raisedException, location);
    } else {
      scope.problemReporter().unhandledException(raisedException, location);
    }
  }