AvoidBranchingStatementAsLastInLoopRule.java
01 package net.sourceforge.pmd.lang.java.rule.basic;
02 
03 import net.sourceforge.pmd.lang.ast.Node;
04 import net.sourceforge.pmd.lang.java.ast.ASTBreakStatement;
05 import net.sourceforge.pmd.lang.java.ast.ASTContinueStatement;
06 import net.sourceforge.pmd.lang.java.ast.ASTDoStatement;
07 import net.sourceforge.pmd.lang.java.ast.ASTForStatement;
08 import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement;
09 import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement;
10 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
11 import net.sourceforge.pmd.lang.rule.properties.EnumeratedMultiProperty;
12 
13 public class AvoidBranchingStatementAsLastInLoopRule extends AbstractJavaRule {
14 
15     public static final String CHECK_FOR = "for";
16     public static final String CHECK_DO = "do";
17     public static final String CHECK_WHILE = "while";
18 
19     private static final String[] ALL_LOOP_TYPES_LABELS = new String[] { CHECK_FOR, CHECK_DO, CHECK_WHILE };
20     private static final String[] ALL_LOOP_TYPES_VALUES = ALL_LOOP_TYPES_LABELS;
21     private static final int[] ALL_LOOP_TYPES_DEFAULTS = new int[] { 01};
22 
23     public static final EnumeratedMultiProperty<String> CHECK_BREAK_LOOP_TYPES = new EnumeratedMultiProperty(
24       "checkBreakLoopTypes""Check for break statements in loop types", ALL_LOOP_TYPES_LABELS,
25       ALL_LOOP_TYPES_VALUES, ALL_LOOP_TYPES_DEFAULTS, 1);
26     public static final EnumeratedMultiProperty<String> CHECK_CONTINUE_LOOP_TYPES = new EnumeratedMultiProperty(
27       "checkContinueLoopTypes""Check for continue statements in loop types", ALL_LOOP_TYPES_LABELS,
28       ALL_LOOP_TYPES_VALUES, ALL_LOOP_TYPES_DEFAULTS, 2);
29     public static final EnumeratedMultiProperty<String> CHECK_RETURN_LOOP_TYPES = new EnumeratedMultiProperty(
30       "checkReturnLoopTypes""Check for return statements in loop types", ALL_LOOP_TYPES_LABELS,
31       ALL_LOOP_TYPES_VALUES, ALL_LOOP_TYPES_DEFAULTS, 3);
32 
33     public AvoidBranchingStatementAsLastInLoopRule() {
34   definePropertyDescriptor(CHECK_BREAK_LOOP_TYPES);
35   definePropertyDescriptor(CHECK_CONTINUE_LOOP_TYPES);
36   definePropertyDescriptor(CHECK_RETURN_LOOP_TYPES);
37 
38   addRuleChainVisit(ASTBreakStatement.class);
39   addRuleChainVisit(ASTContinueStatement.class);
40   addRuleChainVisit(ASTReturnStatement.class);
41     }
42 
43     @Override
44     public Object visit(ASTBreakStatement node, Object data) {
45   return check(CHECK_BREAK_LOOP_TYPES, node, data);
46     }
47 
48     @Override
49     public Object visit(ASTContinueStatement node, Object data) {
50   return check(CHECK_CONTINUE_LOOP_TYPES, node, data);
51     }
52 
53     @Override
54     public Object visit(ASTReturnStatement node, Object data) {
55   return check(CHECK_RETURN_LOOP_TYPES, node, data);
56     }
57 
58     protected Object check(EnumeratedMultiProperty<String> property, Node node, Object data) {
59   Node parent = node.getNthParent(5);
60   if (parent instanceof ASTForStatement) {
61       if (hasPropertyValue(property, CHECK_FOR)) {
62     super.addViolation(data, node);
63       }
64   else if (parent instanceof ASTWhileStatement) {
65       if (hasPropertyValue(property, CHECK_WHILE)) {
66     super.addViolation(data, node);
67       }
68   else if (parent instanceof ASTDoStatement) {
69       if (hasPropertyValue(property, CHECK_DO)) {
70     super.addViolation(data, node);
71       }
72   }
73   return data;
74     }
75 
76     protected boolean hasPropertyValue(EnumeratedMultiProperty<String> property, String value) {
77   final Object[] values = getProperty(property);
78   for (int i = 0; i < values.length; i++) {
79       if (value.equals(values[i])) {
80     return true;
81       }
82   }
83   return false;
84     }
85 }