001: package net.sourceforge.pmd.rules.basic;
002:
003: import net.sourceforge.pmd.AbstractRule;
004: import net.sourceforge.pmd.ast.ASTAllocationExpression;
005: import net.sourceforge.pmd.ast.ASTArrayDimsAndInits;
006: import net.sourceforge.pmd.ast.ASTBooleanLiteral;
007: import net.sourceforge.pmd.ast.ASTClassOrInterfaceType;
008: import net.sourceforge.pmd.ast.ASTCompilationUnit;
009: import net.sourceforge.pmd.ast.ASTImportDeclaration;
010: import net.sourceforge.pmd.ast.ASTLiteral;
011: import net.sourceforge.pmd.ast.ASTName;
012: import net.sourceforge.pmd.ast.ASTPrimaryExpression;
013: import net.sourceforge.pmd.ast.ASTPrimaryPrefix;
014: import net.sourceforge.pmd.ast.ASTPrimarySuffix;
015: import net.sourceforge.pmd.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 BooleanInstantiation extends AbstractRule {
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: public Object visit(ASTCompilationUnit decl, Object data) {
039: // customBoolean needs to be reset for each new file
040: customBoolean = false;
041:
042: return super .visit(decl, data);
043: }
044:
045: public Object visit(ASTImportDeclaration decl, Object data) {
046: // If the import actually import a Boolean class that overrides java.lang.Boolean
047: if (decl.getImportedName().endsWith("Boolean")
048: && !decl.getImportedName().equals("java.lang")) {
049: customBoolean = true;
050: }
051: return super .visit(decl, data);
052: }
053:
054: public Object visit(ASTAllocationExpression node, Object data) {
055:
056: if (!customBoolean) {
057: if (node.findChildrenOfType(ASTArrayDimsAndInits.class)
058: .size() > 0) {
059: return super .visit(node, data);
060: }
061: if (TypeHelper.isA((ASTClassOrInterfaceType) node
062: .jjtGetChild(0), Boolean.class)) {
063: super .addViolation(data, node);
064: return data;
065: }
066: }
067: return super .visit(node, data);
068: }
069:
070: public Object visit(ASTPrimaryPrefix node, Object data) {
071:
072: if (!customBoolean) {
073: if (node.jjtGetNumChildren() == 0
074: || !node.jjtGetChild(0).getClass().equals(
075: ASTName.class)) {
076: return super .visit(node, data);
077: }
078:
079: if ("Boolean.valueOf"
080: .equals(((ASTName) node.jjtGetChild(0)).getImage())
081: || "java.lang.Boolean.valueOf"
082: .equals(((ASTName) node.jjtGetChild(0))
083: .getImage())) {
084: ASTPrimaryExpression parent = (ASTPrimaryExpression) node
085: .jjtGetParent();
086: ASTPrimarySuffix suffix = parent
087: .getFirstChildOfType(ASTPrimarySuffix.class);
088: if (suffix == null) {
089: return super .visit(node, data);
090: }
091: ASTPrimaryPrefix prefix = suffix
092: .getFirstChildOfType(ASTPrimaryPrefix.class);
093: if (prefix == null) {
094: return super .visit(node, data);
095: }
096:
097: if (prefix.getFirstChildOfType(ASTBooleanLiteral.class) != null) {
098: super .addViolation(data, node);
099: return data;
100: }
101: ASTLiteral literal = prefix
102: .getFirstChildOfType(ASTLiteral.class);
103: if (literal != null
104: && ("\"true\"".equals(literal.getImage()) || "\"false\""
105: .equals(literal.getImage()))) {
106: super.addViolation(data, node);
107: return data;
108: }
109: }
110: }
111: return super.visit(node, data);
112: }
113: }
|