View Javadoc
1   /*
2    * SPDX-FileCopyrightText: Copyright (c) 2011-2026 Yegor Bugayenko
3    * SPDX-License-Identifier: MIT
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.ASTReturnStatement;
12  import net.sourceforge.pmd.lang.java.ast.ASTVariableAccess;
13  import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
14  import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
15  
16  /**
17   * Rule to check unnecessary local variables.
18   * @since 0.4
19   */
20  public final class UnnecessaryLocalRule extends AbstractJavaRulechainRule {
21  
22      public UnnecessaryLocalRule() {
23          super(ASTVariableDeclarator.class);
24      }
25  
26      @Override
27      public Object visit(
28          final ASTVariableDeclarator variable,
29          final Object data
30      ) {
31          if (variable.getInitializer() != null) {
32              final String name = variableName(variable);
33              if (!name.isEmpty()) {
34                  asCtx(data).addViolation(variable, name);
35              }
36          }
37          return data;
38      }
39  
40      private static boolean hasReturnOrArguments(
41          final List<ASTVariableAccess> uses
42      ) {
43          boolean result = false;
44          if (uses.size() == 1) {
45              final ASTVariableAccess use = uses.get(0);
46              final boolean loop = use.ancestors(ASTLoopStatement.class)
47                  .toStream().findAny().isPresent();
48              if (!loop
49                  && (use.ancestors(ASTReturnStatement.class).toStream()
50                  .findAny().isPresent()
51                  || use.ancestors(ASTArgumentList.class).toStream()
52                  .findAny().isPresent())
53              ) {
54                  result = true;
55              }
56          }
57          return result;
58      }
59  
60      private static String variableName(final ASTVariableDeclarator variable) {
61          String result = "";
62          final ASTBlock block = variable.ancestors(ASTBlock.class).first();
63          if (block != null) {
64              final String name = variable.getName();
65              if (hasReturnOrArguments(
66                  block.descendants(ASTVariableAccess.class)
67                      .crossFindBoundaries()
68                      .filter(ref -> name.equals(ref.getName()))
69                      .toList()
70              )) {
71                  result = name;
72              }
73          }
74          return result;
75      }
76  }