1
2
3
4 package net.sourceforge.pmd.lang.plsql.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.plsql.ast.ASTCompoundTriggerBlock;
17 import net.sourceforge.pmd.lang.plsql.ast.ASTFormalParameter;
18 import net.sourceforge.pmd.lang.plsql.ast.ASTMethodDeclaration;
19 import net.sourceforge.pmd.lang.plsql.ast.ASTPackageBody;
20 import net.sourceforge.pmd.lang.plsql.ast.ASTProgramUnit;
21 import net.sourceforge.pmd.lang.plsql.ast.ASTTriggerTimingPointSection;
22 import net.sourceforge.pmd.lang.plsql.ast.ASTTriggerUnit;
23 import net.sourceforge.pmd.lang.plsql.ast.ASTTypeMethod;
24 import net.sourceforge.pmd.lang.plsql.ast.ASTVariableOrConstantInitializer;
25 import net.sourceforge.pmd.lang.plsql.ast.PLSQLNode;
26 import net.sourceforge.pmd.lang.plsql.ast.PLSQLParserVisitorAdapter;
27 import net.sourceforge.pmd.lang.plsql.symboltable.PLSQLNameOccurrence;
28 import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
29 import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
30
31
32
33
34
35
36
37 public class VariableAccessVisitor extends PLSQLParserVisitorAdapter {
38
39 public void compute(ASTMethodDeclaration node) {
40
41 if (node.jjtGetParent() instanceof ASTPackageBody) {
42 this.computeNow(node);
43 }
44 }
45
46 public void compute(ASTProgramUnit node) {
47 if (node.jjtGetParent() instanceof ASTPackageBody
48 || node.jjtGetParent() instanceof ASTCompoundTriggerBlock
49 ) {
50 this.computeNow(node);
51 }
52 }
53
54 public void compute(ASTTypeMethod node) {
55 if (node.jjtGetParent() instanceof ASTPackageBody) {
56 this.computeNow(node);
57 }
58 }
59
60 public void compute(ASTTriggerUnit node) {
61 this.computeNow(node);
62 }
63
64 public void compute(ASTTriggerTimingPointSection node) {
65 this.computeNow(node);
66 }
67
68
69
70
71
72 private void computeNow(Node node) {
73 DataFlowNode inode = node.getDataFlowNode();
74
75 List<VariableAccess> undefinitions = markUsages(inode);
76
77
78 DataFlowNode firstINode = inode.getFlow().get(0);
79 firstINode.setVariableAccess(undefinitions);
80
81
82 DataFlowNode lastINode = inode.getFlow().get(inode.getFlow().size() - 1);
83 lastINode.setVariableAccess(undefinitions);
84 }
85
86 private List<VariableAccess> markUsages(DataFlowNode inode) {
87
88 List<VariableAccess> undefinitions = new ArrayList<VariableAccess>();
89 Set<Map<NameDeclaration, List<NameOccurrence>>> variableDeclarations = collectDeclarations(inode);
90 for (Map<NameDeclaration, List<NameOccurrence>> declarations : variableDeclarations) {
91 for (Map.Entry<NameDeclaration, List<NameOccurrence>> entry : declarations.entrySet()) {
92 NameDeclaration vnd = entry.getKey();
93
94 if (vnd.getNode().jjtGetParent() instanceof ASTFormalParameter) {
95
96 continue;
97 } else if ( vnd.getNode().jjtGetParent().getFirstDescendantOfType(ASTVariableOrConstantInitializer.class) != null) {
98
99 addVariableAccess(vnd.getNode(), new VariableAccess(VariableAccess.DEFINITION, vnd.getImage()),
100 inode.getFlow());
101 }
102 undefinitions.add(new VariableAccess(VariableAccess.UNDEFINITION, vnd.getImage()));
103
104 for (NameOccurrence occurrence : entry.getValue()) {
105 addAccess(occurrence, inode);
106 }
107 }
108 }
109 return undefinitions;
110 }
111
112 private Set<Map<NameDeclaration, List<NameOccurrence>>> collectDeclarations(DataFlowNode inode) {
113 Set<Map<NameDeclaration, List<NameOccurrence>>> decls = new HashSet<Map<NameDeclaration, List<NameOccurrence>>>();
114 Map<NameDeclaration, List<NameOccurrence>> varDecls;
115 for (int i = 0; i < inode.getFlow().size(); i++) {
116 DataFlowNode n = inode.getFlow().get(i);
117 if (n instanceof StartOrEndDataFlowNode) {
118 continue;
119 }
120 varDecls = ((PLSQLNode)n.getNode()).getScope().getDeclarations();
121 if (!decls.contains(varDecls)) {
122 decls.add(varDecls);
123 }
124 }
125 return decls;
126 }
127
128 private void addAccess(NameOccurrence occ, DataFlowNode inode) {
129 PLSQLNameOccurrence occurrence = (PLSQLNameOccurrence)occ;
130 if (occurrence.isOnLeftHandSide()) {
131 this.addVariableAccess(occurrence.getLocation(), new VariableAccess(VariableAccess.DEFINITION, occurrence
132 .getImage()), inode.getFlow());
133 } else if (occurrence.isOnRightHandSide() || !occurrence.isOnLeftHandSide() && !occurrence.isOnRightHandSide()) {
134 this.addVariableAccess(occurrence.getLocation(), new VariableAccess(VariableAccess.REFERENCING, occurrence
135 .getImage()), inode.getFlow());
136 }
137 }
138
139
140
141
142
143
144
145 private void addVariableAccess(Node node, VariableAccess va, List<DataFlowNode> flow) {
146
147 for (int i = flow.size() - 1; i > 0; i--) {
148 DataFlowNode inode = flow.get(i);
149 if (inode.getNode() == null) {
150 continue;
151 }
152
153 List<? extends Node> children = inode.getNode().findDescendantsOfType(node.getClass());
154 for (Node n : children) {
155 if (node.equals(n)) {
156 List<VariableAccess> v = new ArrayList<VariableAccess>();
157 v.add(va);
158 inode.setVariableAccess(v);
159 return;
160 }
161 }
162 }
163 }
164
165 }