/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.lang.java.rule.strings; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; import net.sourceforge.pmd.lang.java.rule.AbstractInefficientZeroCheck; import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence; /** * This rule finds code which inefficiently determines empty strings. This code * * <pre> * if(str.trim().length()==0){.... * </pre> * * <p> * is quite inefficient as trim() causes a new String to be created. Smarter * code to check for an empty string would be: * </p> * * <pre> * Character.isWhitespace(str.charAt(i)); * </pre> * * @author acaplan */ public class InefficientEmptyStringCheckRule extends AbstractInefficientZeroCheck { @Override public boolean isTargetMethod(JavaNameOccurrence occ) { if (occ.getNameForWhichThisIsAQualifier() != null && occ.getNameForWhichThisIsAQualifier().getImage().indexOf("trim") != -1) { Node pExpression = occ.getLocation().jjtGetParent().jjtGetParent(); if (pExpression.jjtGetNumChildren() > 2 && "length".equals(pExpression.jjtGetChild(2).getImage())) { return true; } } return false; } @Override public boolean appliesToClassName(String name) { return "String".equals(name); } @Override public Object visit(ASTPrimaryExpression node, Object data) { if (node.jjtGetNumChildren() > 3) { // Check last suffix if (!"isEmpty".equals(node.jjtGetChild(node.jjtGetNumChildren() - 2).getImage())) { return data; } Node prevCall = node.jjtGetChild(node.jjtGetNumChildren() - 4); String target = prevCall.jjtGetNumChildren() > 0 ? prevCall.jjtGetChild(0).getImage() : prevCall.getImage(); if (target != null && ("trim".equals(target) || target.endsWith(".trim"))) { addViolation(data, node); } } return data; } }