blob: 1a1da837b8ceef9e561f2ccb4cbb929bd7bea916 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2006 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.generics;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.resources.IFile;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.ChangeDescriptor;
import org.eclipse.ltk.core.refactoring.RefactoringChangeDescriptor;
import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
import org.eclipse.jdt.core.BindingKey;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTRequestor;
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.jdt.core.dom.CastExpression;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.ParameterizedType;
import org.eclipse.jdt.core.dom.ParenthesizedExpression;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeLiteral;
import org.eclipse.jdt.internal.corext.SourceRange;
import org.eclipse.jdt.internal.corext.refactoring.Checks;
import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptor;
import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptorComment;
import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
import org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitChange;
import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationStateChange;
import org.eclipse.jdt.internal.corext.refactoring.code.ScriptableRefactoring;
import org.eclipse.jdt.internal.corext.refactoring.generics.InferTypeArgumentsUpdate.CuUpdate;
import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType;
import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.EnumeratedTypeSet;
import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet;
import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.CastVariable2;
import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.CollectionElementVariable2;
import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ConstraintVariable2;
import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.TypeVariable2;
import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.corext.util.Messages;
import org.eclipse.jdt.ui.JavaElementLabels;
import org.eclipse.jdt.internal.ui.IJavaStatusConstants;
import org.eclipse.jdt.internal.ui.JavaPlugin;
public class InferTypeArgumentsRefactoring extends ScriptableRefactoring {
private static final String ID_INFER_TYPE_ARGUMENTS= "org.eclipse.jdt.ui.infer.typearguments"; //$NON-NLS-1$
private static final String ATTRIBUTE_CLONE= "clone"; //$NON-NLS-1$
private static final String ATTRIBUTE_LEAVE= "leave"; //$NON-NLS-1$
private static final String REWRITTEN= "InferTypeArgumentsRefactoring.rewritten"; //$NON-NLS-1$
private TextChangeManager fChangeManager;
private IJavaElement[] fElements;
private InferTypeArgumentsTCModel fTCModel;
private boolean fAssumeCloneReturnsSameType;
private boolean fLeaveUnconstrainedRaw;
/**
* Creates a new infer type arguments refactoring.
* @param elements the elements to process, or <code>null</code> if invoked by scripting
*/
public InferTypeArgumentsRefactoring(IJavaElement[] elements) {
fElements= elements;
}
/*
* @see org.eclipse.ltk.core.refactoring.Refactoring#getName()
*/
public String getName() {
return RefactoringCoreMessages.InferTypeArgumentsRefactoring_name;
}
public void setAssumeCloneReturnsSameType(boolean assume) {
fAssumeCloneReturnsSameType= assume;
}
public boolean getAssumeCloneReturnsSameType() {
return fAssumeCloneReturnsSameType;
}
public void setLeaveUnconstrainedRaw(boolean raw) {
fLeaveUnconstrainedRaw= raw;
}
public boolean getLeaveUnconstrainedRaw() {
return fLeaveUnconstrainedRaw;
}
/*
* @see org.eclipse.ltk.core.refactoring.Refactoring#checkInitialConditions(org.eclipse.core.runtime.IProgressMonitor)
*/
public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException {
RefactoringStatus result= check15();
pm.done();
return result;
}
/*
* @see org.eclipse.ltk.core.refactoring.Refactoring#checkFinalConditions(org.eclipse.core.runtime.IProgressMonitor)
*/
public RefactoringStatus checkFinalConditions(final IProgressMonitor pm) throws CoreException, OperationCanceledException {
HashMap/*<IJavaProject, List<JavaElement>>*/ projectsToElements= getJavaElementsPerProject(fElements);
pm.beginTask("", projectsToElements.size() + 2); //$NON-NLS-1$
final RefactoringStatus result= new RefactoringStatus();
try {
fTCModel= new InferTypeArgumentsTCModel();
final InferTypeArgumentsConstraintCreator unitCollector= new InferTypeArgumentsConstraintCreator(fTCModel, fAssumeCloneReturnsSameType);
for (Iterator iter= projectsToElements.entrySet().iterator(); iter.hasNext(); ) {
Entry entry= (Entry) iter.next();
IJavaProject project= (IJavaProject) entry.getKey();
List javaElementsList= (List) entry.getValue();
IJavaElement[] javaElements= (IJavaElement[]) javaElementsList.toArray(new IJavaElement[javaElementsList.size()]);
List cus= Arrays.asList(JavaModelUtil.getAllCompilationUnits(javaElements));
int batchSize= 150;
int batches= ((cus.size()-1) / batchSize) + 1;
SubProgressMonitor projectMonitor= new SubProgressMonitor(pm, 1);
projectMonitor.beginTask("", batches); //$NON-NLS-1$
projectMonitor.setTaskName(RefactoringCoreMessages.InferTypeArgumentsRefactoring_building);
for (int i= 0; i < batches; i++) {
List batch= cus.subList(i * batchSize, Math.min(cus.size(), (i + 1) * batchSize));
ICompilationUnit[] batchCus= (ICompilationUnit[]) batch.toArray(new ICompilationUnit[batch.size()]);
final SubProgressMonitor batchMonitor= new SubProgressMonitor(projectMonitor, 1);
batchMonitor.subTask(RefactoringCoreMessages.InferTypeArgumentsRefactoring_calculating_dependencies);
ASTParser parser= ASTParser.newParser(AST.JLS3);
parser.setProject(project);
parser.setCompilerOptions(RefactoringASTParser.getCompilerOptions(project));
parser.setResolveBindings(true);
parser.createASTs(batchCus, new String[0], new ASTRequestor() {
public void acceptAST(final ICompilationUnit source, final CompilationUnit ast) {
batchMonitor.subTask(source.getElementName());
SafeRunner.run(new ISafeRunnable() {
public void run() throws Exception {
IProblem[] problems= ast.getProblems();
for (int p= 0; p < problems.length; p++) {
if (problems[p].isError()) {
String cuName= JavaElementLabels.getElementLabel(source, JavaElementLabels.CU_QUALIFIED);
String msg= Messages.format(RefactoringCoreMessages.InferTypeArgumentsRefactoring_error_in_cu_skipped, new Object[] {cuName});
result.addError(msg, JavaStatusContext.create(source, new SourceRange(problems[p])));
return;
}
}
ast.accept(unitCollector);
}
public void handleException(Throwable exception) {
String cuName= JavaElementLabels.getElementLabel(source, JavaElementLabels.CU_QUALIFIED);
String msg= Messages.format(RefactoringCoreMessages.InferTypeArgumentsRefactoring_internal_error, new Object[] {cuName});
JavaPlugin.log(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IJavaStatusConstants.INTERNAL_ERROR, msg, null));
String msg2= Messages.format(RefactoringCoreMessages.InferTypeArgumentsRefactoring_error_skipped, new Object[] {cuName});
result.addError(msg2, JavaStatusContext.create(source));
}
});
fTCModel.newCu();
}
public void acceptBinding(String bindingKey, IBinding binding) {
//do nothing
}
}, batchMonitor);
}
projectMonitor.done();
fTCModel.newCu();
}
// Display.getDefault().syncExec(new Runnable() {
// public void run() {
// MessageDialog.openInformation(Display.getCurrent().getActiveShell(), "Debugging...", "after constraint gen");
// }
// });
pm.setTaskName(RefactoringCoreMessages.InferTypeArgumentsRefactoring_solving);
InferTypeArgumentsConstraintsSolver solver= new InferTypeArgumentsConstraintsSolver(fTCModel);
InferTypeArgumentsUpdate updates= solver.solveConstraints(new SubProgressMonitor(pm, 1));
solver= null; //free caches
fChangeManager= new TextChangeManager();
rewriteDeclarations(updates, new SubProgressMonitor(pm, 1));
IFile[] filesToModify= ResourceUtil.getFiles(fChangeManager.getAllCompilationUnits());
result.merge(Checks.validateModifiesFiles(filesToModify, getValidationContext()));
return result;
} finally {
pm.done();
clearGlobalState();
}
}
private void clearGlobalState() {
TypeSet.resetCount();
EnumeratedTypeSet.resetCount();
fTCModel= null;
}
private HashMap getJavaElementsPerProject(IJavaElement[] elements) {
HashMap/*<IJavaProject, List<JavaElement>>*/ result= new HashMap/*<IJavaProject, List<JavaElement>>*/();
for (int i= 0; i < fElements.length; i++) {
IJavaElement element= fElements[i];
IJavaProject javaProject= element.getJavaProject();
ArrayList javaElements= (ArrayList) result.get(javaProject);
if (javaElements == null) {
javaElements= new ArrayList();
result.put(javaProject, javaElements);
}
javaElements.add(element);
}
return result;
}
private RefactoringStatus check15() throws CoreException {
RefactoringStatus result= new RefactoringStatus();
HashSet/*<IJavaProject>*/ checkedProjects= new HashSet/*<IJavaProject>*/();
for (int i= 0; i < fElements.length; i++) {
IJavaProject javaProject= fElements[i].getJavaProject();
if (! checkedProjects.contains(javaProject)) {
if (! JavaModelUtil.is50OrHigher(javaProject)) {
String message= Messages.format(RefactoringCoreMessages.InferTypeArgumentsRefactoring_not50, javaProject.getElementName());
result.addFatalError(message);
} else if (! JavaModelUtil.is50OrHigherJRE(javaProject)) {
String message= Messages.format(RefactoringCoreMessages.InferTypeArgumentsRefactoring_not50Library, javaProject.getElementName());
result.addFatalError(message);
}
checkedProjects.add(javaProject);
}
}
return result;
}
private void rewriteDeclarations(InferTypeArgumentsUpdate update, IProgressMonitor pm) throws CoreException {
HashMap/*<ICompilationUnit, CuUpdate>*/ updates= update.getUpdates();
Set entrySet= updates.entrySet();
pm.beginTask("", entrySet.size()); //$NON-NLS-1$
pm.setTaskName(RefactoringCoreMessages.InferTypeArgumentsRefactoring_creatingChanges);
for (Iterator iter= entrySet.iterator(); iter.hasNext();) {
if (pm.isCanceled())
throw new OperationCanceledException();
Map.Entry entry= (Map.Entry) iter.next();
ICompilationUnit cu= (ICompilationUnit) entry.getKey();
pm.worked(1);
pm.subTask(cu.getElementName());
CompilationUnitRewrite rewrite= new CompilationUnitRewrite(cu);
rewrite.setResolveBindings(false);
CuUpdate cuUpdate= (CuUpdate) entry.getValue();
for (Iterator cvIter= cuUpdate.getDeclarations().iterator(); cvIter.hasNext();) {
ConstraintVariable2 cv= (ConstraintVariable2) cvIter.next();
rewriteConstraintVariable(cv, rewrite, fTCModel, fLeaveUnconstrainedRaw, null);
}
for (Iterator castsIter= cuUpdate.getCastsToRemove().iterator(); castsIter.hasNext();) {
CastVariable2 castCv= (CastVariable2) castsIter.next();
rewriteCastVariable(castCv, rewrite, fTCModel);
}
CompilationUnitChange change= rewrite.createChange();
if (change != null) {
fChangeManager.manage(cu, change);
}
}
}
public static ParameterizedType[] inferArguments(SimpleType[] types, InferTypeArgumentsUpdate update, InferTypeArgumentsTCModel model, CompilationUnitRewrite rewrite) {
for (int i= 0; i < types.length; i++) {
types[i].setProperty(REWRITTEN, null);
}
List result= new ArrayList();
HashMap/*<ICompilationUnit, CuUpdate>*/ updates= update.getUpdates();
Set entrySet= updates.entrySet();
for (Iterator iter= entrySet.iterator(); iter.hasNext();) {
Map.Entry entry= (Map.Entry) iter.next();
rewrite.setResolveBindings(false);
CuUpdate cuUpdate= (CuUpdate) entry.getValue();
for (Iterator cvIter= cuUpdate.getDeclarations().iterator(); cvIter.hasNext();) {
ConstraintVariable2 cv= (ConstraintVariable2) cvIter.next();
ParameterizedType newNode= rewriteConstraintVariable(cv, rewrite, model, false, types);
if (newNode != null)
result.add(newNode);
}
}
return (ParameterizedType[])result.toArray(new ParameterizedType[result.size()]);
}
private static ParameterizedType rewriteConstraintVariable(ConstraintVariable2 cv, CompilationUnitRewrite rewrite, InferTypeArgumentsTCModel tCModel, boolean leaveUnconstraindRaw, SimpleType[] types) {
if (cv instanceof CollectionElementVariable2) {
ConstraintVariable2 parentElement= ((CollectionElementVariable2) cv).getParentConstraintVariable();
if (parentElement instanceof TypeVariable2) {
TypeVariable2 typeCv= (TypeVariable2) parentElement;
return rewriteTypeVariable(typeCv, rewrite, tCModel, leaveUnconstraindRaw, types);
} else {
//only rewrite type variables
}
}
return null;
}
private static ParameterizedType rewriteTypeVariable(TypeVariable2 typeCv, CompilationUnitRewrite rewrite, InferTypeArgumentsTCModel tCModel, boolean leaveUnconstraindRaw, SimpleType[] types) {
ASTNode node= typeCv.getRange().getNode(rewrite.getRoot());
if (node instanceof Name && node.getParent() instanceof Type) {
Type originalType= (Type) node.getParent();
if (types != null && !has(types, originalType))
return null;
// Must rewrite all type arguments in one batch. Do the rewrite when the first one is encountered; skip the others.
Object rewritten= originalType.getProperty(REWRITTEN);
if (rewritten == REWRITTEN)
return null;
originalType.setProperty(REWRITTEN, REWRITTEN);
ArrayList typeArgumentCvs= getTypeArgumentCvs(typeCv, tCModel);
Type[] typeArguments= getTypeArguments(originalType, typeArgumentCvs, rewrite, tCModel, leaveUnconstraindRaw);
if (typeArguments == null)
return null;
Type movingType= (Type) rewrite.getASTRewrite().createMoveTarget(originalType);
ParameterizedType newType= rewrite.getAST().newParameterizedType(movingType);
for (int i= 0; i < typeArguments.length; i++) {
newType.typeArguments().add(typeArguments[i]);
}
rewrite.getASTRewrite().replace(originalType, newType, rewrite.createGroupDescription(RefactoringCoreMessages.InferTypeArgumentsRefactoring_addTypeArguments));
return newType;
} else {//TODO: other node types?
return null;
}
}
private static boolean has(SimpleType[] types, Type originalType) {
for (int i= 0; i < types.length; i++) {
if (types[i] == originalType)
return true;
}
return false;
}
/**
* @return the new type arguments, or <code>null</code> iff an argument could not be infered
*/
private static Type[] getTypeArguments(Type baseType, ArrayList typeArgumentCvs, CompilationUnitRewrite rewrite, InferTypeArgumentsTCModel tCModel, boolean leaveUnconstraindRaw) {
if (typeArgumentCvs.size() == 0)
return null;
Type[] typeArguments= new Type[typeArgumentCvs.size()];
for (int i= 0; i < typeArgumentCvs.size(); i++) {
CollectionElementVariable2 elementCv= (CollectionElementVariable2) typeArgumentCvs.get(i);
Type typeArgument;
TType chosenType= InferTypeArgumentsConstraintsSolver.getChosenType(elementCv);
if (chosenType != null) {
if (chosenType.isWildcardType() && ! unboundedWildcardAllowed(baseType))
return null; // can't e.g. write "new ArrayList<?>()".
if (chosenType.isParameterizedType()) // workaround for bug 99124
chosenType= chosenType.getTypeDeclaration();
BindingKey bindingKey= new BindingKey(chosenType.getBindingKey());
typeArgument= rewrite.getImportRewrite().addImportFromSignature(bindingKey.toSignature(), rewrite.getAST());
ArrayList nestedTypeArgumentCvs= getTypeArgumentCvs(elementCv, tCModel);
Type[] nestedTypeArguments= getTypeArguments(typeArgument, nestedTypeArgumentCvs, rewrite, tCModel, leaveUnconstraindRaw); //recursion
if (nestedTypeArguments != null) {
ParameterizedType parameterizedType= rewrite.getAST().newParameterizedType(typeArgument);
for (int j= 0; j < nestedTypeArguments.length; j++)
parameterizedType.typeArguments().add(nestedTypeArguments[j]);
typeArgument= parameterizedType;
}
} else { // couldn't infer an element type (no constraints)
if (leaveUnconstraindRaw) {
// every guess could be wrong => leave the whole thing raw
return null;
} else {
if (unboundedWildcardAllowed(baseType)) {
typeArgument= rewrite.getAST().newWildcardType();
} else {
String object= rewrite.getImportRewrite().addImport("java.lang.Object"); //$NON-NLS-1$
typeArgument= (Type) rewrite.getASTRewrite().createStringPlaceholder(object, ASTNode.SIMPLE_TYPE);
}
}
// ASTNode baseTypeParent= baseType.getParent();
// if (baseTypeParent instanceof ClassInstanceCreation) {
// //No ? allowed. Take java.lang.Object.
// typeArgument= rewrite.getAST().newSimpleType(rewrite.getAST().newName(rewrite.getImportRewrite().addImport("java.lang.Object"))); //$NON-NLS-1$
// } else if (baseTypeParent instanceof ArrayCreation || baseTypeParent instanceof InstanceofExpression) {
// //Only ? allowed.
// typeArgument= rewrite.getAST().newWildcardType();
// } else {
// //E.g. field type: can put anything. Choosing ? in order to be most constraining.
// typeArgument= rewrite.getAST().newWildcardType();
// }
}
typeArguments[i]= typeArgument;
}
return typeArguments;
}
private static ArrayList/*<CollectionElementVariable2>*/ getTypeArgumentCvs(ConstraintVariable2 baseCv, InferTypeArgumentsTCModel tCModel) {
Map elementCvs= tCModel.getElementVariables(baseCv);
ArrayList typeArgumentCvs= new ArrayList();
for (Iterator iter= elementCvs.values().iterator(); iter.hasNext();) {
CollectionElementVariable2 elementCv= (CollectionElementVariable2) iter.next();
int index= elementCv.getDeclarationTypeVariableIndex();
if (index != CollectionElementVariable2.NOT_DECLARED_TYPE_VARIABLE_INDEX) {
while (index >= typeArgumentCvs.size())
typeArgumentCvs.add(null); // fill with null until set(index, ..) is possible
typeArgumentCvs.set(index, elementCv);
}
}
return typeArgumentCvs;
}
private static boolean unboundedWildcardAllowed(Type originalType) {
ASTNode parent= originalType.getParent();
while (parent instanceof Type)
parent= parent.getParent();
if (parent instanceof ClassInstanceCreation) {
return false;
} else if (parent instanceof AbstractTypeDeclaration) {
return false;
} else if (parent instanceof TypeLiteral) {
return false;
}
return true;
}
private static ASTNode rewriteCastVariable(CastVariable2 castCv, CompilationUnitRewrite rewrite, InferTypeArgumentsTCModel tCModel) {//, List positionGroups) {
ASTNode node= castCv.getRange().getNode(rewrite.getRoot());
ConstraintVariable2 expressionVariable= castCv.getExpressionVariable();
ConstraintVariable2 methodReceiverCv= tCModel.getMethodReceiverCv(expressionVariable);
if (methodReceiverCv != null) {
TType chosenReceiverType= InferTypeArgumentsConstraintsSolver.getChosenType(methodReceiverCv);
if (chosenReceiverType == null)
return null;
else if (! InferTypeArgumentsTCModel.isAGenericType(chosenReceiverType))
return null;
else if (hasUnboundElement(methodReceiverCv, tCModel))
return null;
}
CastExpression castExpression= (CastExpression) node;
Expression expression= castExpression.getExpression();
ASTNode nodeToReplace;
if (castExpression.getParent() instanceof ParenthesizedExpression)
nodeToReplace= castExpression.getParent();
else
nodeToReplace= castExpression;
Expression newExpression= (Expression) rewrite.getASTRewrite().createMoveTarget(expression);
rewrite.getASTRewrite().replace(nodeToReplace, newExpression, rewrite.createGroupDescription(RefactoringCoreMessages.InferTypeArgumentsRefactoring_removeCast));
rewrite.getImportRemover().registerRemovedNode(nodeToReplace);
return newExpression;
}
private static boolean hasUnboundElement(ConstraintVariable2 methodReceiverCv, InferTypeArgumentsTCModel tCModel) {
ArrayList/*<CollectionElementVariable2>*/ typeArgumentCvs= getTypeArgumentCvs(methodReceiverCv, tCModel);
for (Iterator iter= typeArgumentCvs.iterator(); iter.hasNext();) {
CollectionElementVariable2 elementCv= (CollectionElementVariable2) iter.next();
TType chosenElementType= InferTypeArgumentsConstraintsSolver.getChosenType(elementCv);
if (chosenElementType == null)
return true;
}
return false;
}
/*
* @see org.eclipse.ltk.core.refactoring.Refactoring#createChange(org.eclipse.core.runtime.IProgressMonitor)
*/
public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
pm.beginTask("", 1); //$NON-NLS-1$
try {
DynamicValidationStateChange result= new DynamicValidationStateChange(RefactoringCoreMessages.InferTypeArgumentsRefactoring_name, fChangeManager.getAllChanges()) {
public final ChangeDescriptor getDescriptor() {
final Map arguments= new HashMap();
final IJavaProject project= getSingleProject();
final String description= RefactoringCoreMessages.InferTypeArgumentsRefactoring_descriptor_description;
final String header= project != null ? Messages.format(RefactoringCoreMessages.InferTypeArgumentsRefactoring_descriptor_description_project, project.getElementName()) : RefactoringCoreMessages.InferTypeArgumentsRefactoring_descriptor_description;
final String name= project != null ? project.getElementName() : null;
final JavaRefactoringDescriptorComment comment= new JavaRefactoringDescriptorComment(this, header);
final String[] settings= new String[fElements.length];
for (int index= 0; index < settings.length; index++)
settings[index]= JavaElementLabels.getTextLabel(fElements[index], JavaElementLabels.ALL_FULLY_QUALIFIED);
comment.addSetting(JavaRefactoringDescriptorComment.createCompositeSetting(RefactoringCoreMessages.InferTypeArgumentsRefactoring_original_elements, settings));
if (fAssumeCloneReturnsSameType)
comment.addSetting(RefactoringCoreMessages.InferTypeArgumentsRefactoring_assume_clone);
if (fLeaveUnconstrainedRaw)
comment.addSetting(RefactoringCoreMessages.InferTypeArgumentsRefactoring_leave_unconstrained);
final JavaRefactoringDescriptor descriptor= new JavaRefactoringDescriptor(ID_INFER_TYPE_ARGUMENTS, name, description, comment.asString(), arguments, RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE);
for (int index= 0; index < fElements.length; index++)
arguments.put(JavaRefactoringDescriptor.ATTRIBUTE_ELEMENT + (index + 1), descriptor.elementToHandle(fElements[index]));
arguments.put(ATTRIBUTE_CLONE, Boolean.valueOf(fAssumeCloneReturnsSameType).toString());
arguments.put(ATTRIBUTE_LEAVE, Boolean.valueOf(fLeaveUnconstrainedRaw).toString());
return new RefactoringChangeDescriptor(descriptor);
}
};
return result;
} finally {
pm.done();
}
}
private IJavaProject getSingleProject() {
IJavaProject first= null;
for (int index= 0; index < fElements.length; index++) {
final IJavaProject project= fElements[index].getJavaProject();
if (project != null) {
if (first == null)
first= project;
else if (!project.equals(first))
return null;
}
}
return first;
}
public RefactoringStatus initialize(final RefactoringArguments arguments) {
if (arguments instanceof JavaRefactoringArguments) {
final JavaRefactoringArguments generic= (JavaRefactoringArguments) arguments;
final String clone= generic.getAttribute(ATTRIBUTE_CLONE);
if (clone != null) {
fAssumeCloneReturnsSameType= Boolean.valueOf(clone).booleanValue();
} else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_CLONE));
final String leave= generic.getAttribute(ATTRIBUTE_LEAVE);
if (leave != null) {
fLeaveUnconstrainedRaw= Boolean.valueOf(leave).booleanValue();
} else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_LEAVE));
int count= 1;
final List elements= new ArrayList();
String handle= null;
String attribute= JavaRefactoringDescriptor.ATTRIBUTE_ELEMENT + count;
final RefactoringStatus status= new RefactoringStatus();
while ((handle= generic.getAttribute(attribute)) != null) {
final IJavaElement element= JavaRefactoringDescriptor.handleToElement(generic.getProject(), handle, false);
if (element == null || !element.exists())
return createInputFatalStatus(element, ID_INFER_TYPE_ARGUMENTS);
else
elements.add(element);
count++;
attribute= JavaRefactoringDescriptor.ATTRIBUTE_ELEMENT + count;
}
fElements= (IJavaElement[]) elements.toArray(new IJavaElement[elements.size()]);
if (elements.isEmpty())
return createInputFatalStatus(null, ID_INFER_TYPE_ARGUMENTS);
if (!status.isOK())
return status;
} else
return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments);
return new RefactoringStatus();
}
}