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 }