Skip to content

Package: ReferencedConstructorsCheck

ReferencedConstructorsCheck

nameinstructionbranchcomplexitylinemethod
ReferencedConstructorsCheck(Model, TaskExecutor)
M: 0 C: 9
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
beginTask()
M: 0 C: 1
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
checkIfLegitimeSuperTypeList(Type, Collection, Collection)
M: 16 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
checkOneWay(Type, Collection, Collection)
M: 29 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
contains(Type, AtomicType, Collection)
M: 26 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
create(Model, TaskExecutor)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
finalizeTask()
M: 0 C: 1
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getReferencedType(ConstructorReferenceState)
M: 8 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
handleAttribute(Attribute, ClassType)
M: 0 C: 1
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
handleClass(ClassType)
M: 0 C: 1
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
handleConstructorOrOperation(ConstructorOrOperation, ClassType)
M: 7 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
handleGroup(Group)
M: 0 C: 1
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%

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:                                 return true;
277:                         }
278:                         final Iterator<Type> parts = sum.getElements().iterator();
279:                         boolean found = false;
280:                         while (!found && parts.hasNext()) {
281:                                 found = parts.next().accept(new TypeChecker(this.caller, this.called, this.typesToCall));
282:                         }
283:                         
284:                         final Iterator<Type> superParts = this.typesToCall.iterator();
285:                         while (!found && superParts.hasNext()) {
286:                                 found = superParts.next().isSupertypeOf(sum);
287:                         }
288:                         return found;
289:                 }
290:                 
291:                 @Override
292:                 public Boolean handle(final ThrownType thrownType) {
293:                         return this.typesToCall.contains(thrownType);
294:                 }
295:                 
296:         }
297:         
298:         /**
299:          * returns true if typesTocall contains atomicType.
300:          *
301:          * @param caller
302:          * caller
303:          * @param atomicType
304:          * atomicType
305:          * @param typesToCall
306:          * typesToCall
307:          * @return true if typesTocall contains atomicType. false otherwise.
308:          */
309:         public boolean contains(final Type caller, final AtomicType atomicType, final Collection<Type> typesToCall) {
310:                 final Iterator<Type> types = typesToCall.iterator();
311:                 boolean found = false;
312:•                while (!found && types.hasNext()) {
313:                         found = types.next().accept(new TypeVisitorReturn<Boolean>() {
314:                                 
315:                                 @Override
316:                                 public Boolean handle(final AtomicType atomicType2) {
317:                                         return atomicType2.equals(atomicType);
318:                                 }
319:                                 
320:                                 @Override
321:                                 public Boolean handle(final CompositeType compositeType) {
322:                                         final Collection<Type> typesToCall2 = new LinkedList<>();
323:                                         typesToCall2.add(atomicType);
324:                                         return compositeType.accept(new CompositeTypeChecker(caller, atomicType, typesToCall2));
325:                                 }
326:                                 
327:                                 @Override
328:                                 public Boolean handle(final TypeProxy typeProxy) {
329:                                         return typeProxy.getTarget().equals(atomicType);
330:                                 }
331:                                 
332:                         });
333:                 }
334:                 return found;
335:         }
336:         
337:         /**
338:          * Returns the type referenced in state.
339:          *
340:          * @param state
341:          * the state to get the type from.
342:          * @return the referenced type.
343:          * @throws TaskException
344:          * if the state is not a byReference state.
345:          */
346:         protected Type getReferencedType(final ConstructorReferenceState state) throws TaskException {
347:                 return state.accept(new ConstructorReferenceStateVisitorReturnException<Type, TaskException>() {
348:                         
349:                         @Override
350:                         public Type handle(final ConstructorByTypeAndSignatureState byName) throws TaskException {
351:                                 throw new TaskException("ByName states of ConstructorReferenceStates are not allowed here!");
352:                         }
353:                         
354:                         @Override
355:                         public Type handle(final ConstructorInvalidState invalid) throws TaskException {
356:                                 throw new TaskException("Invalid states of ConstructorReferenceStates are not allowed here!");
357:                         }
358:                         
359:                         @Override
360:                         public Type handle(final ConstructorByReferenceState byReference) throws TaskException {
361:                                 return byReference.getType();
362:                         }
363:                         
364:                 });
365:         }
366:         
367:         @Override
368:         public void finalizeTask() throws TaskException {
369:                 // Nothing to do.
370:         }
371:         
372:         @Override
373:         public void beginTask() throws TaskException {
374:                 // Nothing to do.
375:         }
376:         
377: }