/*******************************************************************************
* Copyright (c) 2014 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.fix;
import org.eclipse.core.runtime.CoreException;
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.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.ParameterizedType;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
import org.eclipse.jdt.internal.corext.refactoring.util.NoCommentSourceRangeComputer;
import org.eclipse.jdt.internal.ui.text.correction.ProblemLocation;
import org.eclipse.jdt.ui.cleanup.ICleanUpFix;
import org.eclipse.jdt.ui.text.java.IProblemLocation;
import org.eclipse.text.edits.TextEditGroup;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class TypeParametersFix extends CompilationUnitRewriteOperationsFix {
private static final class InsertTypeArgumentsVisitor extends ASTVisitor {
private final ArrayList<ASTNode> fNodes;
private InsertTypeArgumentsVisitor(ArrayList<ASTNode> nodes) {
fNodes = nodes;
}
@Override
public boolean visit(ParameterizedType createdType) {
if (createdType == null || createdType.typeArguments().size() != 0) {
return true;
}
ITypeBinding binding = createdType.resolveBinding();
if (binding == null) {
return true;
}
ITypeBinding[] typeArguments = binding.getTypeArguments();
if (typeArguments.length == 0) {
return true;
}
fNodes.add(createdType);
return true;
}
}
private static class InsertTypeArgumentsOperation extends CompilationUnitRewriteOperation {
private final ParameterizedType[] fCreatedTypes;
public InsertTypeArgumentsOperation(ParameterizedType[] parameterizedTypes) {
fCreatedTypes = parameterizedTypes;
}
/**
* {@inheritDoc}
*/
@Override
public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModel model) throws CoreException {
TextEditGroup group = createTextEditGroup(FixMessages.TypeParametersFix_insert_inferred_type_arguments_description, cuRewrite);
ASTRewrite rewrite = cuRewrite.getASTRewrite();
ImportRewrite importRewrite = cuRewrite.getImportRewrite();
AST ast = cuRewrite.getRoot().getAST();
for (int i = 0; i < fCreatedTypes.length; i++) {
ParameterizedType createdType = fCreatedTypes[i];
ITypeBinding[] typeArguments = createdType.resolveBinding().getTypeArguments();
ContextSensitiveImportRewriteContext importContext =
new ContextSensitiveImportRewriteContext(cuRewrite.getRoot(), createdType.getStartPosition(), importRewrite);
ListRewrite argumentsRewrite = rewrite.getListRewrite(createdType, ParameterizedType.TYPE_ARGUMENTS_PROPERTY);
for (int j = 0; j < typeArguments.length; j++) {
ITypeBinding typeArgument = typeArguments[j];
Type argumentNode = importRewrite.addImport(typeArgument, ast, importContext);
argumentsRewrite.insertLast(argumentNode, group);
}
}
}
}
private static class RemoveTypeArgumentsOperation extends CompilationUnitRewriteOperation {
private final ParameterizedType fParameterizedType;
public RemoveTypeArgumentsOperation(ParameterizedType parameterizedType) {
fParameterizedType = parameterizedType;
}
/**
* {@inheritDoc}
*/
@Override
public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModel model) throws CoreException {
TextEditGroup group = createTextEditGroup(FixMessages.TypeParametersFix_remove_redundant_type_arguments_description,
cuRewrite);
ASTRewrite rewrite = cuRewrite.getASTRewrite();
rewrite.setTargetSourceRangeComputer(new NoCommentSourceRangeComputer());
ListRewrite listRewrite = rewrite.getListRewrite(fParameterizedType, ParameterizedType.TYPE_ARGUMENTS_PROPERTY);
List<Type> typeArguments = fParameterizedType.typeArguments();
for (Iterator<Type> iterator = typeArguments.iterator(); iterator.hasNext(); ) {
listRewrite.remove(iterator.next(), group);
}
}
}
public static TypeParametersFix createInsertInferredTypeArgumentsFix(CompilationUnit compilationUnit, ParameterizedType node) {
if (node == null)
return null;
final ArrayList<ASTNode> changedNodes = new ArrayList<ASTNode>();
node.accept(new InsertTypeArgumentsVisitor(changedNodes));
if (changedNodes.isEmpty())
return null;
CompilationUnitRewriteOperation op = new InsertTypeArgumentsOperation(new ParameterizedType[]{node});
return new TypeParametersFix(FixMessages.TypeParametersFix_insert_inferred_type_arguments_name, compilationUnit,
new CompilationUnitRewriteOperation[]{op});
}
public static TypeParametersFix createRemoveRedundantTypeArgumentsFix(CompilationUnit compilationUnit, IProblemLocation problem) {
int id = problem.getProblemId();
if (id == IProblem.RedundantSpecificationOfTypeArguments) {
ParameterizedType parameterizedType = getParameterizedType(compilationUnit, problem);
if (parameterizedType == null)
return null;
RemoveTypeArgumentsOperation operation = new RemoveTypeArgumentsOperation(parameterizedType);
return new TypeParametersFix(FixMessages.TypeParametersFix_remove_redundant_type_arguments_name, compilationUnit,
new CompilationUnitRewriteOperation[]{operation});
}
return null;
}
public static ICleanUpFix createCleanUp(CompilationUnit compilationUnit, boolean insertInferredTypeArguments,
boolean removeRedundantTypeArguments) {
IProblem[] problems = compilationUnit.getProblems();
IProblemLocation[] locations = new IProblemLocation[problems.length];
for (int i = 0; i < problems.length; i++) {
locations[i] = new ProblemLocation(problems[i]);
}
return createCleanUp(compilationUnit, locations,
insertInferredTypeArguments,
removeRedundantTypeArguments);
}
public static ICleanUpFix createCleanUp(CompilationUnit compilationUnit, IProblemLocation[] problems,
boolean insertInferredTypeArguments, boolean removeRedundantTypeArguments) {
if (insertInferredTypeArguments) {
final ArrayList<ASTNode> changedNodes = new ArrayList<ASTNode>();
compilationUnit.accept(new InsertTypeArgumentsVisitor(changedNodes));
if (changedNodes.isEmpty())
return null;
CompilationUnitRewriteOperation op =
new InsertTypeArgumentsOperation(changedNodes.toArray(new ParameterizedType[changedNodes.size()]));
return new TypeParametersFix(FixMessages.TypeParametersFix_insert_inferred_type_arguments_name, compilationUnit,
new CompilationUnitRewriteOperation[]{op});
} else if (removeRedundantTypeArguments) {
List<CompilationUnitRewriteOperation> result = new ArrayList<CompilationUnitRewriteOperation>();
for (int i = 0; i < problems.length; i++) {
IProblemLocation problem = problems[i];
int id = problem.getProblemId();
if (id == IProblem.RedundantSpecificationOfTypeArguments) {
ParameterizedType parameterizedType = getParameterizedType(compilationUnit, problem);
if (parameterizedType == null)
return null;
result.add(new RemoveTypeArgumentsOperation(parameterizedType));
}
}
if (!result.isEmpty()) {
return new TypeParametersFix(
FixMessages.TypeParametersFix_remove_redundant_type_arguments_name, compilationUnit, result.toArray(new CompilationUnitRewriteOperation[result.size()]));
}
}
return null;
}
private static ParameterizedType getParameterizedType(CompilationUnit compilationUnit, IProblemLocation problem) {
ASTNode selectedNode= problem.getCoveringNode(compilationUnit);
if (selectedNode == null)
return null;
while (!(selectedNode instanceof ParameterizedType) && !(selectedNode instanceof Statement)) {
selectedNode= selectedNode.getParent();
}
if (selectedNode instanceof ParameterizedType) {
return (ParameterizedType) selectedNode;
}
return null;
}
protected TypeParametersFix(String name, CompilationUnit compilationUnit, CompilationUnitRewriteOperation[] fixRewriteOperations) {
super(name, compilationUnit, fixRewriteOperations);
}
}