// ===================================================================== // // 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.optimization; import static ch.acanda.eclipse.pmd.java.resolution.ASTUtil.copy; import static ch.acanda.eclipse.pmd.java.resolution.ASTUtil.replace; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.CharacterLiteral; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.InfixExpression; import org.eclipse.jdt.core.dom.MethodInvocation; import org.eclipse.jdt.core.dom.StringLiteral; 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.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/optimizations.html#AddEmptyString">AddEmptyString</a>. It replaces the * empty string in additive expressions like <code>"" + 123</code> with <code>String.valueOf(123)</code>. * * @author Philip Graf */ public class AddEmptyStringQuickFix extends ASTQuickFix<InfixExpression> { public AddEmptyStringQuickFix(final PMDMarker marker) { super(marker); } @Override protected ImageDescriptor getImageDescriptor() { return PMDPluginImages.QUICKFIX_REMOVE; } @Override public String getLabel() { return "Remove empty string"; } @Override public String getDescription() { return "Removes the empty string."; } @Override protected NodeFinder<CompilationUnit, InfixExpression> getNodeFinder(final Position position) { return Finders.positionWithinNode(position, getNodeType()); } @Override protected boolean needsTypeResolution() { return true; } @Override @SuppressWarnings("unchecked") protected boolean apply(final InfixExpression node) { final Expression rightOperand = node.getRightOperand(); // "" + "abc" -> "abc" // "" + x.toString() -> x.toString() if (isString(rightOperand)) { return replace(node, copy(rightOperand)); } // "" + 'a' -> "a" if (isCharacterLiteral(rightOperand)) { final AST ast = node.getAST(); final StringLiteral stringLiteral = ast.newStringLiteral(); final String escapedCharacter = ((CharacterLiteral) rightOperand).getEscapedValue(); stringLiteral.setEscapedValue(convertToEscapedString(escapedCharacter)); return replace(node, stringLiteral); } // "" + x -> String.valueOf(x) final AST ast = node.getAST(); final MethodInvocation toString = ast.newMethodInvocation(); toString.setExpression(ast.newSimpleName("String")); toString.setName(ast.newSimpleName("valueOf")); toString.arguments().add(copy(rightOperand)); return replace(node, toString); } private boolean isString(final Expression expression) { return isStringLiteral(expression) || isStringExpression(expression); } private boolean isStringLiteral(final Expression expression) { return expression.getNodeType() == ASTNode.STRING_LITERAL; } private boolean isStringExpression(final Expression expression) { final ITypeBinding typeBinding = expression.resolveTypeBinding(); if (typeBinding != null) { return String.class.getName().equals(typeBinding.getQualifiedName()); } return false; } private boolean isCharacterLiteral(final Expression expression) { return expression.getNodeType() == ASTNode.CHARACTER_LITERAL; } private String convertToEscapedString(final String escapedCharacter) { return '"' + escapedCharacter.substring(1, escapedCharacter.length() - 1) + '"'; } }