Skip to content

Method: toString()

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: * Analyzes the inheritance trees of the given model. Enriches the model with useful information regarding necessary
20: * constructor calls.
21: */
22: public final class AnalyzeInheritanceTreesTask extends SimpleWalkerTask {
23:         
24:         /**
25:          * Used to identify the type Anything.
26:          */
27:         private static final String ANYTHING = "Anything";
28:         
29:         /**
30:          * Returns a new instance of {@link AnalyzeInheritanceTreesTask}.
31:          *
32:          * @param model
33:          * The model to perform this task on.
34:          * @param taskmanager
35:          * The executor which performs this task.
36:          * @return a new instance of {@link AnalyzeInheritanceTreesTask}
37:          */
38:         public static AnalyzeInheritanceTreesTask create(final Model model, final TaskExecutor taskmanager) {
39:                 return new AnalyzeInheritanceTreesTask(model, taskmanager);
40:         }
41:         
42:         /**
43:          * Instantiates a new instance of {@link AnalyzeInheritanceTreesTask}.
44:          *
45:          * @param model
46:          * The model to perform this task on.
47:          * @param taskmanager
48:          * The executor which performs this task.
49:          */
50:         private AnalyzeInheritanceTreesTask(final Model model, final TaskExecutor taskmanager) {
51:                 super(model, taskmanager);
52:         }
53:         
54:         /**
55:          * Helper class which represents one path along the inheritance-hierarchy of a root class.
56:          */
57:         private class InheritancePath {
58:                 /**
59:                  * Types ordered along this InheritancePath.
60:                  */
61:                 private final List<Type> pathElements;
62:                 
63:                 /**
64:                  * Constructs an empty InheritancePath.
65:                  */
66:                 private InheritancePath() {
67:                         this.pathElements = new LinkedList<>();
68:                 }
69:                 
70:                 /**
71:                  * Constructs an InheritancePath with first as its root.
72:                  *
73:                  * @param first
74:                  * the first element of this path.
75:                  */
76:                 InheritancePath(final Type first) {
77:                         this();
78:                         this.addElement(first);
79:                 }
80:                 
81:                 /**
82:                  * Constructs an InheritancePath with firsts as its path elements.
83:                  *
84:                  * @param firsts
85:                  * the path elements for this.
86:                  */
87:                 InheritancePath(final List<Type> firsts) {
88:                         this();
89:                         this.addElements(firsts);
90:                 }
91:                 
92:                 /**
93:                  * Constructs an InheritancePath which is identical to firsts.
94:                  *
95:                  * @param firsts
96:                  * the path to copy.
97:                  */
98:                 InheritancePath(final InheritancePath firsts) {
99:                         this(firsts.pathElements);
100:                 }
101:                 
102:                 /**
103:                  * Adds element to the end of this path.
104:                  *
105:                  * @param element
106:                  * the new end of this path.
107:                  */
108:                 void addElement(final Type element) {
109:                         this.pathElements.add(element);
110:                 }
111:                 
112:                 /**
113:                  * Adds elements to this path so that these elements remain in the order provided in elements.
114:                  *
115:                  * @param elements
116:                  * the elements added to this.
117:                  */
118:                 void addElements(final List<Type> elements) {
119:                         this.pathElements.addAll(elements);
120:                 }
121:                 
122:                 /**
123:                  * Returns true if element is also an element of this. False otherwise.
124:                  *
125:                  * @param element
126:                  * to check.
127:                  * @return true if element is part of this. False otherwise.
128:                  */
129:                 boolean contains(final Type element) {
130:                         return this.pathElements.contains(element);
131:                 }
132:                 
133:                 /**
134:                  * Returns all elements that this and other have in common. The common elements will be provided the order
135:                  * provided by this.
136:                  *
137:                  * @param other
138:                  * the path to intersect with.
139:                  * @return common elements in the order of their existence in this path.
140:                  */
141:                 List<Type> intersect(final InheritancePath other) {
142:                         final List<Type> result = new LinkedList<>();
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.add(myElement);
148:                                 }
149:                         }
150:                         return result;
151:                 }
152:                 
153:                 /**
154:                  * Makes one step in the inheritance-tree. Alternative paths will be returned.
155:                  *
156:                  * @return alternative paths if any exist. An empty llist otherwise.
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:                  * Calculates all inheritance paths reachable from the end of this path and returns them.
181:                  *
182:                  * @return a list with all paths reachable from the last element of this.
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:         @Override
224:         public void handleClass(final ClassType c) throws TaskException {
225:                 final List<InheritancePath> allPaths = new LinkedList<>();
226:                 final Iterator<Type> superTypes = c.getSuperTypes().iterator();
227:                 while (superTypes.hasNext()) {
228:                         final Type currentSuperType = superTypes.next();
229:                         if (!currentSuperType.toString().equals(ANYTHING)) {
230:                                 allPaths.addAll(new InheritancePath(currentSuperType).run());
231:                         }
232:                 }
233:                 final List<InheritancePath> allPathsWithoutOpenEnds = this.removeOpenEnds(allPaths);
234:                 this.mapCalls(c, allPathsWithoutOpenEnds);
235:         }
236:         
237:         /**
238:          * Returns a list with all paths from allPaths that have no common ends with other paths of allPaths. Remoturns
239:          * allPaths if allPaths is of length 1 or if all paths have no common ends. Paths with the length of 1 will not be
240:          * removed.
241:          *
242:          * @param allPaths
243:          * all inheritance paths of a inheritance tree.
244:          * @return a list without "open" ended paths or which is equals allPaths if allPaths is of length 1 or returns
245:          * allPaths itself if all paths have no common ends.
246:          */
247:         private List<InheritancePath> removeOpenEnds(final List<InheritancePath> allPaths) {
248:                 final List<InheritancePath> copy = new LinkedList<>();
249:                 copy.addAll(allPaths);
250:                 if (allPaths.size() > 1) {
251:                         final Iterator<InheritancePath> copyIterator = copy.iterator();
252:                         while (copyIterator.hasNext()) {
253:                                 final InheritancePath currentCopy = copyIterator.next();
254:                                 final Iterator<InheritancePath> pathsIterator = allPaths.iterator();
255:                                 boolean openEnd = true;
256:                                 if (currentCopy.pathElements.size() > 1) {
257:                                         while (openEnd && pathsIterator.hasNext()) {
258:                                                 final InheritancePath currentPath = pathsIterator.next();
259:                                                 if (!currentCopy.equals(currentPath)) {
260:                                                         openEnd =
261:                                                                         !currentCopy.pathElements.get(currentCopy.pathElements.size() - 1).equals(
262:                                                                                         currentPath.pathElements.get(currentPath.pathElements.size() - 1));
263:                                                 }
264:                                         }
265:                                         if (openEnd) {
266:                                                 copyIterator.remove();
267:                                         }
268:                                 }
269:                         }
270:                 }
271:                 if (!copy.isEmpty()) {
272:                         return copy;
273:                 } else {
274:                         return allPaths;
275:                 }
276:                 
277:         }
278:         
279:         /**
280:          * Maps c to all types it has to instantiate during runtime. Uses the map "constructorCalldependencies" in Model for
281:          * this purpose. Maps to an empty list if c has no responsibilities in the regard of instantiating super types.
282:          *
283:          * @param c
284:          * the root of the inheritance tree to map types from.
285:          * @param allPaths
286:          * The inheritance tree with c as root in form of all paths that have the direct super types of c as
287:          * root.
288:          */
289:         private void mapCalls(final ClassType c, final List<InheritancePath> allPaths) {
290:                 final List<Type> definitiveResponsibilities = new LinkedList<>();
291:                 final List<InheritancePath> copy = new LinkedList<>();
292:                 copy.addAll(allPaths);
293:                 Collections.reverse(allPaths);
294:                 final Iterator<InheritancePath> copyPaths = copy.iterator();
295:                 while (copyPaths.hasNext()) {
296:                         final InheritancePath copyPath = copyPaths.next();
297:                         final Iterator<InheritancePath> paths = allPaths.iterator();
298:                         while (paths.hasNext()) {
299:                                 final InheritancePath path = paths.next();
300:                                 final Iterator<Type> intersection = path.intersect(copyPath).iterator();
301:                                 if (intersection.hasNext()) {
302:                                         final Type definitiveOne = intersection.next();
303:                                         if (!definitiveResponsibilities.contains(definitiveOne)) {
304:                                                 definitiveResponsibilities.add(definitiveOne);
305:                                         }
306:                                 }
307:                         }
308:                         copyPaths.remove();
309:                 }
310:                 this.getModel().putConstructorCallDependency(c, definitiveResponsibilities);
311:         }
312:         
313:         @Override
314:         public void handleGroup(final Group g) throws TaskException {
315:                 // Nothing to do.
316:         }
317:         
318:         @Override
319:         public void handleAttribute(final Attribute a, final ClassType owner) throws TaskException {
320:                 // Nothing to do.
321:         }
322:         
323:         @Override
324:         public void handleConstructorOrOperation(final ConstructorOrOperation coo, final ClassType owner)
325:                         throws TaskException {
326:                 // Nothing to do.
327:         }
328:         
329:         @Override
330:         public void finalizeTask() throws TaskException {
331:                 // Nothing to do.
332:         }
333:         
334:         @Override
335:         public void beginTask() throws TaskException {
336:                 // Nothing to do.
337:         }
338:         
339: }