Index: .classpath =================================================================== RCS file: /home/eclipse/org.eclipse.jdt.ui/.classpath,v retrieving revision 1.31 diff -u -r1.31 .classpath --- .classpath 7 May 2003 14:49:45 -0000 1.31 +++ .classpath 14 Aug 2003 17:05:05 -0000 @@ -1,9 +1,9 @@ - - - - + + + + @@ -14,9 +14,9 @@ - + + - Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/ExceptionDeclaredByCalledMethod.java =================================================================== RCS file: core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/ExceptionDeclaredByCalledMethod.java diff -N core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/ExceptionDeclaredByCalledMethod.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/ExceptionDeclaredByCalledMethod.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,47 @@ +package org.eclipse.jdt.internal.corext.refactoring.remove; + +import org.eclipse.jdt.core.dom.IMethodBinding; +import org.eclipse.jdt.core.dom.ITypeBinding; + +class ExceptionDeclaredByCalledMethod extends ExceptionOccurance { + private ITypeBinding fException; + private IMethodBinding fMethod; + + public ITypeBinding getException() { + return fException; + } + + public IMethodBinding getMethod() { + return fMethod; + } + + public ExceptionDeclaredByCalledMethod( + ITypeBinding exception, + IMethodBinding method) { + fException = exception; + fMethod = method; + } + + public int hashCode() { + return fException.hashCode() + fMethod.hashCode(); + } + + public boolean equals(Object o) { + if (o.getClass().equals(getClass())) { + ExceptionDeclaredByCalledMethod exceptionLocation = + (ExceptionDeclaredByCalledMethod) o; + if (exceptionLocation.fException.equals(fException) + && exceptionLocation.fMethod.equals(fMethod)) + return true; + } + return false; + } + + public String toString() { + return "Exception declared by Method:" + + getMethod().getDeclaringClass().getQualifiedName() + + "." + + getMethod().getName() + + "()"; + } +} Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/ExceptionOccurance.java =================================================================== RCS file: core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/ExceptionOccurance.java diff -N core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/ExceptionOccurance.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/ExceptionOccurance.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,5 @@ +package org.eclipse.jdt.internal.corext.refactoring.remove; + +public class ExceptionOccurance { + +} Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/ExceptionThrown.java =================================================================== RCS file: core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/ExceptionThrown.java diff -N core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/ExceptionThrown.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/ExceptionThrown.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,4 @@ +package org.eclipse.jdt.internal.corext.refactoring.remove; + +public class ExceptionThrown extends ExceptionOccurance { +} Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/MethodMatcher.java =================================================================== RCS file: core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/MethodMatcher.java diff -N core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/MethodMatcher.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/MethodMatcher.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,37 @@ +/* + * Created on 24.07.2003 + * + * To change the template for this generated file go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +package org.eclipse.jdt.internal.corext.refactoring.remove; + +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.MethodDeclaration; + + +class MethodMatcher extends ASTVisitor { + + private MethodDeclaration fResult; + private IMethod fMethod; + MethodMatcher(IMethod method) { + fMethod = method; + } + + public void endVisit(MethodDeclaration methodDeclaration) { // TODO bogus, care for different argument types, stop + // visits when fResult is set initially + if (methodDeclaration + .getName() + .toString() + .equals(fMethod.getElementName().toString())) { + RemoveRefactoring.log(this, "found " + fMethod.getElementName().toString()); + fResult = methodDeclaration; + } + } + + /** returns null when no match is found */ + MethodDeclaration getResult() { + return fResult; + } +} Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/MethodsExceptionUsageAnalysisResult.java =================================================================== RCS file: core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/MethodsExceptionUsageAnalysisResult.java diff -N core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/MethodsExceptionUsageAnalysisResult.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/MethodsExceptionUsageAnalysisResult.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,73 @@ +package org.eclipse.jdt.internal.corext.refactoring.remove; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jdt.core.IType; + +/** + * this method's exception usage analysis result is from the point of view of the method + * It a query/filter/holder only class. + * + */ +public class MethodsExceptionUsageAnalysisResult { + private IType fAnalyzedException; + + private List exceptionsDeclaredByCalledMethods; + + private boolean fExceptionThrown; + private boolean fExceptionDeclared; + private boolean fExceptionCaught; + + public MethodsExceptionUsageAnalysisResult(IType analyzedException) { + fAnalyzedException = analyzedException; + exceptionsDeclaredByCalledMethods = new ArrayList(5); + } + public ExceptionDeclaredByCalledMethod[] getExceptionDeclaredByCalledMethods() { + return ( + ExceptionDeclaredByCalledMethod[]) exceptionsDeclaredByCalledMethods + .toArray( + new ExceptionDeclaredByCalledMethod[exceptionsDeclaredByCalledMethods + .size()]); + } + + public void add(ExceptionDeclaredByCalledMethod edbcm) { + exceptionsDeclaredByCalledMethods.add(edbcm); + } + + void setExceptionThrown(boolean b) { + fExceptionThrown = b; + } + void setExceptionDeclared(boolean b) { + fExceptionDeclared = b; + } + void setExceptionCaught(boolean b) { + fExceptionCaught = b; + } + public boolean isExceptionCaught() { + return fExceptionCaught; + } + public boolean isExceptionDeclared() { + return fExceptionDeclared; + } + public boolean isExceptionThrown() { + return fExceptionThrown; + } + + public String toString() { + StringBuffer sb = new StringBuffer("MethodsExceptionUsageResult:\n"); + sb.append("\tthrows Exception=\t"+isExceptionThrown()+"\n"); + sb.append("\tdeclares Exception=\t"+isExceptionDeclared()+"\n"); + sb.append("\tcatches Exception=\t"+isExceptionCaught()+"\n"); + + sb.append("\tException declared by called methods:\n"); + ExceptionDeclaredByCalledMethod[] exceptionDeclaredByCalledMethods = getExceptionDeclaredByCalledMethods(); + for (int i = 0; i < exceptionDeclaredByCalledMethods.length; i++) { + sb.append("\t"+exceptionDeclaredByCalledMethods[i]+"\n"); + } + + return sb.toString(); + } + +} Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/MethodsExceptionUsageAnalyzer.java =================================================================== RCS file: core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/MethodsExceptionUsageAnalyzer.java diff -N core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/MethodsExceptionUsageAnalyzer.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/MethodsExceptionUsageAnalyzer.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,260 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +//TODO rework, generalize and use existing ExceptionAnalyzer +package org.eclipse.jdt.internal.corext.refactoring.remove; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Stack; + +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTVisitor; +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.ConstructorInvocation; +import org.eclipse.jdt.core.dom.IMethodBinding; +import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.MethodInvocation; +import org.eclipse.jdt.core.dom.SimpleName; +import org.eclipse.jdt.core.dom.SuperConstructorInvocation; +import org.eclipse.jdt.core.dom.SuperMethodInvocation; +import org.eclipse.jdt.core.dom.ThrowStatement; +import org.eclipse.jdt.core.dom.TryStatement; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.internal.corext.Assert; +import org.eclipse.jdt.internal.corext.dom.Bindings; +import org.eclipse.jdt.internal.corext.dom.Selection; + +public class MethodsExceptionUsageAnalyzer extends ASTVisitor { + + private Selection fSelection; + private List fCurrentExceptionOccurances; + private Stack fTryStack; + private IType fException; + private MethodsExceptionUsageAnalysisResult fResult; + private MethodDeclaration fMethod; + + private static class ExceptionComparator implements Comparator { + public int compare(Object o1, Object o2) { + int d1 = getDepth((ITypeBinding) o1); + int d2 = getDepth((ITypeBinding) o2); + if (d1 < d2) + return 1; + if (d1 > d2) + return -1; + return 0; + } + private int getDepth(ITypeBinding binding) { + int result = 0; + while (binding != null) { + binding = binding.getSuperclass(); + result++; + } + return result; + } + } + + protected MethodsExceptionUsageAnalyzer( + Selection selection, + IType exception, + MethodsExceptionUsageAnalysisResult result, + MethodDeclaration method) { + Assert.isNotNull(selection); + fSelection = selection; + fTryStack = new Stack(); + fCurrentExceptionOccurances = new ArrayList(1); + fTryStack.push(fCurrentExceptionOccurances); + fException = exception; + fResult = result; + fMethod = method; + + } + // TODO Add type ExceptionUsageAnalyzerResult + public static MethodsExceptionUsageAnalysisResult perform( + IType exceptionToBeAnalyzed, + MethodDeclaration enclosingMethod, + Selection selection) { + MethodsExceptionUsageAnalysisResult result = + new MethodsExceptionUsageAnalysisResult(exceptionToBeAnalyzed); + MethodsExceptionUsageAnalyzer analyzer = + new MethodsExceptionUsageAnalyzer( + selection, + exceptionToBeAnalyzed, + result, + enclosingMethod); + enclosingMethod.accept(analyzer); + result.setExceptionDeclared(analyzer.isExceptionDeclared()); + //if (getDeclaredException(exception, enclosingMethod) != null) + // addExceptionOccurance(getDeclaredException(exception, enclosingMethod)); + //Collections.sort(exceptions, new ExceptionComparator()); TODO what for? + return result; + } + + //TODO check for QualifiedNames too. + private boolean isExceptionDeclared() { + boolean result = false; + for (Iterator simpleNames = fMethod.thrownExceptions().iterator(); + simpleNames.hasNext(); + ) { + SimpleName simpleName = (SimpleName) simpleNames.next(); + ITypeBinding typeBinding = simpleName.resolveTypeBinding(); + if (isRelevantException(typeBinding)) { + result = true; + break; + } + } + return result; + } + private boolean isRelevantException(ITypeBinding exception) { + if (exception + .getQualifiedName() + .equals(fException.getFullyQualifiedName())) + return true; + return false; + } + + public boolean visit(ThrowStatement node) { + ITypeBinding exception = node.getExpression().resolveTypeBinding(); + if (!isSelected(node) + || exception == null + || Bindings.isRuntimeException( + exception)) // Safety net for null bindings when compiling fails. + return true; + // TODO check if runtime exceptions should really be excluded?! + fResult.setExceptionThrown(true); + return true; + } + + public boolean visit(MethodInvocation node) { + if (!isSelected(node)) + return false; + return handleExceptions(node.resolveMethodBinding(), node.getAST()); + } + + public boolean visit(SuperMethodInvocation node) { + if (!isSelected(node)) + return false; + return handleExceptions(node.resolveMethodBinding(), node.getAST()); + } + + public boolean visit(ClassInstanceCreation node) { + if (!isSelected(node)) + return false; + return handleExceptions( + node.resolveConstructorBinding(), + node.getAST()); + } + + public boolean visit(ConstructorInvocation node) { + if (!isSelected(node)) + return false; + return handleExceptions( + node.resolveConstructorBinding(), + node.getAST()); + } + + public boolean visit(SuperConstructorInvocation node) { + if (!isSelected(node)) + return false; + return handleExceptions( + node.resolveConstructorBinding(), + node.getAST()); + } + + private boolean handleExceptions(IMethodBinding binding, AST ast) { + if (binding == null) + return true; + ITypeBinding[] exceptions = binding.getExceptionTypes(); + for (int i = 0; i < exceptions.length; i++) { + if (isRelevantException(exceptions[i])) + fResult.add( + new ExceptionDeclaredByCalledMethod( + exceptions[i], + binding)); + } + return true; + } + + private boolean isSelected(ASTNode node) { + return fSelection.getVisitSelectionMode(node) == Selection.SELECTED; + } + public boolean visit(TypeDeclaration 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) { + fCurrentExceptionOccurances = new ArrayList(1); + fTryStack.push(fCurrentExceptionOccurances); + // 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(); + fCurrentExceptionOccurances = (List) fTryStack.peek(); + for (Iterator iter = current.iterator(); iter.hasNext();) { + //addException((ITypeBinding)iter.next(); + throw new RuntimeException("Not implemented yet!"); + // TODO need to walk the enclosed statements? Would the complier care for that? + } // 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 addExceptionOccurance(ExceptionOccurance exceptionOccurance) { + if (!fCurrentExceptionOccurances.contains(exceptionOccurance)) + fCurrentExceptionOccurances.add(exceptionOccurance); + } + 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(fCurrentExceptionOccurances).iterator(); + exceptions.hasNext(); + ) { + ITypeBinding throwTypeBinding = + (ITypeBinding) exceptions.next(); + if (catches(catchTypeBinding, throwTypeBinding)) + fCurrentExceptionOccurances.remove(throwTypeBinding); + } + } + } + private boolean catches( + ITypeBinding catchTypeBinding, + ITypeBinding throwTypeBinding) { + while (throwTypeBinding != null) { + if (throwTypeBinding == catchTypeBinding) + return true; + throwTypeBinding = throwTypeBinding.getSuperclass(); + } + return false; + } +} Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/Referrer.java =================================================================== RCS file: core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/Referrer.java diff -N core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/Referrer.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/Referrer.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,202 @@ +/* + * Created on 24.07.2003 + * + * To change the template for this generated file go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +package org.eclipse.jdt.internal.corext.refactoring.remove; + +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.SimpleName; +import org.eclipse.jdt.internal.corext.dom.ASTRewrite; +import org.eclipse.jdt.internal.corext.dom.Selection; +import org.eclipse.jdt.internal.corext.refactoring.base.IChange; +import org.eclipse.jdt.internal.corext.refactoring.changes.TextChange; +import org.eclipse.jdt.internal.corext.refactoring.changes.TextFileChange; +import org.eclipse.jdt.internal.corext.refactoring.remove.RemoveRefactoring.ReferrersMap; +import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager; +import org.eclipse.jdt.internal.corext.textmanipulation.MultiTextEdit; +import org.eclipse.jdt.internal.corext.textmanipulation.TextBuffer; +import org.eclipse.jdt.internal.corext.textmanipulation.TextEdit; + + +class Referrer { + private IType fReferencedType; + private IMethod fReferringMethod; + private CompilationUnit fASTCU; + private MethodDeclaration fMethodDeclaration; + private ReferrersMap fEnclosingReferrersMap; + private MethodsExceptionUsageAnalysisResult fResult; + + Referrer( + IType referencedType, + IMethod enclosingElement, + ReferrersMap enclosingReferencesMap) { + fReferencedType = referencedType; + fReferringMethod = enclosingElement; + fEnclosingReferrersMap = enclosingReferencesMap; + analyzeMethod(); + } + + CompilationUnit getASTCU() { + if (fASTCU == null) + fASTCU = + AST.parseCompilationUnit(fReferringMethod.getCompilationUnit(), true); + return fASTCU; + } + + ICompilationUnit getCompilationUnit() { + return fReferencedType.getCompilationUnit(); + } + + MethodDeclaration getReferringMethodDeclaration() { + //TODO remove me. + extractMethodDeclaration(); + return fMethodDeclaration; + } + + ReferrersMap getEnclosingReferenceMap() { + return fEnclosingReferrersMap; + } + + private void analyzeMethod() { + analyzeExceptionUsage(); + } + + private void extractMethodDeclaration() { + + // TODO true? challenge later + MethodMatcher mm = new MethodMatcher(fReferringMethod); + getASTCU().accept(mm); + + fMethodDeclaration = mm.getResult(); + } + + private void analyzeExceptionUsage() { + // TOD look for a better name than occuredException + fResult = + MethodsExceptionUsageAnalyzer.perform( + fReferencedType, + getReferringMethodDeclaration(), + Selection.createFromStartLength( + fMethodDeclaration.getStartPosition(), + fMethodDeclaration.getLength())); + } + + IMethod getReferringMethod() { + return fReferringMethod; + } + boolean isRemovalSafe() { + if (fResult.isExceptionCaught() || fResult.isExceptionThrown()) + return false; + + ExceptionDeclaredByCalledMethod[] edbcm = + fResult.getExceptionDeclaredByCalledMethods(); + for (int i = 0; i < edbcm.length; i++) { + ExceptionDeclaredByCalledMethod method = edbcm[i]; + Referrer calledMethod = + (Referrer) fEnclosingReferrersMap.get( + method.getMethod().getName()); + // TODO replace getName() by real key. also look at + // at collectReferences + boolean isCalledMethodDeclaringTheExceptionAlsoAnObservedReferrer = + calledMethod != null; + if (!isCalledMethodDeclaringTheExceptionAlsoAnObservedReferrer) + return false; + else { + if (!calledMethod.isRemovalSafe()) { + RemoveRefactoring.log( + this, + "removal is unsafe, because of " + calledMethod); + return false; + } + } + } + return true; + } + // TODO do in batch mode with all methods for that particular cu? + IChange rewriteThrowsClause(TextChangeManager changeManager) throws CoreException { + ICompilationUnit enclosingCU = getCompilationUnit(); + //CompilationUnit cu = AST.parseCompilationUnit(enclosingCU, true); + CompilationUnit cu = getASTCU(); + // TODO challenge true + ASTRewrite rewrite = new ASTRewrite(cu); + //ASTNodeDeleteUtil.markAsDeleted(new IMethod[] { method }, cu, rewrite); + + //TODO move the whole method to Reference?! + MethodDeclaration existingMethodDeclaration = getReferringMethodDeclaration(); + List thrownExceptions = existingMethodDeclaration.thrownExceptions(); + for (Iterator allExceptions = thrownExceptions.iterator(); allExceptions.hasNext();) { + SimpleName simpleName = (SimpleName) allExceptions.next(); + if (simpleName.toString().equals(fReferencedType.getElementName())) { + rewrite.markAsRemoved(simpleName); + } + } + + TextBuffer textBuffer = + TextBuffer.create(enclosingCU.getBuffer().getContents()); + TextEdit resultingEdits = new MultiTextEdit(); + rewrite.rewriteNode(textBuffer, resultingEdits); + + TextChange textChange = changeManager.get(enclosingCU); + // TODO what is that supposed to be good for? + if (textChange instanceof TextFileChange) { + TextFileChange tfc = (TextFileChange) textChange; + tfc.setSave(!enclosingCU.isWorkingCopy()); + } + //TODO fix the descriptions + String message = "Remove exception from throws clause of " + existingMethodDeclaration.getName()+"."; + textChange.addTextEdit(message, resultingEdits); + rewrite.removeModifications(); + RemoveRefactoring.log(this, "resultingEdits="+resultingEdits.size()); + return textChange; + + } + + public String toString() { + StringBuffer sb = + new StringBuffer( + "Reference: method=" + + fReferringMethod.getDeclaringType().getFullyQualifiedName() + + "." + + fReferringMethod.getElementName() + + "()\n"); + sb.append("exception usage=\n" + fResult + "\n"); + sb.append("isRemovalSafe=\t" + isRemovalSafe() + "\n"); + // sb.append("\traises Exceptions\n"); + // sb.append("\tinvoking methods=\t\t"); + // IMethodBinding[] methodsDependingOn = getMethodsDependingOn(); + // for (int i = 0; i < methodsDependingOn.length; i++) { + // sb.append(methodsDependingOn[i].getName()); + // if (i != methodsDependingOn.length - 1) + // sb.append(", "); + // + // sb.append("\tDeclared Exceptions=\t"); + // for (int i = 0; i < fDeclaredExceptions.length; i++) { + // sb.append(fDeclaredExceptions[i].getQualifiedName()); + // if (i != fDeclaredExceptions.length - 1) + // sb.append(", "); + // } + // + // sb.append("\n\tRaised Exceptions=\t\t"); + // for (int i = 0; i < fRaisedExceptions.length; i++) { + // sb.append(fRaisedExceptions[i].getQualifiedName()); + // if (i != fRaisedExceptions.length - 1) + // sb.append(", "); + // } + + //} + // sb.append("\n\tsafe removal=\t\t\t" + isRemovalSafe()); + //sb.append("\n"); + return sb.toString(); + } +} Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/RemoveRefactoring.java =================================================================== RCS file: core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/RemoveRefactoring.java diff -N core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/RemoveRefactoring.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/RemoveRefactoring.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,325 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +//TODO 2000? +//TODO Check for subclasses of exception to be removed. +package org.eclipse.jdt.internal.corext.refactoring.remove; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.SubProgressMonitor; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.SimpleName; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.search.IJavaSearchConstants; +import org.eclipse.jdt.core.search.IJavaSearchResultCollector; +import org.eclipse.jdt.core.search.IJavaSearchScope; +import org.eclipse.jdt.core.search.SearchEngine; +import org.eclipse.jdt.internal.corext.Assert; +import org.eclipse.jdt.internal.corext.dom.ASTRewrite; +import org.eclipse.jdt.internal.corext.refactoring.Checks; +import org.eclipse.jdt.internal.corext.refactoring.CompositeChange; +import org.eclipse.jdt.internal.corext.refactoring.base.IChange; +import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext; +import org.eclipse.jdt.internal.corext.refactoring.base.Refactoring; +import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatus; +import org.eclipse.jdt.internal.corext.refactoring.changes.TextChange; +import org.eclipse.jdt.internal.corext.refactoring.changes.TextFileChange; +import org.eclipse.jdt.internal.corext.refactoring.reorg.ASTNodeDeleteUtil; +import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager; +import org.eclipse.jdt.internal.corext.textmanipulation.MultiTextEdit; +import org.eclipse.jdt.internal.corext.textmanipulation.TextBuffer; +import org.eclipse.jdt.internal.corext.textmanipulation.TextEdit; + +/** + * TODO describe me + */ +public class RemoveRefactoring extends Refactoring { + + public static RemoveRefactoring create(IType type) + throws JavaModelException { + if (Checks.checkAvailability(type).hasFatalError()) { + // TODO challenge + log(RemoveRefactoring.class, "checkAvailabilty has fatal error."); + return null; + } + return new RemoveRefactoring(type); + } + + public static void log(Object caller, String message) { + System.out.println(caller.getClass().getName() + ": " + message); + } + private TextChangeManager fChangeManager; + private IType fType; + + private ReferrersMap fReferrersMap; + private RemoveRefactoring(IType type) { + fType = type; + fReferrersMap = new ReferrersMap(); + fChangeManager = new TextChangeManager(); + } + + public RefactoringStatus checkActivation(IProgressMonitor pm) + throws JavaModelException { + + log(this, "checkActivation::enter"); + + pm.beginTask("", 11); // TODO message + pm.setTaskName("Checking selected IType"); // TODO message + + RefactoringStatus result = new RefactoringStatus(); + //log(this, "type=" + fType); + validateTypeIsSubclassOfThrowable( + result, + new SubProgressMonitor(pm, 1)); + log(this, "result.isOK()=" + result.isOK()); + log(this, "result=" + result); + log(this, "checkActivation::exit"); + pm.done(); + return result; + } + + public RefactoringStatus checkInput(IProgressMonitor pm) + throws JavaModelException { + log(this, "checkInput::enter"); + RefactoringStatus result = new RefactoringStatus(); + fChangeManager.clear(); + + pm.beginTask("", 1); // PM + pm.setTaskName("Checking input."); // TODO message + + collectReferrers(new SubProgressMonitor(pm, 1)); + int removedCount = 0; + for (Iterator referrers = fReferrersMap.values().iterator(); + referrers.hasNext(); + ) { + Referrer referrer = (Referrer) referrers.next(); + log(this, "processing " + referrer + "."); + if (referrer.isRemovalSafe()) { + try { + log(this, "rewriting Throws Clause."); + referrer.rewriteThrowsClause(fChangeManager); + log(this, "rewriting Throws Clause done."); + removedCount++; + } catch (CoreException e) { + result.addFatalError( + "CoreException raised while removing method.", + JavaStatusContext.create( + referrer.getReferringMethod())); + } + } + } + + log(this, "checkInput::" + fReferrersMap.size()); + // check number of edits instead? + try { + if (fReferrersMap.size() == removedCount) + removeReferencedType(fChangeManager); + } catch (CoreException e) { + result.addFatalError( + "CoreException raised while removing method.", + JavaStatusContext.create(fType)); + } + log(this, "checkInput::exit"); + return result; + } + + private TextChange removeReferencedType(TextChangeManager changeManager) + throws CoreException { + CompilationUnit cu = + AST.parseCompilationUnit(fType.getCompilationUnit(), true); + TypeMatcher typeMatcher = new TypeMatcher(fType); + cu.accept(typeMatcher); + TypeDeclaration typeDeclaration = typeMatcher.getResult(); + ASTRewrite rewrite = new ASTRewrite(cu); + ASTNodeDeleteUtil.markAsDeleted(new IType[] { fType }, cu, rewrite); + + TextBuffer textBuffer = + TextBuffer.create( + fType.getCompilationUnit().getBuffer().getContents()); + TextEdit resultingEdits = new MultiTextEdit(); + rewrite.rewriteNode(textBuffer, resultingEdits); + + TextChange textChange = changeManager.get(fType.getCompilationUnit()); + // TODO what is that supposed to be good for? + if (textChange instanceof TextFileChange) { + TextFileChange tfc = (TextFileChange) textChange; + tfc.setSave(!fType.getCompilationUnit().isWorkingCopy()); + } + //TODO fix the descriptions + String message = + "Remove exception from throws clause of " + + fType.getElementName() + + "."; + textChange.addTextEdit(message, resultingEdits); + rewrite.removeModifications(); + RemoveRefactoring.log(this, "resultingEdits=" + resultingEdits.size()); + return textChange; + + } + + private void collectReferrers(final IProgressMonitor pm) + throws JavaModelException { + log(this, "collectReferences::enter"); + pm.beginTask("", 5); + pm.setTaskName("Searching references"); // TODO + + IJavaSearchResultCollector searchCollector = + new IJavaSearchResultCollector() { + public void aboutToStart() { + } + + public void accept( + IResource resource, + int start, + int end, + IJavaElement enclosingElement, + int accuracy) + throws CoreException { + Assert.isTrue( + enclosingElement.getElementType() == IJavaElement.METHOD, + "Oops. Haven't expected anything, but a method."); + //TODO + addReference( + new Referrer( + fType, + (IMethod) enclosingElement, + fReferrersMap)); + // TODO check for accuracy needed + } + + private void addReference(Referrer reference) { + ReferrersMap referencesMap = + reference.getEnclosingReferenceMap(); + if (referencesMap + .get(reference.getReferringMethod().getElementName()) + == null) + referencesMap.put( + reference.getReferringMethod().getElementName(), + reference); + } + + public void done() { + } + + public IProgressMonitor getProgressMonitor() { + return pm; + } + }; + new SearchEngine().search( + ResourcesPlugin.getWorkspace(), + fType, + IJavaSearchConstants.REFERENCES, + SearchEngine.createJavaSearchScope( + new IJavaElement[] { fType.getCompilationUnit()}), + searchCollector); + // TODO enlarge scope + log(this, "\n" + fReferrersMap.toString()); + pm.done(); + log(this, "collectReferences::exit"); + } + + public IChange createChange(IProgressMonitor pm) + throws JavaModelException { + log(this, "createChange::enter"); + CompositeChange result = new CompositeChange(getName()); + + result.addAll(fChangeManager.getAllChanges()); + log(this, "createChange::exit"); + return result; + } + + public String getName() { + // TODO + return "Remove (from getName())"; + } + private void validateTypeIsSubclassOfThrowable( + final RefactoringStatus result, + final IProgressMonitor pm) + throws JavaModelException { + //String[] superTypesNames = type.getSuperInterfaceNames(); + // if (superTypesNames.length == 0 + // || !superTypesNames[superTypesNames.length + // - 1].equals("java.lang.Throwable")) + // result.addFatalError("Type does not extend Throwable"); + // TODO provide real message + // TODO check the hierarchy, not just the immediate superclass + // TODO check qualified/simple + //if (!type.getSuperclassName().equals("java.lang.Exception")) + // result.addFatalError("Type does not extend Throwable"); + //pm.worked(1); + + IJavaSearchScope searchScope = SearchEngine.createHierarchyScope(fType); + new SearchEngine() + .search(ResourcesPlugin.getWorkspace(), "java.lang.Exception", + // TODO Why doesn't this work with Throwable? + IJavaSearchConstants.TYPE, + IJavaSearchConstants.REFERENCES, + searchScope, + new IJavaSearchResultCollector() { + boolean typeIsSubclassOfThrowable = false; + public void aboutToStart() { + //log(this, "aboutToStart"); + } + + public void accept( + IResource resource, + int start, + int end, + IJavaElement enclosingElement, + int accuracy) + throws CoreException { + typeIsSubclassOfThrowable = true; + //log(this, "accept"); + } + + public void done() { + if (!typeIsSubclassOfThrowable) + result.addFatalError( + fType.getElementName() + + " is not a subclass of java.lang.Throwable."); + // TODO rework literal. + //log(this, "done()"); + } + + public IProgressMonitor getProgressMonitor() { + return pm; + } + }); + + } + class ReferrersMap extends HashMap { + //TODO check other ways to implement the enclosing reference map + public String toString() { + StringBuffer sb = + new StringBuffer( + "ReferencesMap: (holding " + size() + " references)\n"); + for (Iterator allReferences = values().iterator(); + allReferences.hasNext(); + ) { + Referrer reference = (Referrer) allReferences.next(); + sb.append(reference + "\n"); + } + return sb.toString(); + } + } +} Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/TypeMatcher.java =================================================================== RCS file: core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/TypeMatcher.java diff -N core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/TypeMatcher.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/remove/TypeMatcher.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,39 @@ +/* + * Created on 24.07.2003 + * + * To change the template for this generated file go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +package org.eclipse.jdt.internal.corext.refactoring.remove; + +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.TypeDeclaration; + +class TypeMatcher extends ASTVisitor { + + private TypeDeclaration fResult; + private IType fType; + + TypeMatcher(IType type) { + fType = type; + } + + public void endVisit(TypeDeclaration typeDeclaration) { // TODO bogus, care for different argument types, stop + // visits when fResult is set initially + if (typeDeclaration + .getName() + .toString() + .equals(fType.getElementName().toString())) { + RemoveRefactoring.log( + this, + "found " + fType.getElementName().toString()); + fResult = typeDeclaration; + } + } + + /** returns null when no match is found */ + TypeDeclaration getResult() { + return fResult; + } +}