View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.java.rule.basic;
5   
6   import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
7   import net.sourceforge.pmd.lang.java.ast.ASTArrayDimsAndInits;
8   import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral;
9   import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
10  import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
11  import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
12  import net.sourceforge.pmd.lang.java.ast.ASTLiteral;
13  import net.sourceforge.pmd.lang.java.ast.ASTName;
14  import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
15  import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
16  import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
17  import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
18  import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper;
19  
20  /**
21   * Avoid instantiating Boolean objects; you can reference Boolean.TRUE,
22   * Boolean.FALSE, or call Boolean.valueOf() instead.
23   *
24   * <pre>
25   *  public class Foo {
26   *       Boolean bar = new Boolean("true");    // just do a Boolean
27   *       bar = Boolean.TRUE;                   //ok
28   *       Boolean buz = Boolean.valueOf(false); // just do a Boolean buz = Boolean.FALSE;
29   *  }
30   * </pre>
31   */
32  public class BooleanInstantiationRule extends AbstractJavaRule {
33  
34  	/*
35  	 *  see bug 1744065 : If somebody create it owns Boolean, the rule should not be triggered
36  	 *   Therefore, we use this boolean to flag if the source code contains such an import
37  	 *
38  	 */
39  	private boolean customBoolean;
40  
41      @Override
42      public Object visit(ASTCompilationUnit decl,Object data) {
43          // customBoolean needs to be reset for each new file
44          customBoolean = false;
45  
46          return super.visit(decl, data);
47      }
48  
49  	@Override
50  	public Object visit(ASTImportDeclaration decl,Object data) {
51  		// If the import actually import a Boolean class that overrides java.lang.Boolean
52  		if ( decl.getImportedName().endsWith("Boolean") && ! decl.getImportedName().equals("java.lang"))
53  		{
54  			customBoolean = true;
55  		}
56  		return super.visit(decl, data);
57  	}
58  
59      @Override
60      public Object visit(ASTAllocationExpression node, Object data) {
61  
62      	if ( ! customBoolean ) {
63  	        if (node.hasDescendantOfType(ASTArrayDimsAndInits.class)) {
64  	            return super.visit(node, data);
65  	        }
66  	        if (TypeHelper.isA((ASTClassOrInterfaceType) node.jjtGetChild(0), Boolean.class)) {
67                  super.addViolation(data, node);
68                  return data;
69              }
70      	}
71          return super.visit(node, data);
72      }
73  
74      @Override
75      public Object visit(ASTPrimaryPrefix node, Object data) {
76  
77      	if ( ! customBoolean )
78      	{
79  	        if (node.jjtGetNumChildren() == 0 || !(node.jjtGetChild(0) instanceof ASTName)) {
80  	            return super.visit(node, data);
81  	        }
82  
83  	        if ("Boolean.valueOf".equals(((ASTName) node.jjtGetChild(0)).getImage())
84  	                || "java.lang.Boolean.valueOf".equals(((ASTName) node.jjtGetChild(0)).getImage())) {
85  	            ASTPrimaryExpression parent = (ASTPrimaryExpression) node.jjtGetParent();
86  	            ASTPrimarySuffix suffix = parent.getFirstDescendantOfType(ASTPrimarySuffix.class);
87  	            if (suffix == null) {
88  	                return super.visit(node, data);
89  	            }
90  	            ASTPrimaryPrefix prefix = suffix.getFirstDescendantOfType(ASTPrimaryPrefix.class);
91  	            if (prefix == null) {
92  	                return super.visit(node, data);
93  	            }
94  
95  	            if (prefix.hasDescendantOfType(ASTBooleanLiteral.class)) {
96  	                super.addViolation(data, node);
97  	                return data;
98  	            }
99  	            ASTLiteral literal = prefix.getFirstDescendantOfType(ASTLiteral.class);
100 	            if (literal != null && ("\"true\"".equals(literal.getImage()) || "\"false\"".equals(literal.getImage()))) {
101 	                super.addViolation(data, node);
102 	                return data;
103 	            }
104 	        }
105     	}
106         return super.visit(node, data);
107     }
108 }