1
2
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
50 IDataFlowNode firstINode = (IDataFlowNode) inode.getFlow().get(0);
51 firstINode.setVariableAccess(undefinitions);
52
53
54 IDataFlowNode lastINode = (IDataFlowNode) inode.getFlow().get(inode.getFlow().size() - 1);
55 lastINode.setVariableAccess(undefinitions);
56 }
57
58 private List markUsages(IDataFlowNode inode) {
59
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
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
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
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 }