|
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 |
| } |