1 |
| |
2 |
| |
3 |
| |
4 |
| package net.sourceforge.pmd.dfa; |
5 |
| |
6 |
| import java.util.List; |
7 |
| |
8 |
| import net.sourceforge.pmd.ast.ASTLabeledStatement; |
9 |
| import net.sourceforge.pmd.ast.SimpleNode; |
10 |
| |
11 |
| |
12 |
| |
13 |
| |
14 |
| |
15 |
| public class Linker { |
16 |
| |
17 |
| private List braceStack; |
18 |
| private List continueBreakReturnStack; |
19 |
| |
20 |
45
| public Linker(List braceStack, List continueBreakReturnStack) {
|
21 |
45
| this.braceStack = braceStack;
|
22 |
45
| this.continueBreakReturnStack = continueBreakReturnStack;
|
23 |
| } |
24 |
| |
25 |
| |
26 |
| |
27 |
| |
28 |
45
| public void computePaths() throws LinkerException, SequenceException {
|
29 |
| |
30 |
| |
31 |
45
| SequenceChecker sc = new SequenceChecker(braceStack);
|
32 |
45
| while (!sc.run()) {
|
33 |
63
| if (sc.getFirstIndex() < 0 || sc.getLastIndex() < 0) {
|
34 |
0
| throw new SequenceException("computePaths(): return index < 0");
|
35 |
| } |
36 |
| |
37 |
63
| StackObject firstStackObject = (StackObject) braceStack.get(sc.getFirstIndex());
|
38 |
| |
39 |
63
| switch (firstStackObject.getType()) {
|
40 |
27
| case NodeType.IF_EXPR:
|
41 |
27
| int x = sc.getLastIndex() - sc.getFirstIndex();
|
42 |
27
| if (x == 2) {
|
43 |
11
| this.computeIf(sc.getFirstIndex(), sc.getFirstIndex() + 1, sc.getLastIndex());
|
44 |
16
| } else if (x == 1) {
|
45 |
16
| this.computeIf(sc.getFirstIndex(), sc.getLastIndex());
|
46 |
| } else { |
47 |
0
| System.out.println("Error - computePaths 1");
|
48 |
| } |
49 |
27
| break;
|
50 |
| |
51 |
3
| case NodeType.WHILE_EXPR:
|
52 |
3
| this.computeWhile(sc.getFirstIndex(), sc.getLastIndex());
|
53 |
3
| break;
|
54 |
| |
55 |
3
| case NodeType.SWITCH_START:
|
56 |
3
| this.computeSwitch(sc.getFirstIndex(), sc.getLastIndex());
|
57 |
3
| break;
|
58 |
| |
59 |
21
| case NodeType.FOR_INIT:
|
60 |
5
| case NodeType.FOR_EXPR:
|
61 |
0
| case NodeType.FOR_UPDATE:
|
62 |
0
| case NodeType.FOR_BEFORE_FIRST_STATEMENT:
|
63 |
26
| this.computeFor(sc.getFirstIndex(), sc.getLastIndex());
|
64 |
26
| break;
|
65 |
| |
66 |
3
| case NodeType.DO_BEFORE_FIRST_STATEMENT:
|
67 |
3
| this.computeDo(sc.getFirstIndex(), sc.getLastIndex());
|
68 |
3
| break;
|
69 |
| |
70 |
1
| default:
|
71 |
| } |
72 |
| |
73 |
63
| for (int y = sc.getLastIndex(); y >= sc.getFirstIndex(); y--) {
|
74 |
210
| braceStack.remove(y);
|
75 |
| } |
76 |
| } |
77 |
| |
78 |
45
| while (!continueBreakReturnStack.isEmpty()) {
|
79 |
6
| StackObject stackObject = (StackObject) continueBreakReturnStack.get(0);
|
80 |
6
| IDataFlowNode node = stackObject.getDataFlowNode();
|
81 |
| |
82 |
6
| switch (stackObject.getType()) {
|
83 |
0
| case NodeType.RETURN_STATEMENT:
|
84 |
| |
85 |
0
| node.removePathToChild((IDataFlowNode) node.getChildren().get(0));
|
86 |
0
| IDataFlowNode lastNode = (IDataFlowNode) node.getFlow().get(node.getFlow().size() - 1);
|
87 |
0
| node.addPathToChild(lastNode);
|
88 |
0
| continueBreakReturnStack.remove(0);
|
89 |
0
| break;
|
90 |
5
| case NodeType.BREAK_STATEMENT:
|
91 |
5
| IDataFlowNode last = getNodeToBreakStatement(node);
|
92 |
5
| node.removePathToChild((IDataFlowNode) node.getChildren().get(0));
|
93 |
5
| node.addPathToChild(last);
|
94 |
5
| continueBreakReturnStack.remove(0);
|
95 |
5
| break;
|
96 |
| |
97 |
1
| case NodeType.CONTINUE_STATEMENT:
|
98 |
| |
99 |
| |
100 |
| |
101 |
| |
102 |
| |
103 |
| |
104 |
| |
105 |
| |
106 |
| |
107 |
| |
108 |
| |
109 |
| |
110 |
| |
111 |
| |
112 |
| |
113 |
| |
114 |
| |
115 |
| |
116 |
| |
117 |
| |
118 |
| |
119 |
| |
120 |
| |
121 |
| |
122 |
| |
123 |
| |
124 |
| |
125 |
| |
126 |
| |
127 |
| |
128 |
| |
129 |
| |
130 |
| |
131 |
| |
132 |
| |
133 |
| |
134 |
| |
135 |
| |
136 |
| |
137 |
| |
138 |
| |
139 |
| |
140 |
| |
141 |
| |
142 |
| |
143 |
| |
144 |
| |
145 |
| |
146 |
| |
147 |
| |
148 |
| |
149 |
| |
150 |
| |
151 |
| |
152 |
| |
153 |
| |
154 |
| |
155 |
| |
156 |
| |
157 |
| |
158 |
| |
159 |
1
| continueBreakReturnStack.remove(0);
|
160 |
| } |
161 |
| } |
162 |
| } |
163 |
| |
164 |
5
| private IDataFlowNode getNodeToBreakStatement(IDataFlowNode node) {
|
165 |
| |
166 |
5
| List bList = node.getFlow();
|
167 |
5
| int findEnds = 1;
|
168 |
| |
169 |
| |
170 |
| |
171 |
5
| int index = bList.indexOf(node);
|
172 |
5
| for (; index < bList.size()-2; index++) {
|
173 |
4
| IDataFlowNode n = (IDataFlowNode) bList.get(index);
|
174 |
4
| if (n.isType(NodeType.DO_EXPR) ||
|
175 |
| n.isType(NodeType.FOR_INIT) || |
176 |
| n.isType(NodeType.WHILE_EXPR) || |
177 |
| n.isType(NodeType.SWITCH_START)) { |
178 |
0
| findEnds++;
|
179 |
| } |
180 |
4
| if (n.isType(NodeType.WHILE_LAST_STATEMENT) ||
|
181 |
| n.isType(NodeType.SWITCH_END) || |
182 |
| n.isType(NodeType.FOR_END) || |
183 |
| n.isType(NodeType.DO_EXPR)) { |
184 |
1
| if (findEnds > 1) {
|
185 |
| |
186 |
0
| findEnds--;
|
187 |
| } else { |
188 |
1
| break;
|
189 |
| } |
190 |
| } |
191 |
| |
192 |
3
| if (n.isType(NodeType.LABEL_LAST_STATEMENT)) {
|
193 |
0
| SimpleNode parentNode = (SimpleNode) n.getSimpleNode().getFirstParentOfType(ASTLabeledStatement.class);
|
194 |
0
| if (parentNode == null) {
|
195 |
0
| break;
|
196 |
| } else { |
197 |
0
| String label = node.getSimpleNode().getImage();
|
198 |
0
| if (label == null || label.equals(parentNode.getImage())) {
|
199 |
0
| node.removePathToChild((IDataFlowNode) node.getChildren().get(0));
|
200 |
0
| IDataFlowNode last = (IDataFlowNode) bList.get(index + 1);
|
201 |
0
| node.addPathToChild(last);
|
202 |
0
| break;
|
203 |
| } |
204 |
| } |
205 |
| } |
206 |
| } |
207 |
5
| return (IDataFlowNode)node.getFlow().get(index+1);
|
208 |
| } |
209 |
| |
210 |
3
| private void computeDo(int first, int last) {
|
211 |
3
| IDataFlowNode doSt = ((StackObject) this.braceStack.get(first)).getDataFlowNode();
|
212 |
3
| IDataFlowNode doExpr = ((StackObject) this.braceStack.get(last)).getDataFlowNode();
|
213 |
3
| IDataFlowNode doFirst = (IDataFlowNode) doSt.getFlow().get(doSt.getIndex() + 1);
|
214 |
3
| if (doFirst.getIndex() != doExpr.getIndex()) {
|
215 |
3
| doExpr.addPathToChild(doFirst);
|
216 |
| } |
217 |
| } |
218 |
| |
219 |
26
| private void computeFor(int firstIndex, int lastIndex) {
|
220 |
26
| IDataFlowNode fExpr = null;
|
221 |
26
| IDataFlowNode fUpdate = null;
|
222 |
26
| IDataFlowNode fSt = null;
|
223 |
26
| IDataFlowNode fEnd = null;
|
224 |
26
| boolean isUpdate = false;
|
225 |
| |
226 |
26
| for (int i = firstIndex; i <= lastIndex; i++) {
|
227 |
120
| StackObject so = (StackObject) this.braceStack.get(i);
|
228 |
120
| IDataFlowNode node = so.getDataFlowNode();
|
229 |
| |
230 |
120
| if (so.getType() == NodeType.FOR_EXPR) {
|
231 |
26
| fExpr = node;
|
232 |
94
| } else if (so.getType() == NodeType.FOR_UPDATE) {
|
233 |
21
| fUpdate = node;
|
234 |
21
| isUpdate = true;
|
235 |
73
| } else if (so.getType() == NodeType.FOR_BEFORE_FIRST_STATEMENT) {
|
236 |
26
| fSt = node;
|
237 |
47
| } else if (so.getType() == NodeType.FOR_END) {
|
238 |
26
| fEnd = node;
|
239 |
| } |
240 |
| } |
241 |
26
| IDataFlowNode end = (IDataFlowNode) fEnd.getFlow().get(fEnd.getIndex() + 1);
|
242 |
| |
243 |
26
| IDataFlowNode firstSt = (IDataFlowNode) fSt.getChildren().get(0);
|
244 |
| |
245 |
26
| if (isUpdate) {
|
246 |
21
| if (fSt.getIndex() != fEnd.getIndex()) {
|
247 |
14
| end.reverseParentPathsTo(fUpdate);
|
248 |
14
| fExpr.removePathToChild(fUpdate);
|
249 |
14
| fUpdate.addPathToChild(fExpr);
|
250 |
14
| fUpdate.removePathToChild(firstSt);
|
251 |
14
| fExpr.addPathToChild(firstSt);
|
252 |
14
| fExpr.addPathToChild(end);
|
253 |
| } else { |
254 |
7
| fSt.removePathToChild(end);
|
255 |
7
| fExpr.removePathToChild(fUpdate);
|
256 |
7
| fUpdate.addPathToChild(fExpr);
|
257 |
7
| fExpr.addPathToChild(fUpdate);
|
258 |
7
| fExpr.addPathToChild(end);
|
259 |
| } |
260 |
| } else { |
261 |
5
| if (fSt.getIndex() != fEnd.getIndex()) {
|
262 |
1
| end.reverseParentPathsTo(fExpr);
|
263 |
1
| fExpr.addPathToChild(end);
|
264 |
| } |
265 |
| } |
266 |
| } |
267 |
| |
268 |
3
| private void computeSwitch(int firstIndex, int lastIndex) {
|
269 |
| |
270 |
3
| int diff = lastIndex - firstIndex;
|
271 |
3
| boolean defaultStatement = false;
|
272 |
| |
273 |
3
| IDataFlowNode sStart = ((StackObject) this.braceStack.get(firstIndex)).getDataFlowNode();
|
274 |
3
| IDataFlowNode sEnd = ((StackObject) this.braceStack.get(lastIndex)).getDataFlowNode();
|
275 |
3
| IDataFlowNode end = (IDataFlowNode) sEnd.getChildren().get(0);
|
276 |
| |
277 |
3
| for (int i = 0; i < diff - 2; i++) {
|
278 |
2
| StackObject so = (StackObject) this.braceStack.get(firstIndex + 2 + i);
|
279 |
2
| IDataFlowNode node = so.getDataFlowNode();
|
280 |
| |
281 |
2
| sStart.addPathToChild((IDataFlowNode) node.getChildren().get(0));
|
282 |
| |
283 |
2
| if (so.getType() == NodeType.SWITCH_LAST_DEFAULT_STATEMENT)
|
284 |
1
| defaultStatement = true;
|
285 |
| } |
286 |
| |
287 |
3
| if (!defaultStatement)
|
288 |
2
| sStart.addPathToChild(end);
|
289 |
| } |
290 |
| |
291 |
3
| private void computeWhile(int first, int last) {
|
292 |
3
| IDataFlowNode wStart = ((StackObject) this.braceStack.get(first)).getDataFlowNode();
|
293 |
3
| IDataFlowNode wEnd = ((StackObject) this.braceStack.get(last)).getDataFlowNode();
|
294 |
| |
295 |
3
| IDataFlowNode end = (IDataFlowNode) wEnd.getFlow().get(wEnd.getIndex() + 1);
|
296 |
| |
297 |
3
| if (wStart.getIndex() != wEnd.getIndex()) {
|
298 |
2
| end.reverseParentPathsTo(wStart);
|
299 |
2
| wStart.addPathToChild(end);
|
300 |
| } |
301 |
| } |
302 |
| |
303 |
11
| private void computeIf(int first, int second, int last) {
|
304 |
11
| IDataFlowNode ifStart = ((StackObject) this.braceStack.get(first)).getDataFlowNode();
|
305 |
11
| IDataFlowNode ifEnd = ((StackObject) this.braceStack.get(second)).getDataFlowNode();
|
306 |
11
| IDataFlowNode elseEnd = ((StackObject) this.braceStack.get(last)).getDataFlowNode();
|
307 |
| |
308 |
11
| IDataFlowNode elseStart = (IDataFlowNode) ifEnd.getFlow().get(ifEnd.getIndex() + 1);
|
309 |
11
| IDataFlowNode end = (IDataFlowNode) elseEnd.getFlow().get(elseEnd.getIndex() + 1);
|
310 |
| |
311 |
| |
312 |
11
| if (ifStart.getIndex() != ifEnd.getIndex() &&
|
313 |
| ifEnd.getIndex() != elseEnd.getIndex()) { |
314 |
11
| elseStart.reverseParentPathsTo(end);
|
315 |
11
| ifStart.addPathToChild(elseStart);
|
316 |
| } |
317 |
| |
318 |
0
| else if (ifStart.getIndex() == ifEnd.getIndex() &&
|
319 |
| ifEnd.getIndex() != elseEnd.getIndex()) { |
320 |
0
| ifStart.addPathToChild(end);
|
321 |
| } |
322 |
| |
323 |
0
| else if (ifEnd.getIndex() == elseEnd.getIndex() &&
|
324 |
| ifStart.getIndex() != ifEnd.getIndex()) { |
325 |
0
| ifStart.addPathToChild(end);
|
326 |
| } |
327 |
| } |
328 |
| |
329 |
16
| private void computeIf(int first, int last) {
|
330 |
16
| IDataFlowNode ifStart = ((StackObject) this.braceStack.get(first)).getDataFlowNode();
|
331 |
16
| IDataFlowNode ifEnd = ((StackObject) this.braceStack.get(last)).getDataFlowNode();
|
332 |
| |
333 |
| |
334 |
16
| if (ifStart.getIndex() != ifEnd.getIndex()) {
|
335 |
13
| IDataFlowNode end = (IDataFlowNode) ifEnd.getFlow().get(ifEnd.getIndex() + 1);
|
336 |
13
| ifStart.addPathToChild(end);
|
337 |
| } |
338 |
| } |
339 |
| } |