View Javadoc

    1   package net.sourceforge.pmd.lang.java.rule.basic;
    2
    3   import net.sourceforge.pmd.PropertySource;
    4   import net.sourceforge.pmd.lang.ast.Node;
    5   import net.sourceforge.pmd.lang.java.ast.ASTBreakStatement;
    6   import net.sourceforge.pmd.lang.java.ast.ASTContinueStatement;
    7   import net.sourceforge.pmd.lang.java.ast.ASTDoStatement;
    8   import net.sourceforge.pmd.lang.java.ast.ASTForStatement;
    9   import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement;
    10  import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement;
    11  import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
    12  import net.sourceforge.pmd.lang.rule.properties.EnumeratedMultiProperty;
    13
    14  public class AvoidBranchingStatementAsLastInLoopRule extends AbstractJavaRule {
    15
    16      public static final String CHECK_FOR = "for";
    17      public static final String CHECK_DO = "do";
    18      public static final String CHECK_WHILE = "while";
    19
    20      private static final String[] ALL_LOOP_TYPES_LABELS = new String[] { CHECK_FOR, CHECK_DO, CHECK_WHILE };
    21      private static final String[] ALL_LOOP_TYPES_VALUES = ALL_LOOP_TYPES_LABELS;
    22      private static final int[] ALL_LOOP_TYPES_DEFAULTS = new int[] { 0, 1, 2 };
    23
    24      public static final EnumeratedMultiProperty<String> CHECK_BREAK_LOOP_TYPES = new EnumeratedMultiProperty(
    25  	    "checkBreakLoopTypes", "Check for break statements in loop types", ALL_LOOP_TYPES_LABELS,
    26  	    ALL_LOOP_TYPES_VALUES, ALL_LOOP_TYPES_DEFAULTS, 1);
    27      public static final EnumeratedMultiProperty<String> CHECK_CONTINUE_LOOP_TYPES = new EnumeratedMultiProperty(
    28  	    "checkContinueLoopTypes", "Check for continue statements in loop types", ALL_LOOP_TYPES_LABELS,
    29  	    ALL_LOOP_TYPES_VALUES, ALL_LOOP_TYPES_DEFAULTS, 2);
    30      public static final EnumeratedMultiProperty<String> CHECK_RETURN_LOOP_TYPES = new EnumeratedMultiProperty(
    31  	    "checkReturnLoopTypes", "Check for return statements in loop types", ALL_LOOP_TYPES_LABELS,
    32  	    ALL_LOOP_TYPES_VALUES, ALL_LOOP_TYPES_DEFAULTS, 3);
    33
    34      public AvoidBranchingStatementAsLastInLoopRule() {
    35  	definePropertyDescriptor(CHECK_BREAK_LOOP_TYPES);
    36  	definePropertyDescriptor(CHECK_CONTINUE_LOOP_TYPES);
    37  	definePropertyDescriptor(CHECK_RETURN_LOOP_TYPES);
    38
    39  	addRuleChainVisit(ASTBreakStatement.class);
    40  	addRuleChainVisit(ASTContinueStatement.class);
    41  	addRuleChainVisit(ASTReturnStatement.class);
    42      }
    43
    44      @Override
    45      public Object visit(ASTBreakStatement node, Object data) {
    46  	return check(CHECK_BREAK_LOOP_TYPES, node, data);
    47      }
    48
    49      @Override
    50      public Object visit(ASTContinueStatement node, Object data) {
    51  	return check(CHECK_CONTINUE_LOOP_TYPES, node, data);
    52      }
    53
    54      @Override
    55      public Object visit(ASTReturnStatement node, Object data) {
    56  	return check(CHECK_RETURN_LOOP_TYPES, node, data);
    57      }
    58
    59      protected Object check(EnumeratedMultiProperty<String> property, Node node, Object data) {
    60  	Node parent = node.getNthParent(5);
    61  	if (parent instanceof ASTForStatement) {
    62  	    if (hasPropertyValue(property, CHECK_FOR)) {
    63  		super.addViolation(data, node);
    64  	    }
    65  	} else if (parent instanceof ASTWhileStatement) {
    66  	    if (hasPropertyValue(property, CHECK_WHILE)) {
    67  		super.addViolation(data, node);
    68  	    }
    69  	} else if (parent instanceof ASTDoStatement) {
    70  	    if (hasPropertyValue(property, CHECK_DO)) {
    71  		super.addViolation(data, node);
    72  	    }
    73  	}
    74  	return data;
    75      }
    76
    77      protected boolean hasPropertyValue(EnumeratedMultiProperty<String> property, String value) {
    78  	final Object[] values = getProperty(property);
    79  	for (int i = 0; i < values.length; i++) {
    80  	    if (value.equals(values[i])) {
    81  		return true;
    82  	    }
    83  	}
    84  	return false;
    85      }
    86
    87  	public boolean checksNothing() {
    88
    89  		return getProperty(CHECK_BREAK_LOOP_TYPES).length == 0 &&
    90  			getProperty(CHECK_CONTINUE_LOOP_TYPES).length == 0 &&
    91  			getProperty(CHECK_RETURN_LOOP_TYPES).length == 0 ;
    92  	}
    93
    94  	/**
    95  	 * @see PropertySource#dysfunctionReason()
    96  	 */
    97  	@Override
    98  	public String dysfunctionReason() {
    99  		return checksNothing() ?
    100 				"All loop types are ignored" :
    101 				null;
    102 	}
    103 }