Skip to content

Package: ConstructorReferencer$1

ConstructorReferencer$1

nameinstructionbranchcomplexitylinemethod
handleConstructor(Constructor)
M: 0 C: 23
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 5
100%
M: 0 C: 1
100%
handleOperation(Operation)
M: 1 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
{...}
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
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:
7: import de.fhdw.wtf.common.ast.Attribute;
8: import de.fhdw.wtf.common.ast.Constructor;
9: import de.fhdw.wtf.common.ast.ConstructorByReferenceState;
10: import de.fhdw.wtf.common.ast.ConstructorByTypeAndSignatureState;
11: import de.fhdw.wtf.common.ast.ConstructorInvalidState;
12: import de.fhdw.wtf.common.ast.ConstructorOrOperation;
13: import de.fhdw.wtf.common.ast.ConstructorReference;
14: import de.fhdw.wtf.common.ast.Group;
15: import de.fhdw.wtf.common.ast.Model;
16: import de.fhdw.wtf.common.ast.Operation;
17: import de.fhdw.wtf.common.ast.Tuple;
18: import de.fhdw.wtf.common.ast.type.ClassType;
19: import de.fhdw.wtf.common.ast.visitor.ConstructorOrOperationExceptionVisitor;
20: import de.fhdw.wtf.common.ast.visitor.ConstructorReferenceStateVisitorReturn;
21: import de.fhdw.wtf.common.exception.referencer.ConstructorReferenceMismatchException;
22: import de.fhdw.wtf.common.exception.referencer.ConstructorReferencerExceptions;
23: import de.fhdw.wtf.common.exception.referencer.CyclicConstructorCallException;
24: import de.fhdw.wtf.common.exception.referencer.DuplicateConstructorException;
25: import de.fhdw.wtf.common.exception.walker.TaskException;
26: import de.fhdw.wtf.common.task.TaskExecutor;
27:
28: /**
29: * This referencer tries to find the real {@link Constructor} instances that are referenced by the
30: * {@link ConstructorReference} instances. The found {@link ConstructorReference} instances in the superConstructor
31: * collections of all defined {@link Constructor} instances are being replaced by matching {@link Constructor}
32: * instances. This task shall not be performed before the task {@link TypeReferencer}.
33: *
34: */
35: public class ConstructorReferencer extends Referencer {
36:         
37:         /**
38:          * The minimum of {@link Constructor} instances that are searched to replace a {@link ConstructorReference}.
39:          *
40:          */
41:         private static final int MINIMUM_OF_CONSTRUCTOR_INSTANCES_NEEDED_TO_MATCH_A_REFERENCE = 1;
42:         
43:         /**
44:          * The maximum of {@link Constructor} instances that are searched to replace a {@link ConstructorReference}. The
45:          * transgression of that value can be seen as exceptional behavior (Wrong wtf-model).
46:          */
47:         private static final int MAXIMUM_OF_CONSTRUCTOR_INSTANCES_ALLOWED_TO_MATCH_A_REFERENCE = 1;
48:         
49:         /**
50:          * COntains all {@link ClassType} instances that contain at least one {@link Constructor} instance (which should be
51:          * all {@link ClassType} instances).
52:          */
53:         private final Collection<ClassType> constructorOwners;
54:         /**
55:          * Contains tuples of {@link ConstructorReference} instances and the {@link Constructor} instances which contain
56:          * them.
57:          */
58:         private final Collection<Tuple<ConstructorReference, Constructor>> constructorReferences;
59:         /**
60:          * Contains all exception that might appear when this task is being performed. This field should be read to
61:          * determine whether an exception happened or not.
62:          */
63:         private final Collection<TaskException> exceptions;
64:         
65:         /**
66:          * Instantiates a new {@link ConstructorReferencer}.
67:          *
68:          * @param model
69:          * the model with the {@link ConstructorReference} instances to replace.
70:          * @param taskmanager
71:          * the manager which performs this task.
72:          */
73:         public ConstructorReferencer(final Model model, final TaskExecutor taskmanager) {
74:                 super(model, taskmanager);
75:                 this.constructorOwners = new LinkedList<>();
76:                 this.constructorReferences = new LinkedList<>();
77:                 this.exceptions = new LinkedList<>();
78:         }
79:         
80:         /**
81:          * Creates a {@link ConstructorReferencer}-Object.
82:          *
83:          * @param inputModel
84:          * Model
85:          * @param taskmanager
86:          * Taskmanager
87:          * @return The Referencer-Object
88:          */
89:         public static ConstructorReferencer create(final Model inputModel, final TaskExecutor taskmanager) {
90:                 return new ConstructorReferencer(inputModel, taskmanager);
91:         }
92:         
93:         @Override
94:         public void handleClass(final ClassType c) throws TaskException {
95:                 this.constructorOwners.add(c);
96:         }
97:         
98:         @Override
99:         public void handleGroup(final Group g) throws TaskException {
100:                 // Nothing to do.
101:         }
102:         
103:         @Override
104:         public void handleAttribute(final Attribute a, final ClassType owner) throws TaskException {
105:                 // Nothing to do.
106:         }
107:         
108:         @Override
109:         public void handleConstructorOrOperation(final ConstructorOrOperation coo, final ClassType owner)
110:                         throws TaskException {
111:                 coo.accept(new ConstructorOrOperationExceptionVisitor<TaskException>() {
112:                         
113:                         @Override
114:                         public void handleOperation(final Operation operation) throws TaskException {
115:                                 // Nothing to do.
116:                                 
117:                         }
118:                         
119:                         @Override
120:                         public void handleConstructor(final Constructor constructor) throws TaskException {
121:                                 final Iterator<ConstructorReference> referencedConstructors = constructor.getSuperConstructors().iterator();
122:•                                while (referencedConstructors.hasNext()) {
123:                                         final ConstructorReference referencedConstructor = referencedConstructors.next();
124:                                         ConstructorReferencer.this.constructorReferences.add(new Tuple<>(referencedConstructor, constructor));
125:                                 }
126:                                 
127:                         }
128:                 });
129:                 
130:         }
131:         
132:         @Override
133:         public void finalizeTask() throws TaskException {
134:                 final Iterator<Tuple<ConstructorReference, Constructor>> references = this.constructorReferences.iterator();
135:                 while (references.hasNext()) {
136:                         final Tuple<ConstructorReference, Constructor> currentReferenceTuple = references.next();
137:                         final ConstructorReference currentReference = currentReferenceTuple.getFirst();
138:                         final Constructor callingConstructor = currentReferenceTuple.getSecond();
139:                         final Iterator<ClassType> constructorOwnersIterator = this.constructorOwners.iterator();
140:                         boolean matchFound = false;
141:                         while (!matchFound && constructorOwnersIterator.hasNext()) {
142:                                 final ClassType currentConstructorOwner = constructorOwnersIterator.next();
143:                                 matchFound =
144:                                                 this.replaceReferenceWithRealConstructorIfMatchFound(
145:                                                                 currentConstructorOwner,
146:                                                                 callingConstructor,
147:                                                                 currentReference);
148:                         }
149:                         if (!matchFound) {
150:                                 this.exceptions.add(ConstructorReferenceMismatchException.create(currentReference.getFirstToken()));
151:                         }
152:                 }
153:                 if (!this.exceptions.isEmpty()) {
154:                         throw ConstructorReferencerExceptions.create(this.exceptions);
155:                 }
156:         }
157:         
158:         /**
159:          * Tries to find exactly one match between reference, if it has only a type and the list of parameters, and one of
160:          * constructorOwners constructors and replaces reference in callingConstructor with the matched constructor. Returns
161:          * true if the above applies. Adds a DuplicateConstructorException to exceptions if more than one match is being
162:          * found.
163:          *
164:          * @param constructorOwner
165:          * a class with a list of constructors to match
166:          * @param callingConstructor
167:          * the constructor that references another constructor
168:          * @param reference
169:          * the reference to replace with a real constructor.
170:          * @return true if one or more matching constructors have been found (Regardless of the fact that this "causes" an
171:          * exception). Otherwise false.
172:          */
173:         private boolean replaceReferenceWithRealConstructorIfMatchFound(final ClassType constructorOwner,
174:                         final Constructor callingConstructor,
175:                         final ConstructorReference reference) {
176:                 
177:                 return reference.getState().accept(new ConstructorReferenceStateVisitorReturn<Boolean>() {
178:                         
179:                         @Override
180:                         public Boolean handle(final ConstructorByTypeAndSignatureState byName) {
181:                                 boolean matchFound = false;
182:                                 final Collection<Constructor> matchedConstuctors = constructorOwner.getMatchingConstructors(byName);
183:                                 matchFound = !matchedConstuctors.isEmpty();
184:                                 if (matchedConstuctors.size() == ConstructorReferencer.MINIMUM_OF_CONSTRUCTOR_INSTANCES_NEEDED_TO_MATCH_A_REFERENCE
185:                                                 && !ConstructorReferencer.this.constructorCycle(callingConstructor, matchedConstuctors)) {
186:                                         reference.setState(ConstructorByReferenceState.create(
187:                                                         matchedConstuctors.iterator().next(),
188:                                                         constructorOwner));
189:                                 } else if (matchedConstuctors.size() > ConstructorReferencer.MAXIMUM_OF_CONSTRUCTOR_INSTANCES_ALLOWED_TO_MATCH_A_REFERENCE) {
190:                                         ConstructorReferencer.this.exceptions.add(DuplicateConstructorException.create(
191:                                                         matchedConstuctors,
192:                                                         callingConstructor.getFirstToken()));
193:                                 }
194:                                 return matchFound;
195:                         }
196:                         
197:                         @Override
198:                         public Boolean handle(final ConstructorInvalidState invalid) {
199:                                 // nothing to do
200:                                 return false;
201:                         }
202:                         
203:                         @Override
204:                         public Boolean handle(final ConstructorByReferenceState byReference) {
205:                                 // nothing to do
206:                                 return false;
207:                         }
208:                 });
209:                 
210:         }
211:         
212:         /**
213:          * Returns true if callingConstructor is part of matchedConstructors. Adds a CyclicConstructorCallException to
214:          * exceptions and returns false otherwise.
215:          *
216:          * @param callingConstructor
217:          * the constructor search for within matchedConstructors.
218:          * @param matchedConstuctors
219:          * matchedConstructors.
220:          * @return a boolean as stated above.
221:          */
222:         private boolean constructorCycle(final Constructor callingConstructor,
223:                         final Collection<Constructor> matchedConstuctors) {
224:                 final boolean result = matchedConstuctors.contains(callingConstructor);
225:                 if (result) {
226:                         this.exceptions.add(CyclicConstructorCallException.create(
227:                                         callingConstructor,
228:                                         callingConstructor.getFirstToken()));
229:                 }
230:                 return result;
231:         }
232:         
233:         @Override
234:         public void beginTask() throws TaskException {
235:                 // Nothing to do.
236:         }
237:         
238: }