/** * Find all methods which have the requested name. * * <p>{@code <clinit>} is not supported. * * @param type JDT type declaration * @param name name of methods to find * @return list of matching methods */ private static List<AbstractMethodDeclaration> findNamedMethods( TypeDeclaration type, String name) { List<AbstractMethodDeclaration> matching = new ArrayList<AbstractMethodDeclaration>(); boolean isCtor = "<init>".equals(name); char[] nameArray = name.toCharArray(); for (AbstractMethodDeclaration method : type.methods) { if ((isCtor && method.isConstructor()) || (!isCtor && !method.isConstructor() && !method.isClinit() && Arrays.equals(method.selector, nameArray))) { matching.add(method); } } return matching; }
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); } } }
/** * @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); } }
public AbstractMethodDeclaration updatedMethodDeclaration() { /* update annotations */ if (modifiers != 0) { this.methodDeclaration.modifiers |= modifiers; if (this.modifiersStart < this.methodDeclaration.declarationSourceStart) { this.methodDeclaration.declarationSourceStart = modifiersStart; } } /* update annotations */ if (annotationCount > 0) { int existingCount = methodDeclaration.annotations == null ? 0 : methodDeclaration.annotations.length; Annotation[] annotationReferences = new Annotation[existingCount + annotationCount]; if (existingCount > 0) { System.arraycopy( methodDeclaration.annotations, 0, annotationReferences, annotationCount, existingCount); } for (int i = 0; i < annotationCount; i++) { annotationReferences[i] = annotations[i].updatedAnnotationReference(); } methodDeclaration.annotations = annotationReferences; int start = this.annotations[0].annotation.sourceStart; if (start < this.methodDeclaration.declarationSourceStart) { this.methodDeclaration.declarationSourceStart = start; } } if (methodBody != null) { Block block = methodBody.updatedBlock(); if (block != null) { methodDeclaration.statements = block.statements; if (methodDeclaration.declarationSourceEnd == 0) { methodDeclaration.declarationSourceEnd = block.sourceEnd; methodDeclaration.bodyEnd = block.sourceEnd; } /* first statement might be an explict constructor call destinated to a special slot */ if (methodDeclaration.isConstructor()) { ConstructorDeclaration constructor = (ConstructorDeclaration) methodDeclaration; if (methodDeclaration.statements != null && methodDeclaration.statements[0] instanceof ExplicitConstructorCall) { constructor.constructorCall = (ExplicitConstructorCall) methodDeclaration.statements[0]; int length = methodDeclaration.statements.length; System.arraycopy( methodDeclaration.statements, 1, (methodDeclaration.statements = new Statement[length - 1]), 0, length - 1); } if (constructor.constructorCall == null) { // add implicit constructor call constructor.constructorCall = SuperReference.implicitSuperConstructorCall(); } } } } else { if (methodDeclaration.declarationSourceEnd == 0) { if (methodDeclaration.sourceEnd + 1 == methodDeclaration.bodyStart) { // right brace is missing methodDeclaration.declarationSourceEnd = methodDeclaration.sourceEnd; methodDeclaration.bodyStart = methodDeclaration.sourceEnd; methodDeclaration.bodyEnd = methodDeclaration.sourceEnd; } else { methodDeclaration.declarationSourceEnd = methodDeclaration.bodyStart; methodDeclaration.bodyEnd = methodDeclaration.bodyStart; } } } if (localTypeCount > 0) methodDeclaration.bits |= ASTNode.HasLocalType; return methodDeclaration; }