001 package net.sourceforge.pmd.lang.java.rule.basic;
002
003 import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
004 import net.sourceforge.pmd.lang.java.ast.ASTArrayDimsAndInits;
005 import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral;
006 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
007 import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
008 import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
009 import net.sourceforge.pmd.lang.java.ast.ASTLiteral;
010 import net.sourceforge.pmd.lang.java.ast.ASTName;
011 import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
012 import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
013 import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
014 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
015 import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper;
016
017 /**
018 * Avoid instantiating Boolean objects; you can reference Boolean.TRUE,
019 * Boolean.FALSE, or call Boolean.valueOf() instead.
020 *
021 * <pre>
022 * public class Foo {
023 * Boolean bar = new Boolean("true"); // just do a Boolean
024 * bar = Boolean.TRUE; //ok
025 * Boolean buz = Boolean.valueOf(false); // just do a Boolean buz = Boolean.FALSE;
026 * }
027 * </pre>
028 */
029 public class BooleanInstantiationRule extends AbstractJavaRule {
030
031 /*
032 * see bug 1744065 : If somebody create it owns Boolean, the rule should not be triggered
033 * Therefore, we use this boolean to flag if the source code contains such an import
034 *
035 */
036 private boolean customBoolean;
037
038 @Override
039 public Object visit(ASTCompilationUnit decl,Object data) {
040 // customBoolean needs to be reset for each new file
041 customBoolean = false;
042
043 return super.visit(decl, data);
044 }
045
046 @Override
047 public Object visit(ASTImportDeclaration decl,Object data) {
048 // If the import actually import a Boolean class that overrides java.lang.Boolean
049 if ( decl.getImportedName().endsWith("Boolean") && ! decl.getImportedName().equals("java.lang"))
050 {
051 customBoolean = true;
052 }
053 return super.visit(decl, data);
054 }
055
056 @Override
057 public Object visit(ASTAllocationExpression node, Object data) {
058
059 if ( ! customBoolean ) {
060 if (node.hasDescendantOfType(ASTArrayDimsAndInits.class)) {
061 return super.visit(node, data);
062 }
063 if (TypeHelper.isA((ASTClassOrInterfaceType) node.jjtGetChild(0), Boolean.class)) {
064 super.addViolation(data, node);
065 return data;
066 }
067 }
068 return super.visit(node, data);
069 }
070
071 @Override
072 public Object visit(ASTPrimaryPrefix node, Object data) {
073
074 if ( ! customBoolean )
075 {
076 if (node.jjtGetNumChildren() == 0 || !(node.jjtGetChild(0) instanceof ASTName)) {
077 return super.visit(node, data);
078 }
079
080 if ("Boolean.valueOf".equals(((ASTName) node.jjtGetChild(0)).getImage())
081 || "java.lang.Boolean.valueOf".equals(((ASTName) node.jjtGetChild(0)).getImage())) {
082 ASTPrimaryExpression parent = (ASTPrimaryExpression) node.jjtGetParent();
083 ASTPrimarySuffix suffix = parent.getFirstDescendantOfType(ASTPrimarySuffix.class);
084 if (suffix == null) {
085 return super.visit(node, data);
086 }
087 ASTPrimaryPrefix prefix = suffix.getFirstDescendantOfType(ASTPrimaryPrefix.class);
088 if (prefix == null) {
089 return super.visit(node, data);
090 }
091
092 if (prefix.hasDescendantOfType(ASTBooleanLiteral.class)) {
093 super.addViolation(data, node);
094 return data;
095 }
096 ASTLiteral literal = prefix.getFirstDescendantOfType(ASTLiteral.class);
097 if (literal != null && ("\"true\"".equals(literal.getImage()) || "\"false\"".equals(literal.getImage()))) {
098 super.addViolation(data, node);
099 return data;
100 }
101 }
102 }
103 return super.visit(node, data);
104 }
105 }
|