| /******************************************************************************* |
| * 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(); |
| } |
| } |