1 package net.sourceforge.pmd.rules.design;
2
3 import java.util.List;
4 import java.util.Map;
5
6 import net.sourceforge.pmd.AbstractRule;
7 import net.sourceforge.pmd.ast.ASTExpression;
8 import net.sourceforge.pmd.ast.ASTMethodDeclaration;
9 import net.sourceforge.pmd.ast.ASTName;
10 import net.sourceforge.pmd.ast.ASTPrimaryExpression;
11 import net.sourceforge.pmd.ast.ASTPrimarySuffix;
12 import net.sourceforge.pmd.ast.ASTReturnStatement;
13 import net.sourceforge.pmd.symboltable.NameOccurrence;
14 import net.sourceforge.pmd.symboltable.VariableNameDeclaration;
15
16 public class UnnecessaryLocalBeforeReturn extends AbstractRule {
17
18 public Object visit(ASTMethodDeclaration meth, Object data) {
19
20 if (meth.isVoid() || meth.isAbstract() || meth.isNative()) {
21 return data;
22 }
23 return super.visit(meth, data);
24 }
25
26 public Object visit(ASTReturnStatement rtn, Object data) {
27
28 ASTName name = rtn.getFirstChildOfType(ASTName.class);
29 if (name == null) {
30 return data;
31 }
32
33
34 if (rtn.findChildrenOfType(ASTExpression.class).size() > 1 || rtn.findChildrenOfType(ASTPrimaryExpression.class).size() > 1 || isMethodCall(rtn)) {
35 return data;
36 }
37
38 Map<VariableNameDeclaration, List<NameOccurrence>> vars = name.getScope().getVariableDeclarations();
39 for (Map.Entry<VariableNameDeclaration, List<NameOccurrence>> entry: vars.entrySet()) {
40 VariableNameDeclaration key = entry.getKey();
41 List<NameOccurrence> usages = entry.getValue();
42 for (NameOccurrence occ: usages) {
43 if (occ.getLocation().equals(name)) {
44
45 if (key.getNode().getBeginLine() == name.getBeginLine() - 1) {
46 String var = name.getImage();
47 if (var.indexOf('.') != -1) {
48 var = var.substring(0, var.indexOf('.'));
49 }
50 addViolation(data, rtn, var);
51 }
52 }
53 }
54 }
55 return data;
56 }
57
58 /**
59 * Determine if the given return statement has any embedded method calls.
60 *
61 * @param rtn
62 * return statement to analyze
63 * @return true if any method calls are made within the given return
64 */
65 private boolean isMethodCall(ASTReturnStatement rtn) {
66 List<ASTPrimarySuffix> suffix = rtn.findChildrenOfType( ASTPrimarySuffix.class );
67 for ( ASTPrimarySuffix element: suffix ) {
68 if ( element.isArguments() ) {
69 return true;
70 }
71 }
72 return false;
73 }
74 }