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