View Javadoc
1   /*
2    * SPDX-FileCopyrightText: Copyright (c) 2011-2025 Yegor Bugayenko
3    * SPDX-License-Identifier: MIT
4    */
5   package com.qulice.pmd.rules;
6   
7   import java.util.List;
8   import java.util.Map;
9   import net.sourceforge.pmd.lang.java.ast.ASTArgumentList;
10  import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
11  import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement;
12  import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
13  import net.sourceforge.pmd.lang.java.ast.JavaNode;
14  import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
15  import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
16  import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
17  
18  /**
19   * Rule to check unnecessary local variables.
20   *
21   * @since 0.4
22   */
23  public final class UnnecessaryLocalRule extends AbstractJavaRule {
24      @Override
25      public Object visit(final ASTMethodDeclaration meth, final Object data) {
26          Object ndata = data;
27          if (!meth.isAbstract() && !meth.isNative()) {
28              ndata = super.visit(meth, data);
29          }
30          return ndata;
31      }
32  
33      @Override
34      public Object visit(final ASTReturnStatement rtn, final Object data) {
35          final ASTVariableDeclarator name =
36              rtn.getFirstChildOfType(ASTVariableDeclarator.class);
37          if (name != null) {
38              this.usages(rtn, data, name);
39          }
40          return data;
41      }
42  
43      @Override
44      public Object visit(final ASTArgumentList rtn, final Object data) {
45          final List<ASTVariableDeclarator> names =
46              rtn.findChildrenOfType(ASTVariableDeclarator.class);
47          for (final ASTVariableDeclarator name : names) {
48              this.usages(rtn, data, name);
49          }
50          return data;
51      }
52  
53      /**
54       * Report when number of variable usages is equal to zero.
55       * @param node Node to check.
56       * @param data Context.
57       * @param name Variable name.
58       */
59      private void usages(final JavaNode node, final Object data,
60          final ASTVariableDeclarator name) {
61          final Map<NameDeclaration, List<NameOccurrence>> vars = name
62              .getScope().getDeclarations();
63          for (final Map.Entry<NameDeclaration, List<NameOccurrence>> entry
64              : vars.entrySet()) {
65              final List<NameOccurrence> usages = entry.getValue();
66              if (usages.size() > 1) {
67                  continue;
68              }
69              for (final NameOccurrence occ: usages) {
70                  if (occ.getLocation().equals(name)) {
71                      this.asCtx(data).addViolation(
72                          node, name.getImage()
73                      );
74                  }
75              }
76          }
77      }
78  }