View Javadoc

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