/** * Record that a nullity mismatch was detected against an annotated type reference. * * @param currentScope scope for error reporting * @param expression the expression violating the specification * @param providedType the type of the provided value, i.e., either expression or an element * thereof (in ForeachStatements) * @param expectedType the declared type of the spec'ed variable, for error reporting. * @param flowInfo the flowInfo observed when visiting expression * @param nullStatus the null status of expression at the current location * @param annotationStatus status from type annotation analysis, or null */ public void recordNullityMismatch( BlockScope currentScope, Expression expression, TypeBinding providedType, TypeBinding expectedType, FlowInfo flowInfo, int nullStatus, NullAnnotationMatching annotationStatus) { if (providedType == null) { return; // assume type error was already reported } if (expression.localVariableBinding() != null) { // flowContext cannot yet handle non-localvar expressions (e.g., fields) // find the inner-most flowContext that might need deferred handling: FlowContext currentContext = this; while (currentContext != null) { // some flow contexts implement deferred checking, should we participate in that? int isInsideAssert = 0x0; if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) { isInsideAssert = FlowContext.HIDE_NULL_COMPARISON_WARNING; } if (currentContext.internalRecordNullityMismatch( expression, providedType, flowInfo, nullStatus, expectedType, ASSIGN_TO_NONNULL | isInsideAssert)) return; currentContext = currentContext.parent; } } // no reason to defer, so report now: if (annotationStatus != null) currentScope .problemReporter() .nullityMismatchingTypeAnnotation( expression, providedType, expectedType, annotationStatus); else currentScope .problemReporter() .nullityMismatch( expression, providedType, expectedType, nullStatus, currentScope.environment().getNonNullAnnotationName()); }
/** * @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); } }