1 package de.fhdw.wtf.walker.tasks;
2
3 import java.util.Collections;
4 import java.util.Iterator;
5 import java.util.LinkedList;
6 import java.util.List;
7
8 import de.fhdw.wtf.common.ast.Attribute;
9 import de.fhdw.wtf.common.ast.ConstructorOrOperation;
10 import de.fhdw.wtf.common.ast.Group;
11 import de.fhdw.wtf.common.ast.Model;
12 import de.fhdw.wtf.common.ast.type.ClassType;
13 import de.fhdw.wtf.common.ast.type.Type;
14 import de.fhdw.wtf.common.exception.walker.TaskException;
15 import de.fhdw.wtf.common.task.TaskExecutor;
16 import de.fhdw.wtf.walker.walker.SimpleWalkerTask;
17
18
19
20
21
22 public final class AnalyzeInheritanceTreesTask extends SimpleWalkerTask {
23
24
25
26
27 private static final String ANYTHING = "Anything";
28
29
30
31
32
33
34
35
36
37
38 public static AnalyzeInheritanceTreesTask create(final Model model, final TaskExecutor taskmanager) {
39 return new AnalyzeInheritanceTreesTask(model, taskmanager);
40 }
41
42
43
44
45
46
47
48
49
50 private AnalyzeInheritanceTreesTask(final Model model, final TaskExecutor taskmanager) {
51 super(model, taskmanager);
52 }
53
54
55
56
57 private class InheritancePath {
58
59
60
61 private final List<Type> pathElements;
62
63
64
65
66 private InheritancePath() {
67 this.pathElements = new LinkedList<>();
68 }
69
70
71
72
73
74
75
76 InheritancePath(final Type first) {
77 this();
78 this.addElement(first);
79 }
80
81
82
83
84
85
86
87 InheritancePath(final List<Type> firsts) {
88 this();
89 this.addElements(firsts);
90 }
91
92
93
94
95
96
97
98 InheritancePath(final InheritancePath firsts) {
99 this(firsts.pathElements);
100 }
101
102
103
104
105
106
107
108 void addElement(final Type element) {
109 this.pathElements.add(element);
110 }
111
112
113
114
115
116
117
118 void addElements(final List<Type> elements) {
119 this.pathElements.addAll(elements);
120 }
121
122
123
124
125
126
127
128
129 boolean contains(final Type element) {
130 return this.pathElements.contains(element);
131 }
132
133
134
135
136
137
138
139
140
141 InheritancePath intersect(final InheritancePath other) {
142 final InheritancePath result = new InheritancePath();
143 final Iterator<Type> myElements = this.pathElements.iterator();
144 while (myElements.hasNext()) {
145 final Type myElement = myElements.next();
146 if (other.contains(myElement)) {
147 result.addElement(myElement);
148 }
149 }
150 return result;
151 }
152
153
154
155
156
157
158 List<InheritancePath> step() {
159 final List<InheritancePath> alternativePaths = new LinkedList<>();
160 final Type lastElement = this.pathElements.get(this.pathElements.size() - 1);
161 final Iterator<Type> followers = lastElement.getSuperTypes().iterator();
162 if (followers.hasNext()) {
163 final Type firstFollower = followers.next();
164 while (followers.hasNext()) {
165 final Type follower = followers.next();
166 if (!follower.toString().equals(ANYTHING)) {
167 final InheritancePath alternativePath = new InheritancePath(this);
168 alternativePath.addElement(follower);
169 alternativePaths.add(alternativePath);
170 }
171 }
172 if (!firstFollower.toString().equals(ANYTHING)) {
173 this.addElement(firstFollower);
174 }
175 }
176 return alternativePaths;
177 }
178
179
180
181
182
183
184 List<InheritancePath> run() {
185 final List<InheritancePath> result = new LinkedList<>();
186 final List<InheritancePath> preResult = new LinkedList<>();
187 int oldSize = this.pathElements.size();
188 List<InheritancePath> alternativePaths = this.step();
189 while (this.pathElements.size() != oldSize || !alternativePaths.isEmpty()) {
190 preResult.addAll(alternativePaths);
191 oldSize = this.pathElements.size();
192 alternativePaths = this.step();
193 }
194 final Iterator<InheritancePath> paths = preResult.iterator();
195 result.add(this);
196 while (paths.hasNext()) {
197 result.addAll(paths.next().run());
198 }
199 return result;
200 }
201
202 @Override
203 public String toString() {
204 return this.pathElements.toString();
205 }
206
207 @Override
208 public boolean equals(final Object o) {
209 if (o instanceof InheritancePath) {
210 final InheritancePath oAsInheritancePath = (InheritancePath) o;
211 return this.pathElements.equals(oAsInheritancePath.pathElements);
212 }
213 return false;
214 }
215
216 @Override
217 public int hashCode() {
218 return this.pathElements.hashCode();
219 }
220
221
222
223
224
225 boolean isEmpty() {
226 return this.pathElements.isEmpty();
227 }
228
229
230
231
232
233
234
235
236 void removeTop(final Type top) {
237 final int highestIndex = this.pathElements.size() - 1;
238 if (highestIndex >= 0 && this.pathElements.get(highestIndex).equals(top)) {
239 this.pathElements.remove(highestIndex);
240 }
241 }
242
243 }
244
245 @Override
246 public void handleClass(final ClassType c) throws TaskException {
247 final List<InheritancePath> allPaths = new LinkedList<>();
248 final Iterator<Type> superTypes = c.getSuperTypes().iterator();
249 while (superTypes.hasNext()) {
250 final Type currentSuperType = superTypes.next();
251 if (!currentSuperType.toString().equals(ANYTHING)) {
252 allPaths.addAll(new InheritancePath(currentSuperType).run());
253 }
254 }
255 final List<Type> definitiveResponsibilities = new LinkedList<>();
256 final List<InheritancePath> allIntersections =
257 this.gatherAllRelevantIntersections(allPaths, definitiveResponsibilities);
258 this.mapCalls(c, allIntersections, definitiveResponsibilities);
259 }
260
261
262
263
264
265
266
267
268
269
270
271 private List<InheritancePath> gatherAllRelevantIntersections(final List<InheritancePath> allPaths,
272 final List<Type> definitiveResponsibilities) {
273 if (allPaths.size() <= 1) {
274 return allPaths;
275 }
276 final List<InheritancePath> allIntersections = new LinkedList<>();
277 final List<InheritancePath> copy = new LinkedList<>();
278 copy.addAll(allPaths);
279 Collections.reverse(copy);
280 boolean firstSingleOne = true;
281 boolean firstRound = true;
282 boolean firstAllLooseEnds = true;
283 final Iterator<InheritancePath> paths = allPaths.iterator();
284 while (paths.hasNext()) {
285 final InheritancePath currentPath = paths.next();
286 final Type pathEnd = currentPath.pathElements.get(currentPath.pathElements.size() - 1);
287 final List<InheritancePath> currentIntersections = new LinkedList<>();
288 boolean commonEnd = false;
289 final Iterator<InheritancePath> copyPaths = copy.iterator();
290 while (copyPaths.hasNext()) {
291 final InheritancePath currentCopy = copyPaths.next();
292 final InheritancePath intersection = currentPath.intersect(currentCopy);
293 if (!intersection.isEmpty()) {
294 currentIntersections.add(intersection);
295 }
296 if (!currentPath.equals(currentCopy)) {
297 commonEnd =
298 commonEnd
299 || pathEnd
300 .equals(currentCopy.pathElements.get(currentCopy.pathElements.size() - 1));
301 firstAllLooseEnds = firstAllLooseEnds && firstRound && !commonEnd;
302 }
303 }
304 if (commonEnd) {
305 if (firstSingleOne) {
306 firstSingleOne =
307 this.gatherSingleOnes(currentPath, currentIntersections, definitiveResponsibilities);
308 }
309 allIntersections.addAll(currentIntersections);
310 } else {
311 if (firstAllLooseEnds && currentPath.pathElements.size() == 1) {
312 final Type type = currentPath.pathElements.get(0);
313 if (!definitiveResponsibilities.contains(type)) {
314 definitiveResponsibilities.add(type);
315 }
316 } else {
317 allIntersections.addAll(currentIntersections);
318 }
319 }
320 firstRound = firstAllLooseEnds;
321 }
322
323 return allIntersections;
324 }
325
326
327
328
329
330
331
332
333
334
335
336
337
338 private boolean gatherSingleOnes(final InheritancePath currentPath,
339 final List<InheritancePath> currentIntersections,
340 final List<Type> definitiveResponsibilities) {
341 final Iterator<InheritancePath> intersections = currentIntersections.iterator();
342 final Type first = currentPath.pathElements.get(0);
343 boolean firstOne = false;
344 while (intersections.hasNext()) {
345 final InheritancePath current = intersections.next();
346 if (current.pathElements.size() == 1) {
347 final Type type = current.pathElements.get(0);
348 firstOne = !type.equals(first) && !definitiveResponsibilities.contains(type);
349 if (firstOne) {
350 definitiveResponsibilities.add(type);
351 }
352 }
353 }
354 return firstOne;
355 }
356
357
358
359
360
361
362
363
364
365
366
367
368
369 private void mapCalls(final ClassType c,
370 final List<InheritancePath> allIntersections,
371 final List<Type> definitiveResponsibilities) {
372 List<InheritancePath> copyNewIntersections = new LinkedList<>();
373 copyNewIntersections.addAll(allIntersections);
374 while (!copyNewIntersections.isEmpty()) {
375 final List<InheritancePath> newIntersections = new LinkedList<>();
376 final Iterator<InheritancePath> intersections = copyNewIntersections.iterator();
377 while (intersections.hasNext()) {
378 final InheritancePath path = intersections.next();
379 if (path.isEmpty()) {
380 intersections.remove();
381 } else if (path.pathElements.size() == 1) {
382 final Type type = path.pathElements.get(0);
383 if (!definitiveResponsibilities.contains(type)) {
384 definitiveResponsibilities.add(type);
385 }
386 final List<InheritancePath> copyList = new LinkedList<>();
387 copyList.addAll(copyNewIntersections);
388 final Iterator<InheritancePath> copy = copyList.iterator();
389 while (copy.hasNext()) {
390 copy.next().removeTop(type);
391 }
392
393 } else {
394 final Type top = path.pathElements.get(path.pathElements.size() - 1);
395 final List<InheritancePath> copyList = new LinkedList<>();
396 copyList.addAll(copyNewIntersections);
397 final Iterator<InheritancePath> copies = copyList.iterator();
398 while (copies.hasNext()) {
399 final InheritancePath copy = copies.next();
400 final InheritancePath intersection = path.intersect(copy);
401 copy.removeTop(top);
402 if (!intersection.isEmpty()) {
403 if (intersection.pathElements.size() == 1) {
404 final Type type = path.pathElements.get(0);
405 if (!definitiveResponsibilities.contains(type)) {
406 definitiveResponsibilities.add(type);
407 }
408 } else {
409 intersection.removeTop(top);
410 newIntersections.add(intersection);
411 }
412 }
413 }
414 }
415 }
416 copyNewIntersections = new LinkedList<>();
417 copyNewIntersections.addAll(newIntersections);
418 }
419 this.getModel().putConstructorCallDependency(c, definitiveResponsibilities);
420 }
421
422 @Override
423 public void handleGroup(final Group g) throws TaskException {
424
425 }
426
427 @Override
428 public void handleAttribute(final Attribute a, final ClassType owner) throws TaskException {
429
430 }
431
432 @Override
433 public void handleConstructorOrOperation(final ConstructorOrOperation coo, final ClassType owner)
434 throws TaskException {
435
436 }
437
438 @Override
439 public void finalizeTask() throws TaskException {
440
441 }
442
443 @Override
444 public void beginTask() throws TaskException {
445
446 }
447
448 }