Skip to content

Package: ReferencedConstructorsCheck$2

ReferencedConstructorsCheck$2

nameinstructionbranchcomplexitylinemethod
handle(AtomicType)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
handle(CompositeType)
M: 23 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
handle(TypeProxy)
M: 7 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
{...}
M: 12 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%

Coverage

1: package de.fhdw.wtf.walker.tasks;
2:
3: import java.util.Collection;
4: import java.util.Iterator;
5: import java.util.LinkedList;
6: import java.util.List;
7: import java.util.Map;
8:
9: import de.fhdw.wtf.common.ast.Attribute;
10: import de.fhdw.wtf.common.ast.Constructor;
11: import de.fhdw.wtf.common.ast.ConstructorByReferenceState;
12: import de.fhdw.wtf.common.ast.ConstructorByTypeAndSignatureState;
13: import de.fhdw.wtf.common.ast.ConstructorInvalidState;
14: import de.fhdw.wtf.common.ast.ConstructorOrOperation;
15: import de.fhdw.wtf.common.ast.ConstructorReference;
16: import de.fhdw.wtf.common.ast.ConstructorReferenceState;
17: import de.fhdw.wtf.common.ast.Group;
18: import de.fhdw.wtf.common.ast.Model;
19: import de.fhdw.wtf.common.ast.Operation;
20: import de.fhdw.wtf.common.ast.type.AtomicType;
21: import de.fhdw.wtf.common.ast.type.ClassType;
22: import de.fhdw.wtf.common.ast.type.CompositeType;
23: import de.fhdw.wtf.common.ast.type.ListType;
24: import de.fhdw.wtf.common.ast.type.MapType;
25: import de.fhdw.wtf.common.ast.type.ProductType;
26: import de.fhdw.wtf.common.ast.type.SumType;
27: import de.fhdw.wtf.common.ast.type.ThrownType;
28: import de.fhdw.wtf.common.ast.type.Type;
29: import de.fhdw.wtf.common.ast.type.TypeProxy;
30: import de.fhdw.wtf.common.ast.visitor.CompositeTypeVisitorReturn;
31: import de.fhdw.wtf.common.ast.visitor.ConstructorOrOperationExceptionVisitor;
32: import de.fhdw.wtf.common.ast.visitor.ConstructorReferenceStateVisitorReturnException;
33: import de.fhdw.wtf.common.ast.visitor.TypeVisitorReturn;
34: import de.fhdw.wtf.common.exception.walker.InvalidConstructorReferenceListException;
35: import de.fhdw.wtf.common.exception.walker.TaskException;
36: import de.fhdw.wtf.common.task.TaskExecutor;
37: import de.fhdw.wtf.walker.walker.SimpleWalkerTask;
38:
39: /**
40: * Checks if the list of super constructors in constructors apply to the rules for constructors. Should not run before
41: * {@link ConstructorReferencer}.
42: */
43: public final class ReferencedConstructorsCheck extends SimpleWalkerTask {
44:         
45:         /**
46:          * The instantiations classes must do.
47:          */
48:         private final Map<Type, List<Type>> necessaryCalls;
49:         
50:         /**
51:          * Returns a new instance of {@link ReferencedConstructorsCheck}.
52:          *
53:          * @param model
54:          * The model to check.
55:          * @param taskmanager
56:          * The executor which performs this task.
57:          * @return a new instance of {@link ReferencedConstructorsCheck}
58:          */
59:         public static ReferencedConstructorsCheck create(final Model model, final TaskExecutor taskmanager) {
60:                 return new ReferencedConstructorsCheck(model, taskmanager);
61:         }
62:         
63:         /**
64:          * Instantiates a new instance of {@link ReferencedConstructorsCheck}.
65:          *
66:          * @param model
67:          * The model to check.
68:          * @param taskmanager
69:          * The executor which performs this task.
70:          */
71:         private ReferencedConstructorsCheck(final Model model, final TaskExecutor taskmanager) {
72:                 super(model, taskmanager);
73:                 this.necessaryCalls = model.getConstructorCallDependencies();
74:         }
75:         
76:         @Override
77:         public void handleClass(final ClassType c) throws TaskException {
78:                 // Nothing to do.
79:         }
80:         
81:         @Override
82:         public void handleGroup(final Group g) throws TaskException {
83:                 // Nothing to do.
84:         }
85:         
86:         @Override
87:         public void handleAttribute(final Attribute a, final ClassType owner) throws TaskException {
88:                 // Nothing to do.
89:         }
90:         
91:         @Override
92:         public void handleConstructorOrOperation(final ConstructorOrOperation coo, final ClassType owner)
93:                         throws TaskException {
94:                 coo.accept(new ConstructorOrOperationExceptionVisitor<TaskException>() {
95:                         
96:                         @Override
97:                         public void handleConstructor(final Constructor constructor) throws TaskException {
98:                                 final Type caller = constructor.getReturnType();
99:                                 final List<Type> typesToCall = ReferencedConstructorsCheck.this.necessaryCalls.get(caller);
100:                                 final Collection<Type> calledSuperTypes = new LinkedList<>();
101:                                 final Iterator<ConstructorReference> references = constructor.getSuperConstructors().iterator();
102:                                 while (references.hasNext()) {
103:                                         final ConstructorReference reference = references.next();
104:                                         calledSuperTypes.add(ReferencedConstructorsCheck.this.getReferencedType(reference.getState()));
105:                                 }
106:                                 if (!ReferencedConstructorsCheck.this.checkIfLegitimeSuperTypeList(
107:                                                 caller,
108:                                                 calledSuperTypes,
109:                                                 typesToCall)) {
110:                                         throw InvalidConstructorReferenceListException.create(
111:                                                         constructor,
112:                                                         "Either not all constructors that have to be called are being referenced"
113:                                                                         + "or too many constructors are being referenced!"
114:                                                                         + "\nSupertypes which have to be instanciated by this class:"
115:                                                                         + typesToCall.toString() + "\nCalling constructor: ");
116:                                 }
117:                                 
118:                         }
119:                         
120:                         @Override
121:                         public void handleOperation(final Operation operation) throws TaskException {
122:                                 // Nothing to do.
123:                         }
124:                         
125:                 });
126:                 
127:         }
128:         
129:         /**
130:          * Checks if the two collections contain each over mutually.
131:          *
132:          * @param caller
133:          * the caller.
134:          * @param calledSuperTypes
135:          * one collection.
136:          * @param typesToCall
137:          * one collection.
138:          * @return true if they contain each other. Otherwise false.
139:          */
140:         protected boolean checkIfLegitimeSuperTypeList(final Type caller,
141:                         final Collection<Type> calledSuperTypes,
142:                         final Collection<Type> typesToCall) {
143:                 return this.checkOneWay(caller, calledSuperTypes, typesToCall)
144:                                 && this.checkOneWay(caller, typesToCall, calledSuperTypes);
145:         }
146:         
147:         /**
148:          * Checks if all elements in left are contained in right.
149:          *
150:          * @param caller
151:          * the caller.
152:          *
153:          * @param left
154:          * a collection.
155:          * @param right
156:          * a collection.
157:          * @return true if right contains all elements of right.
158:          */
159:         private boolean checkOneWay(final Type caller, final Collection<Type> left, final Collection<Type> right) {
160:                 final Iterator<Type> leftIterator = left.iterator();
161:                 boolean legitimate = true;
162:                 while (legitimate && leftIterator.hasNext()) {
163:                         final Type currentCalled = leftIterator.next();
164:                         legitimate = currentCalled.accept(new TypeChecker(caller, currentCalled, right));
165:                 }
166:                 return legitimate;
167:         }
168:         
169:         /**
170:          * Checks if a type is part of a given list of types.
171:          */
172:         class TypeChecker implements TypeVisitorReturn<Boolean> {
173:                 
174:                 /**
175:                  * Calling type.
176:                  */
177:                 private final Type caller;
178:                 
179:                 /**
180:                  * Called type.
181:                  */
182:                 private final Type called;
183:                 /**
184:                  * types to call.
185:                  */
186:                 private final Collection<Type> typesToCall;
187:                 
188:                 /**
189:                  * Returns a new TypeChecker.
190:                  *
191:                  * @param caller
192:                  * the caller.
193:                  * @param called
194:                  * called.
195:                  *
196:                  * @param typesToCall
197:                  * the list to check against.
198:                  */
199:                 TypeChecker(final Type caller, final Type called, final Collection<Type> typesToCall) {
200:                         this.caller = caller;
201:                         this.called = called;
202:                         this.typesToCall = typesToCall;
203:                 }
204:                 
205:                 @Override
206:                 public Boolean handle(final AtomicType atomicType) {
207:                         return ReferencedConstructorsCheck.this.contains(this.caller, atomicType, this.typesToCall);
208:                 }
209:                 
210:                 @Override
211:                 public Boolean handle(final CompositeType compositeType) {
212:                         return compositeType.accept(new CompositeTypeChecker(this.caller, this.called, this.typesToCall));
213:                 }
214:                 
215:                 @Override
216:                 public Boolean handle(final TypeProxy typeProxy) {
217:                         return typeProxy.getTarget().accept(this);
218:                 }
219:                 
220:         }
221:         
222:         /**
223:          * Checks if a part of a sum type is part of a given list of types.
224:          */
225:         class CompositeTypeChecker implements CompositeTypeVisitorReturn<Boolean> {
226:                 
227:                 /**
228:                  * Calling type.
229:                  */
230:                 private final Type caller;
231:                 /**
232:                  * Called type.
233:                  */
234:                 private final Type called;
235:                 /**
236:                  * types to call.
237:                  */
238:                 private final Collection<Type> typesToCall;
239:                 
240:                 /**
241:                  * Returns a new CompositeTypeChecker.
242:                  *
243:                  * @param caller
244:                  * the caller.
245:                  * @param called
246:                  * called.
247:                  *
248:                  * @param typesToCall
249:                  * the list to check against.
250:                  */
251:                 CompositeTypeChecker(final Type caller, final Type called, final Collection<Type> typesToCall) {
252:                         this.caller = caller;
253:                         this.called = called;
254:                         this.typesToCall = typesToCall;
255:                 }
256:                 
257:                 @Override
258:                 public Boolean handle(final ListType list) {
259:                         return list.getOf().accept(new TypeChecker(this.caller, this.called, this.typesToCall));
260:                 }
261:                 
262:                 @Override
263:                 public Boolean handle(final MapType map) {
264:                         return map.getOf().accept(new TypeChecker(this.caller, this.called, this.typesToCall));
265:                 }
266:                 
267:                 @Override
268:                 public Boolean handle(final ProductType product) {
269:                         return this.typesToCall.contains(product);
270:                 }
271:                 
272:                 @Override
273:                 public Boolean handle(final SumType sum) {
274:                         final Collection<Type> elements = sum.getElements();
275:                         if (elements.contains(this.caller)) {
276:                                 final List<Type> newToCall = ReferencedConstructorsCheck.this.necessaryCalls.get(this.caller);
277:                                 newToCall.remove(sum);
278:                                 ReferencedConstructorsCheck.this.getModel().putConstructorCallDependency(this.caller, newToCall);
279:                                 return true;
280:                         }
281:                         final Iterator<Type> parts = elements.iterator();
282:                         boolean found = false;
283:                         while (!found && parts.hasNext()) {
284:                                 found = parts.next().accept(new TypeChecker(this.caller, this.called, this.typesToCall));
285:                         }
286:                         
287:                         final Iterator<Type> superParts = this.typesToCall.iterator();
288:                         while (!found && superParts.hasNext()) {
289:                                 found = superParts.next().isSupertypeOf(sum);
290:                         }
291:                         if (found) {
292:                                 final List<Type> newToCall = ReferencedConstructorsCheck.this.necessaryCalls.get(this.caller);
293:                                 final int index = newToCall.indexOf(sum);
294:                                 newToCall.remove(index);
295:                                 newToCall.add(index, this.called);
296:                                 ReferencedConstructorsCheck.this.getModel().putConstructorCallDependency(this.caller, newToCall);
297:                         }
298:                         return found;
299:                 }
300:                 
301:                 @Override
302:                 public Boolean handle(final ThrownType thrownType) {
303:                         return this.typesToCall.contains(thrownType);
304:                 }
305:                 
306:         }
307:         
308:         /**
309:          * returns true if typesTocall contains atomicType.
310:          *
311:          * @param caller
312:          * caller
313:          * @param atomicType
314:          * atomicType
315:          * @param typesToCall
316:          * typesToCall
317:          * @return true if typesTocall contains atomicType. false otherwise.
318:          */
319:         public boolean contains(final Type caller, final AtomicType atomicType, final Collection<Type> typesToCall) {
320:                 final Iterator<Type> types = typesToCall.iterator();
321:                 boolean found = false;
322:                 while (!found && types.hasNext()) {
323:                         found = types.next().accept(new TypeVisitorReturn<Boolean>() {
324:                                 
325:                                 @Override
326:                                 public Boolean handle(final AtomicType atomicType2) {
327:                                         return atomicType2.equals(atomicType);
328:                                 }
329:                                 
330:                                 @Override
331:                                 public Boolean handle(final CompositeType compositeType) {
332:                                         final Collection<Type> typesToCall2 = new LinkedList<>();
333:                                         typesToCall2.add(atomicType);
334:                                         return compositeType.accept(new CompositeTypeChecker(caller, atomicType, typesToCall2));
335:                                 }
336:                                 
337:                                 @Override
338:                                 public Boolean handle(final TypeProxy typeProxy) {
339:                                         return typeProxy.getTarget().equals(atomicType);
340:                                 }
341:                                 
342:                         });
343:                 }
344:                 return found;
345:         }
346:         
347:         /**
348:          * Returns the type referenced in state.
349:          *
350:          * @param state
351:          * the state to get the type from.
352:          * @return the referenced type.
353:          * @throws TaskException
354:          * if the state is not a byReference state.
355:          */
356:         protected Type getReferencedType(final ConstructorReferenceState state) throws TaskException {
357:                 return state.accept(new ConstructorReferenceStateVisitorReturnException<Type, TaskException>() {
358:                         
359:                         @Override
360:                         public Type handle(final ConstructorByTypeAndSignatureState byName) throws TaskException {
361:                                 throw new TaskException("ByName states of ConstructorReferenceStates are not allowed here!");
362:                         }
363:                         
364:                         @Override
365:                         public Type handle(final ConstructorInvalidState invalid) throws TaskException {
366:                                 throw new TaskException("Invalid states of ConstructorReferenceStates are not allowed here!");
367:                         }
368:                         
369:                         @Override
370:                         public Type handle(final ConstructorByReferenceState byReference) throws TaskException {
371:                                 return byReference.getType();
372:                         }
373:                         
374:                 });
375:         }
376:         
377:         @Override
378:         public void finalizeTask() throws TaskException {
379:                 // Nothing to do.
380:         }
381:         
382:         @Override
383:         public void beginTask() throws TaskException {
384:                 // Nothing to do.
385:         }
386:         
387: }