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
22 public final class UnnecessaryLocalRule extends AbstractJavaRulechainRule {
23
24
25
26
27 public UnnecessaryLocalRule() {
28 super(ASTVariableDeclarator.class);
29 }
30
31 @Override
32 public Object visit(
33 final ASTVariableDeclarator variable,
34 final Object data
35 ) {
36 if (variable.getInitializer() != null
37 && variable.ancestors(ASTResource.class).first() == null) {
38 final String name = UnnecessaryLocalRule.variableName(variable);
39 if (!name.isEmpty()) {
40 this.asCtx(data).addViolation(variable, name);
41 }
42 }
43 return data;
44 }
45
46 private static boolean hasReturnOrArguments(
47 final List<ASTVariableAccess> uses
48 ) {
49 boolean result = false;
50 if (uses.size() == 1) {
51 final ASTVariableAccess use = uses.get(0);
52 final boolean loop = use.ancestors(ASTLoopStatement.class)
53 .toStream().findAny().isPresent();
54 if (!loop
55 && (use.ancestors(ASTReturnStatement.class).toStream()
56 .findAny().isPresent()
57 || use.ancestors(ASTArgumentList.class).toStream()
58 .findAny().isPresent())
59 ) {
60 result = true;
61 }
62 }
63 return result;
64 }
65
66 private static String variableName(final ASTVariableDeclarator variable) {
67 String result = "";
68 final ASTBlock block = variable.ancestors(ASTBlock.class).first();
69 if (block != null
70 && !UnnecessaryLocalSkips.freshState(variable.getInitializer())) {
71 final String name = variable.getName();
72 final List<ASTVariableAccess> uses = block
73 .descendants(ASTVariableAccess.class)
74 .crossFindBoundaries()
75 .filter(ref -> name.equals(ref.getName()))
76 .toList();
77 if (UnnecessaryLocalRule.hasReturnOrArguments(uses)
78 && !UnnecessaryLocalSkips.acrossBoundary(block, name, uses.size())
79 && !UnnecessaryLocalSkips.interveningCall(variable, uses.get(0))) {
80 result = name;
81 }
82 }
83 return result;
84 }
85 }