View Javadoc

    1   /*
    2    * Created on 14.07.2004
    3    */
    4   package net.sourceforge.pmd.dfa.variableaccess;
    5
    6   import net.sourceforge.pmd.ast.ASTClassOrInterfaceBodyDeclaration;
    7   import net.sourceforge.pmd.ast.ASTConstructorDeclaration;
    8   import net.sourceforge.pmd.ast.ASTFormalParameter;
    9   import net.sourceforge.pmd.ast.ASTFormalParameters;
    10  import net.sourceforge.pmd.ast.ASTMethodDeclaration;
    11  import net.sourceforge.pmd.ast.ASTVariableInitializer;
    12  import net.sourceforge.pmd.ast.JavaParserVisitorAdapter;
    13  import net.sourceforge.pmd.ast.SimpleNode;
    14  import net.sourceforge.pmd.dfa.IDataFlowNode;
    15  import net.sourceforge.pmd.dfa.StartOrEndDataFlowNode;
    16  import net.sourceforge.pmd.symboltable.NameOccurrence;
    17  import net.sourceforge.pmd.symboltable.VariableNameDeclaration;
    18
    19  import java.util.ArrayList;
    20  import java.util.HashSet;
    21  import java.util.Iterator;
    22  import java.util.List;
    23  import java.util.Map;
    24  import java.util.Set;
    25
    26  /***
    27   * @author raik, Sven Jacob
    28   *         <p/>
    29   *         Searches for special nodes and computes based on the sequence, the type of
    30   *         access of a variable.
    31   */
    32  public class VariableAccessVisitor extends JavaParserVisitorAdapter {
    33
    34      public void compute(ASTMethodDeclaration node) {
    35          if (node.jjtGetParent() instanceof ASTClassOrInterfaceBodyDeclaration) {
    36              this.computeNow(node);
    37          }
    38      }
    39
    40      public void compute(ASTConstructorDeclaration node) {
    41          this.computeNow(node);
    42      }
    43
    44      private void computeNow(SimpleNode node) {
    45          IDataFlowNode inode = node.getDataFlowNode();
    46
    47          List undefinitions = markUsages(inode);
    48
    49          // all variables are first in state undefinition
    50          IDataFlowNode firstINode = (IDataFlowNode) inode.getFlow().get(0);
    51          firstINode.setVariableAccess(undefinitions);
    52
    53          // all variables are getting undefined when leaving scope
    54          IDataFlowNode lastINode = (IDataFlowNode) inode.getFlow().get(inode.getFlow().size() - 1);
    55          lastINode.setVariableAccess(undefinitions);
    56      }
    57
    58      private List markUsages(IDataFlowNode inode) {
    59          // undefinitions was once a field... seems like it works fine as a local
    60          List undefinitions = new ArrayList();
    61          Set variableDeclarations = collectDeclarations(inode);
    62          for (Iterator i = variableDeclarations.iterator(); i.hasNext();) {
    63              Map declarations = (Map) i.next();
    64              for (Iterator j = declarations.entrySet().iterator(); j.hasNext();) {
    65  				Map.Entry entry = (Map.Entry) j.next();
    66                  VariableNameDeclaration vnd = (VariableNameDeclaration) entry.getKey();
    67
    68                  if (vnd.getAccessNodeParent() instanceof ASTFormalParameter) {
    69                      // add definition for parameters
    70                      addVariableAccess(
    71                              (SimpleNode)vnd.getNode().getFirstParentOfType(ASTFormalParameters.class),
    72                              new VariableAccess(VariableAccess.DEFINITION, vnd.getImage()),
    73                              inode.getFlow());
    74                  } else if (vnd.getAccessNodeParent().getFirstChildOfType(ASTVariableInitializer.class) != null) {
    75                      // add definition for initialized variables
    76                      addVariableAccess(
    77                              vnd.getNode(),
    78                              new VariableAccess(VariableAccess.DEFINITION, vnd.getImage()),
    79                              inode.getFlow());
    80                  }
    81                  undefinitions.add(new VariableAccess(VariableAccess.UNDEFINITION, vnd.getImage()));
    82
    83                  for (Iterator k = ((List) entry.getValue()).iterator(); k.hasNext();) {
    84                      addAccess(k, inode);
    85                  }
    86              }
    87          }
    88          return undefinitions;
    89      }
    90
    91      private Set collectDeclarations(IDataFlowNode inode) {
    92          Set decls = new HashSet();
    93          Map varDecls;
    94          for (int i = 0; i < inode.getFlow().size(); i++) {
    95              IDataFlowNode n = (IDataFlowNode) inode.getFlow().get(i);
    96              if (n instanceof StartOrEndDataFlowNode) {
    97                  continue;
    98              }
    99              varDecls = n.getSimpleNode().getScope().getVariableDeclarations();
    100             if (!decls.contains(varDecls)) {
    101                 decls.add(varDecls);
    102             }
    103         }
    104         return decls;
    105     }
    106
    107     private void addAccess(Iterator k, IDataFlowNode inode) {
    108         NameOccurrence occurrence = (NameOccurrence) k.next();
    109         if (occurrence.isOnLeftHandSide()) {
    110             this.addVariableAccess(occurrence.getLocation(), new VariableAccess(VariableAccess.DEFINITION, occurrence.getImage()), inode.getFlow());
    111         } else if (occurrence.isOnRightHandSide() || (!occurrence.isOnLeftHandSide() && !occurrence.isOnRightHandSide())) {
    112             this.addVariableAccess(occurrence.getLocation(), new VariableAccess(VariableAccess.REFERENCING, occurrence.getImage()), inode.getFlow());
    113         }
    114     }
    115
    116     /***
    117      * Adds a VariableAccess to a dataflow node.
    118      * @param node location of the access of a variable
    119      * @param va variable access to add
    120      * @param flow dataflownodes that can contain the node.
    121      */
    122     private void addVariableAccess(SimpleNode node, VariableAccess va, List flow) {
    123         // backwards to find the right inode (not a method declaration)
    124         for (int i = flow.size()-1; i > 0; i--) {
    125             IDataFlowNode inode = (IDataFlowNode) flow.get(i);
    126             if (inode.getSimpleNode() == null) {
    127                 continue;
    128             }
    129
    130             List children = inode.getSimpleNode().findChildrenOfType(node.getClass());
    131             Iterator childrenIterator = children.iterator();
    132             while (childrenIterator.hasNext()) {
    133                 if (node.equals(childrenIterator.next())) {
    134                     List v = new ArrayList();
    135                     v.add(va);
    136                     inode.setVariableAccess(v);
    137                     return;
    138                 }
    139             }
    140         }
    141     }
    142
    143 }