| /******************************************************************************* |
| * Copyright (c) 2007, 2009 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.codeassist; |
| |
| import java.util.Stack; |
| |
| import org.eclipse.jdt.internal.compiler.ASTVisitor; |
| import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; |
| import org.eclipse.jdt.internal.compiler.ast.Argument; |
| import org.eclipse.jdt.internal.compiler.ast.Block; |
| import org.eclipse.jdt.internal.compiler.ast.MessageSend; |
| import org.eclipse.jdt.internal.compiler.ast.ThrowStatement; |
| import org.eclipse.jdt.internal.compiler.ast.TryStatement; |
| import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; |
| import org.eclipse.jdt.internal.compiler.lookup.BlockScope; |
| import org.eclipse.jdt.internal.compiler.lookup.ClassScope; |
| import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; |
| import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; |
| import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; |
| import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; |
| import org.eclipse.jdt.internal.compiler.util.SimpleSet; |
| |
| public class ThrownExceptionFinder extends ASTVisitor { |
| |
| private SimpleSet thrownExceptions; |
| private Stack exceptionsStack; |
| |
| public ReferenceBinding[] find(TryStatement tryStatement, BlockScope scope) { |
| this.thrownExceptions = new SimpleSet(); |
| this.exceptionsStack = new Stack(); |
| tryStatement.traverse(this, scope); |
| removeCaughtExceptions(tryStatement); |
| |
| ReferenceBinding[] result = new ReferenceBinding[this.thrownExceptions.elementSize]; |
| this.thrownExceptions.asArray(result); |
| return result; |
| } |
| |
| private void acceptException(ReferenceBinding binding) { |
| if (binding != null && binding.isValidBinding()) { |
| this.thrownExceptions.add(binding); |
| } |
| } |
| |
| public void endVisit(MessageSend messageSend, BlockScope scope) { |
| if (messageSend.binding != null) { |
| endVisitMethodInvocation(messageSend.binding); |
| } |
| super.endVisit(messageSend, scope); |
| } |
| |
| public void endVisit(AllocationExpression allocationExpression, BlockScope scope) { |
| if (allocationExpression.binding != null) { |
| endVisitMethodInvocation(allocationExpression.binding); |
| } |
| super.endVisit(allocationExpression, scope); |
| } |
| |
| public void endVisit(ThrowStatement throwStatement, BlockScope scope) { |
| acceptException((ReferenceBinding)throwStatement.exception.resolvedType); |
| super.endVisit(throwStatement, scope); |
| } |
| |
| |
| private void endVisitMethodInvocation(MethodBinding methodBinding) { |
| ReferenceBinding[] thrownExceptionBindings = methodBinding.thrownExceptions; |
| int length = thrownExceptionBindings == null ? 0 : thrownExceptionBindings.length; |
| for (int i = 0; i < length; i++) { |
| acceptException(thrownExceptionBindings[i]); |
| } |
| } |
| |
| public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) { |
| return visitType(typeDeclaration); |
| } |
| |
| public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) { |
| return visitType(memberTypeDeclaration); |
| } |
| |
| public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope scope) { |
| return visitType(localTypeDeclaration); |
| } |
| |
| private boolean visitType(TypeDeclaration typeDeclaration) { |
| return false; |
| } |
| |
| public boolean visit(TryStatement tryStatement, BlockScope scope) { |
| this.exceptionsStack.push(this.thrownExceptions); |
| SimpleSet exceptionSet = new SimpleSet(); |
| this.thrownExceptions = exceptionSet; |
| tryStatement.tryBlock.traverse(this, scope); |
| |
| removeCaughtExceptions(tryStatement); |
| |
| this.thrownExceptions = (SimpleSet)this.exceptionsStack.pop(); |
| |
| Object[] values = exceptionSet.values; |
| for (int i = 0; i < values.length; i++) { |
| if (values[i] != null) { |
| this.thrownExceptions.add(values[i]); |
| } |
| } |
| |
| Block[] catchBlocks = tryStatement.catchBlocks; |
| int length = catchBlocks == null ? 0 : catchBlocks.length; |
| for (int i = 0; i < length; i++) { |
| catchBlocks[i].traverse(this, scope); |
| } |
| return false; |
| } |
| |
| private void removeCaughtExceptions(TryStatement tryStatement) { |
| Argument[] catchArguments = tryStatement.catchArguments; |
| int length = catchArguments == null ? 0 : catchArguments.length; |
| for (int i = 0; i < length; i++) { |
| TypeBinding exception = catchArguments[i].type.resolvedType; |
| if (exception != null && exception.isValidBinding()) { |
| removeCaughtException((ReferenceBinding)exception); |
| |
| } |
| } |
| } |
| |
| private void removeCaughtException(ReferenceBinding caughtException) { |
| Object[] exceptions = this.thrownExceptions.values; |
| for (int i = 0; i < exceptions.length; i++) { |
| ReferenceBinding exception = (ReferenceBinding)exceptions[i]; |
| if (exception != null) { |
| if (exception == caughtException || caughtException.isSuperclassOf(exception)) { |
| this.thrownExceptions.remove(exception); |
| } |
| } |
| } |
| } |
| } |