blob: a18dc2ab39cf166475105aecba14f9c64d64ea88 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 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.corext.refactoring.util;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration;
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
import org.eclipse.jdt.core.dom.CatchClause;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.EnumDeclaration;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.ThrowStatement;
import org.eclipse.jdt.core.dom.TryStatement;
import org.eclipse.jdt.core.dom.TypeDeclaration;
public abstract class AbstractExceptionAnalyzer extends ASTVisitor {
private List fCurrentExceptions; // Elements in this list are of type TypeBinding
private Stack fTryStack;
protected AbstractExceptionAnalyzer() {
fTryStack= new Stack();
fCurrentExceptions= new ArrayList(1);
fTryStack.push(fCurrentExceptions);
}
public abstract boolean visit(ThrowStatement node);
public abstract boolean visit(MethodInvocation node);
public abstract boolean visit(ClassInstanceCreation node);
public boolean visit(TypeDeclaration node) {
// Don't dive into a local type.
if (node.isLocalTypeDeclaration())
return false;
return true;
}
public boolean visit(EnumDeclaration node) {
// Don't dive into a local type.
if (node.isLocalTypeDeclaration())
return false;
return true;
}
public boolean visit(AnnotationTypeDeclaration node) {
// Don't dive into a local type.
if (node.isLocalTypeDeclaration())
return false;
return true;
}
public boolean visit(AnonymousClassDeclaration node) {
// Don't dive into a local type.
return false;
}
public boolean visit(TryStatement node) {
fCurrentExceptions= new ArrayList(1);
fTryStack.push(fCurrentExceptions);
// visit try block
node.getBody().accept(this);
// Remove those exceptions that get catch by following catch blocks
List catchClauses= node.catchClauses();
if (!catchClauses.isEmpty())
handleCatchArguments(catchClauses);
List current= (List)fTryStack.pop();
fCurrentExceptions= (List)fTryStack.peek();
for (Iterator iter= current.iterator(); iter.hasNext();) {
addException((ITypeBinding)iter.next());
}
// visit catch and finally
for (Iterator iter= catchClauses.iterator(); iter.hasNext(); ) {
((CatchClause)iter.next()).accept(this);
}
if (node.getFinally() != null)
node.getFinally().accept(this);
// return false. We have visited the body by ourselves.
return false;
}
protected void addExceptions(ITypeBinding[] exceptions) {
if(exceptions == null)
return;
for (int i= 0; i < exceptions.length;i++) {
addException(exceptions[i]);
}
}
protected void addException(ITypeBinding exception) {
if (!fCurrentExceptions.contains(exception))
fCurrentExceptions.add(exception);
}
protected List getCurrentExceptions() {
return fCurrentExceptions;
}
private void handleCatchArguments(List catchClauses) {
for (Iterator iter= catchClauses.iterator(); iter.hasNext(); ) {
CatchClause clause= (CatchClause)iter.next();
ITypeBinding catchTypeBinding= clause.getException().getType().resolveBinding();
if (catchTypeBinding == null) // No correct type resolve.
continue;
for (Iterator exceptions= new ArrayList(fCurrentExceptions).iterator(); exceptions.hasNext(); ) {
ITypeBinding throwTypeBinding= (ITypeBinding)exceptions.next();
if (catches(catchTypeBinding, throwTypeBinding))
fCurrentExceptions.remove(throwTypeBinding);
}
}
}
private boolean catches(ITypeBinding catchTypeBinding, ITypeBinding throwTypeBinding) {
while(throwTypeBinding != null) {
if (throwTypeBinding == catchTypeBinding)
return true;
throwTypeBinding= throwTypeBinding.getSuperclass();
}
return false;
}
}