/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.lang.java.rule.basic; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; import net.sourceforge.pmd.lang.java.ast.ASTArrayDimsAndInits; import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTLiteral; import net.sourceforge.pmd.lang.java.ast.ASTName; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; /** * Avoid instantiating Boolean objects; you can reference Boolean.TRUE, * Boolean.FALSE, or call Boolean.valueOf() instead. * * <pre> * public class Foo { * Boolean bar = new Boolean("true"); // just do a Boolean * bar = Boolean.TRUE; //ok * Boolean buz = Boolean.valueOf(false); // just do a Boolean buz = Boolean.FALSE; * } * </pre> */ public class BooleanInstantiationRule extends AbstractJavaRule { /* * see bug 1744065 : If somebody create it owns Boolean, the rule should not * be triggered Therefore, we use this boolean to flag if the source code * contains such an import * */ private boolean customBoolean; @Override public Object visit(ASTCompilationUnit decl, Object data) { // customBoolean needs to be reset for each new file customBoolean = false; return super.visit(decl, data); } @Override public Object visit(ASTImportDeclaration decl, Object data) { // If the import actually import a Boolean class that overrides // java.lang.Boolean if (decl.getImportedName().endsWith("Boolean") && !decl.getImportedName().equals("java.lang")) { customBoolean = true; } return super.visit(decl, data); } @Override public Object visit(ASTAllocationExpression node, Object data) { if (!customBoolean) { if (node.hasDescendantOfType(ASTArrayDimsAndInits.class)) { return super.visit(node, data); } Node n1 = node.getFirstChildOfType(ASTClassOrInterfaceType.class); if (TypeHelper.isA((ASTClassOrInterfaceType) n1, Boolean.class)) { super.addViolation(data, node); return data; } } return super.visit(node, data); } @Override public Object visit(ASTPrimaryPrefix node, Object data) { if (!customBoolean) { if (node.jjtGetNumChildren() == 0 || !(node.jjtGetChild(0) instanceof ASTName)) { return super.visit(node, data); } if ("Boolean.valueOf".equals(((ASTName) node.jjtGetChild(0)).getImage()) || "java.lang.Boolean.valueOf".equals(((ASTName) node.jjtGetChild(0)).getImage())) { ASTPrimaryExpression parent = (ASTPrimaryExpression) node.jjtGetParent(); ASTPrimarySuffix suffix = parent.getFirstDescendantOfType(ASTPrimarySuffix.class); if (suffix == null) { return super.visit(node, data); } ASTPrimaryPrefix prefix = suffix.getFirstDescendantOfType(ASTPrimaryPrefix.class); if (prefix == null) { return super.visit(node, data); } if (prefix.hasDescendantOfType(ASTBooleanLiteral.class)) { super.addViolation(data, node); return data; } ASTLiteral literal = prefix.getFirstDescendantOfType(ASTLiteral.class); if (literal != null && ("\"true\"".equals(literal.getImage()) || "\"false\"".equals(literal.getImage()))) { super.addViolation(data, node); return data; } } } return super.visit(node, data); } }