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