// =====================================================================
//
// Copyright (C) 2012 - 2016, Philip Graf
//
// 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
//
// =====================================================================
package ch.acanda.eclipse.pmd.java.resolution.design;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.InfixExpression;
import org.eclipse.jdt.core.dom.InfixExpression.Operator;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.PrefixExpression;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.text.Position;
import ch.acanda.eclipse.pmd.java.resolution.ASTQuickFix;
import ch.acanda.eclipse.pmd.java.resolution.ASTUtil;
import ch.acanda.eclipse.pmd.java.resolution.Finders;
import ch.acanda.eclipse.pmd.java.resolution.NodeFinder;
import ch.acanda.eclipse.pmd.marker.PMDMarker;
import ch.acanda.eclipse.pmd.ui.util.PMDPluginImages;
/**
* Quick fix for the rule <a
* href="http://pmd.sourceforge.net/rules/java/design.html#UseCollectionIsEmpty">UseCollectionIsEmpty</a>. It replaces
* {@code x.size() == 0} with {@code x.isEmpty()}.
*
* @author Philip Graf
*/
public class UseCollectionIsEmptyQuickFix extends ASTQuickFix<InfixExpression> {
public UseCollectionIsEmptyQuickFix(final PMDMarker marker) {
super(marker);
}
@Override
protected ImageDescriptor getImageDescriptor() {
return PMDPluginImages.QUICKFIX_CHANGE;
}
@Override
public String getLabel() {
return "Replace with call to isEmpty()";
}
@Override
public String getDescription() {
return "Replaces call to size() with call to isEmpty().";
}
@Override
protected NodeFinder<CompilationUnit, InfixExpression> getNodeFinder(final Position position) {
return Finders.positionWithinNode(position, getNodeType());
}
/**
* Replaces {@code x.size() == 0} or {@code 0 == x.size()} with {@code x.isEmpty()}. Replaces {@code x.size() != 0}
* or {@code 0 != x.size()} with {@code !x.isEmpty()}.
*/
@Override
protected boolean apply(final InfixExpression node) {
final MethodInvocation size;
if (node.getLeftOperand() instanceof MethodInvocation) {
size = (MethodInvocation) node.getLeftOperand();
} else if (node.getRightOperand() instanceof MethodInvocation) {
size = (MethodInvocation) node.getRightOperand();
} else {
return false;
}
final AST ast = node.getAST();
final MethodInvocation invocation = (MethodInvocation) ast.createInstance(MethodInvocation.class);
invocation.setExpression(ASTUtil.copy(size.getExpression()));
final SimpleName isEmpty = (SimpleName) ast.createInstance(SimpleName.class);
isEmpty.setIdentifier("isEmpty");
invocation.setName(isEmpty);
final Expression replacement;
if (isNotEmpty(node)) {
final PrefixExpression not = (PrefixExpression) ast.createInstance(PrefixExpression.class);
not.setOperator(org.eclipse.jdt.core.dom.PrefixExpression.Operator.NOT);
not.setOperand(invocation);
replacement = not;
} else {
replacement = invocation;
}
ASTUtil.replace(node, replacement);
return true;
}
/**
* {@code c.size() != 0} and {@code c.size() >= 0} should be converted into {@code !c.isEmpty()}.
*/
private boolean isNotEmpty(final InfixExpression node) {
return Operator.NOT_EQUALS.equals(node.getOperator()) || Operator.GREATER.equals(node.getOperator());
}
}