View Javadoc
1   /*
2    * Copyright (c) 2011-2024 Qulice.com
3    *
4    * All rights reserved.
5    *
6    * Redistribution and use in source and binary forms, with or without
7    * modification, are permitted provided that the following conditions
8    * are met: 1) Redistributions of source code must retain the above
9    * copyright notice, this list of conditions and the following
10   * disclaimer. 2) Redistributions in binary form must reproduce the above
11   * copyright notice, this list of conditions and the following
12   * disclaimer in the documentation and/or other materials provided
13   * with the distribution. 3) Neither the name of the Qulice.com nor
14   * the names of its contributors may be used to endorse or promote
15   * products derived from this software without specific prior written
16   * permission.
17   *
18   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
20   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22   * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29   * OF THE POSSIBILITY OF SUCH DAMAGE.
30   */
31  package com.qulice.pmd.rules;
32  
33  import java.util.List;
34  import java.util.Map;
35  import net.sourceforge.pmd.lang.java.ast.ASTArgumentList;
36  import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
37  import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement;
38  import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
39  import net.sourceforge.pmd.lang.java.ast.JavaNode;
40  import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
41  import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
42  import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
43  
44  /**
45   * Rule to check unnecessary local variables.
46   *
47   * @since 0.4
48   */
49  public final class UnnecessaryLocalRule extends AbstractJavaRule {
50      @Override
51      public Object visit(final ASTMethodDeclaration meth, final Object data) {
52          Object ndata = data;
53          if (!meth.isAbstract() && !meth.isNative()) {
54              ndata = super.visit(meth, data);
55          }
56          return ndata;
57      }
58  
59      @Override
60      public Object visit(final ASTReturnStatement rtn, final Object data) {
61          final ASTVariableDeclarator name =
62              rtn.getFirstChildOfType(ASTVariableDeclarator.class);
63          if (name != null) {
64              this.usages(rtn, data, name);
65          }
66          return data;
67      }
68  
69      @Override
70      public Object visit(final ASTArgumentList rtn, final Object data) {
71          final List<ASTVariableDeclarator> names =
72              rtn.findChildrenOfType(ASTVariableDeclarator.class);
73          for (final ASTVariableDeclarator name : names) {
74              this.usages(rtn, data, name);
75          }
76          return data;
77      }
78  
79      /**
80       * Report when number of variable usages is equal to zero.
81       * @param node Node to check.
82       * @param data Context.
83       * @param name Variable name.
84       */
85      private void usages(final JavaNode node, final Object data,
86          final ASTVariableDeclarator name) {
87          final Map<NameDeclaration, List<NameOccurrence>> vars = name
88              .getScope().getDeclarations();
89          for (final Map.Entry<NameDeclaration, List<NameOccurrence>> entry
90              : vars.entrySet()) {
91              final List<NameOccurrence> usages = entry.getValue();
92              if (usages.size() > 1) {
93                  continue;
94              }
95              for (final NameOccurrence occ: usages) {
96                  if (occ.getLocation().equals(name)) {
97                      this.asCtx(data).addViolation(
98                          node, name.getImage()
99                      );
100                 }
101             }
102         }
103     }
104 }