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
96
97 @Override
98 public String dysfunctionReason() {
99 return checksNothing() ?
100 "All loop types are ignored" :
101 null;
102 }
103 }