1
2
3
4
5 package com.qulice.pmd.rules;
6
7 import java.util.List;
8 import net.sourceforge.pmd.lang.java.ast.ASTArgumentList;
9 import net.sourceforge.pmd.lang.java.ast.ASTBlock;
10 import net.sourceforge.pmd.lang.java.ast.ASTLoopStatement;
11 import net.sourceforge.pmd.lang.java.ast.ASTResource;
12 import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement;
13 import net.sourceforge.pmd.lang.java.ast.ASTVariableAccess;
14 import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
15 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
16
17
18
19
20
21 public final class UnnecessaryLocalRule extends AbstractJavaRulechainRule {
22
23
24
25
26 public UnnecessaryLocalRule() {
27 super(ASTVariableDeclarator.class);
28 }
29
30 @Override
31 public Object visit(
32 final ASTVariableDeclarator variable,
33 final Object data
34 ) {
35 if (variable.getInitializer() != null
36 && variable.ancestors(ASTResource.class).first() == null) {
37 final String name = UnnecessaryLocalRule.variableName(variable);
38 if (!name.isEmpty()) {
39 this.asCtx(data).addViolation(variable, name);
40 }
41 }
42 return data;
43 }
44
45 private static boolean hasReturnOrArguments(
46 final List<ASTVariableAccess> uses
47 ) {
48 boolean result = false;
49 if (uses.size() == 1) {
50 final ASTVariableAccess use = uses.get(0);
51 final boolean loop = use.ancestors(ASTLoopStatement.class)
52 .toStream().findAny().isPresent();
53 if (!loop
54 && (use.ancestors(ASTReturnStatement.class).toStream()
55 .findAny().isPresent()
56 || use.ancestors(ASTArgumentList.class).toStream()
57 .findAny().isPresent())
58 ) {
59 result = true;
60 }
61 }
62 return result;
63 }
64
65 private static String variableName(final ASTVariableDeclarator variable) {
66 String result = "";
67 final ASTBlock block = variable.ancestors(ASTBlock.class).first();
68 if (block != null
69 && !UnnecessaryLocalSkips.freshState(variable.getInitializer())) {
70 final String name = variable.getName();
71 final List<ASTVariableAccess> uses = block
72 .descendants(ASTVariableAccess.class)
73 .crossFindBoundaries()
74 .filter(ref -> name.equals(ref.getName()))
75 .toList();
76 if (UnnecessaryLocalRule.hasReturnOrArguments(uses)
77 && !UnnecessaryLocalSkips.acrossBoundary(block, name, uses.size())
78 && !UnnecessaryLocalSkips.interveningCall(variable, uses.get(0))) {
79 result = name;
80 }
81 }
82 return result;
83 }
84 }