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