1
2
3
4 package net.sourceforge.pmd.lang.java.dfa;
5
6 import java.util.ArrayList;
7 import java.util.HashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11
12 import net.sourceforge.pmd.lang.ast.Node;
13 import net.sourceforge.pmd.lang.dfa.DataFlowNode;
14 import net.sourceforge.pmd.lang.dfa.StartOrEndDataFlowNode;
15 import net.sourceforge.pmd.lang.dfa.VariableAccess;
16 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration;
17 import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
18 import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
19 import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
20 import net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer;
21 import net.sourceforge.pmd.lang.java.ast.JavaNode;
22 import net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter;
23 import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence;
24 import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
25 import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
26
27
28
29
30
31
32
33 public class VariableAccessVisitor extends JavaParserVisitorAdapter {
34
35 public void compute(ASTMethodDeclaration node) {
36 if (node.jjtGetParent() instanceof ASTClassOrInterfaceBodyDeclaration) {
37 this.computeNow(node);
38 }
39 }
40
41 public void compute(ASTConstructorDeclaration node) {
42 this.computeNow(node);
43 }
44
45 private void computeNow(Node node) {
46 DataFlowNode inode = node.getDataFlowNode();
47
48 List<VariableAccess> undefinitions = markUsages(inode);
49
50
51 DataFlowNode firstINode = inode.getFlow().get(0);
52 firstINode.setVariableAccess(undefinitions);
53
54
55 DataFlowNode lastINode = inode.getFlow().get(inode.getFlow().size() - 1);
56 lastINode.setVariableAccess(undefinitions);
57 }
58
59 private List<VariableAccess> markUsages(DataFlowNode inode) {
60
61 List<VariableAccess> undefinitions = new ArrayList<VariableAccess>();
62 Set<Map<VariableNameDeclaration, List<NameOccurrence>>> variableDeclarations = collectDeclarations(inode);
63 for (Map<VariableNameDeclaration, List<NameOccurrence>> declarations : variableDeclarations) {
64 for (Map.Entry<VariableNameDeclaration, List<NameOccurrence>> entry : declarations.entrySet()) {
65 VariableNameDeclaration vnd = entry.getKey();
66
67 if (vnd.getAccessNodeParent() instanceof ASTFormalParameter) {
68
69 continue;
70 } else if (vnd.getAccessNodeParent().getFirstDescendantOfType(ASTVariableInitializer.class) != null) {
71
72 addVariableAccess(vnd.getNode(), new VariableAccess(VariableAccess.DEFINITION, vnd.getImage()),
73 inode.getFlow());
74 }
75 undefinitions.add(new VariableAccess(VariableAccess.UNDEFINITION, vnd.getImage()));
76
77 for (NameOccurrence occurrence : entry.getValue()) {
78 addAccess((JavaNameOccurrence)occurrence, inode);
79 }
80 }
81 }
82 return undefinitions;
83 }
84
85 private Set<Map<VariableNameDeclaration, List<NameOccurrence>>> collectDeclarations(DataFlowNode inode) {
86 Set<Map<VariableNameDeclaration, List<NameOccurrence>>> decls = new HashSet<Map<VariableNameDeclaration, List<NameOccurrence>>>();
87 Map<VariableNameDeclaration, List<NameOccurrence>> varDecls;
88 for (int i = 0; i < inode.getFlow().size(); i++) {
89 DataFlowNode n = inode.getFlow().get(i);
90 if (n instanceof StartOrEndDataFlowNode) {
91 continue;
92 }
93 varDecls = ((JavaNode)n.getNode()).getScope().getDeclarations(VariableNameDeclaration.class);
94 if (!decls.contains(varDecls)) {
95 decls.add(varDecls);
96 }
97 }
98 return decls;
99 }
100
101 private void addAccess(JavaNameOccurrence occurrence, DataFlowNode inode) {
102 if (occurrence.isOnLeftHandSide()) {
103 this.addVariableAccess(occurrence.getLocation(), new VariableAccess(VariableAccess.DEFINITION, occurrence
104 .getImage()), inode.getFlow());
105 } else if (occurrence.isOnRightHandSide() || !occurrence.isOnLeftHandSide() && !occurrence.isOnRightHandSide()) {
106 this.addVariableAccess(occurrence.getLocation(), new VariableAccess(VariableAccess.REFERENCING, occurrence
107 .getImage()), inode.getFlow());
108 }
109 }
110
111
112
113
114
115
116
117 private void addVariableAccess(Node node, VariableAccess va, List<DataFlowNode> flow) {
118
119 for (int i = flow.size() - 1; i > 0; i--) {
120 DataFlowNode inode = flow.get(i);
121 if (inode.getNode() == null) {
122 continue;
123 }
124
125 List<? extends Node> children = inode.getNode().findDescendantsOfType(node.getClass());
126 for (Node n : children) {
127 if (node.equals(n)) {
128 List<VariableAccess> v = new ArrayList<VariableAccess>();
129 v.add(va);
130 inode.setVariableAccess(v);
131 return;
132 }
133 }
134 }
135 }
136
137 }