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 }