Clover coverage report - PMD - 3.9 Coverage timestamp: Tue Dec 19 2006 09:38:44 EST FRAMES NO FRAMES |
file stats: | LOC: | 339 |  | Methods: | 9
| NCLOC: | 216 |  | Classes: | 1
Source file | Conditionals | Statements | Methods | TOTAL
Linker.java | 75% | 83.3% | 100% | 81.7% |

1 |  | /*
2 |  | * Created on 12.07.2004
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 |  | * @author raik
13 |  | * Links data flow nodes to each other.
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 |  | * Creates all the links between the data flow nodes.
27 |  | */
28 | 45 | public void computePaths() throws LinkerException, SequenceException {
29 |  | // Returns true if there are more sequences, computes the first and
30 |  | // the last index of the sequence.
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 |  | // remove all children (should contain only one child)
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 |  | //List cList = node.getFlow();
99 |  | /* traverse up the tree and find the first loop start node
100 |  | */
101 |  | /*
102 |  | for(int i = cList.indexOf(node)-1;i>=0;i--) {
103 |  | IDataFlowNode n = (IDataFlowNode)cList.get(i);
104 |  |
105 |  | if(n.isType(NodeType.FOR_UPDATE) ||
106 |  | n.isType(NodeType.FOR_EXPR) ||
107 |  | n.isType(NodeType.WHILE_EXPR)) {
108 |  | */
109 |  | /*
110 |  | * while(..) {
111 |  | * while(...) {
112 |  | * ...
113 |  | * }
114 |  | * continue;
115 |  | * }
116 |  | *
117 |  | * Without this Expression he continues the second
118 |  | * WHILE loop. The continue statement and the while loop
119 |  | * have to be in different scopes.
120 |  | *
121 |  | * TODO An error occurs if "continue" is even nested in
122 |  | * scopes other than local loop scopes, like "if".
123 |  | * The result is, that the data flow isn't build right
124 |  | * and the pathfinder runs in invinity loop.
125 |  | * */
126 |  | /* if(n.getSimpleNode().getScope().equals(node.getSimpleNode().getScope())) {
127 |  | System.err.println("equals");
128 |  | continue;
129 |  | }
130 |  | else {
131 |  | System.err.println("don't equals");
132 |  | }
133 |  |
134 |  | //remove all children (should contain only one child)
135 |  | node.removePathToChild((IDataFlowNode)node.getChildren().get(0));
136 |  |
137 |  | node.addPathToChild(n);
138 |  | cbrStack.remove(0);
139 |  | break;
140 |  |
141 |  | }else if(n.isType(NodeType.DO_BEFOR_FIRST_STATEMENT)) {
142 |  |
143 |  | IDataFlowNode inode = (IDataFlowNode)n.getFlow().get(n.getIndex()1);
144 |  |
145 |  | for(int j=0;j<inode.getParents().size();j) {
146 |  | IDataFlowNode parent = (IDataFlowNode)inode.getParents().get(j);
147 |  |
148 |  | if(parent.isType(NodeType.DO_EXPR)) {
149 |  | node.removePathToChild((IDataFlowNode)node.getChildren().get(0));
150 |  | node.addPathToChild(parent);
151 |  |
152 |  | cbrStack.remove(0);
153 |  | break;
154 |  | }
155 |  | }
156 |  | break;
157 |  | }
158 |  | }
159 | 1 | */continueBreakReturnStack.remove(0); // delete this statement if you uncomment the stuff above
160 |  | }
161 |  | }
162 |  | }
163 |  |
164 | 5 | private IDataFlowNode getNodeToBreakStatement(IDataFlowNode node) {
165 |  | // What about breaks to labels above if statements?
166 | 5 | List bList = node.getFlow();
167 | 5 | int findEnds = 1; // ignore ends of other for's while's etc.
168 |  |
169 |  |
170 |  | // find out index of the node where the path goes to after the break
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 |  | // thats not the right node
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 |  | // if if-statement and else-statement contains statements or expressions
312 | 11 | if (ifStart.getIndex() != ifEnd.getIndex() &&
313 |  | ifEnd.getIndex() != elseEnd.getIndex()) {
314 | 11 | elseStart.reverseParentPathsTo(end);
315 | 11 | ifStart.addPathToChild(elseStart);
316 |  | }
317 |  | // if only if-statement contains no expressions
318 | 0 | else if (ifStart.getIndex() == ifEnd.getIndex() &&
319 |  | ifEnd.getIndex() != elseEnd.getIndex()) {
320 | 0 | ifStart.addPathToChild(end);
321 |  | }
322 |  | // if only else-statement contains no expressions
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 |  | // only if the if-statement contains another Statement or Expression
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 |  | }