View Javadoc
1   package de.fhdw.wtf.walker.tasks;
2   
3   import java.util.ArrayList;
4   import java.util.Collection;
5   import java.util.HashMap;
6   import java.util.Iterator;
7   import java.util.LinkedList;
8   import java.util.Map;
9   
10  import de.fhdw.wtf.common.ast.Attribute;
11  import de.fhdw.wtf.common.ast.Constructor;
12  import de.fhdw.wtf.common.ast.ConstructorOrOperation;
13  import de.fhdw.wtf.common.ast.Group;
14  import de.fhdw.wtf.common.ast.Model;
15  import de.fhdw.wtf.common.ast.Name;
16  import de.fhdw.wtf.common.ast.Operation;
17  import de.fhdw.wtf.common.ast.type.ClassType;
18  import de.fhdw.wtf.common.ast.type.ProductElementType;
19  import de.fhdw.wtf.common.ast.visitor.ConstructorOrOperationExceptionVisitor;
20  import de.fhdw.wtf.common.exception.walker.DuplicateConstructorException;
21  import de.fhdw.wtf.common.exception.walker.InvalidOverloadingException;
22  import de.fhdw.wtf.common.exception.walker.TaskException;
23  import de.fhdw.wtf.common.task.TaskExecutor;
24  import de.fhdw.wtf.walker.walker.SimpleWalkerTask;
25  
26  /**
27   * This Task check that operations, which have the same name, are different in their parametertypes! So it only allowes
28   * correct overloading.
29   * 
30   * This Checker must run after the {@link PrototypesTask}.
31   */
32  public final class OverloadingCheck extends SimpleWalkerTask {
33  	
34  	/**
35  	 * Map from Name of a class to their already found list of operation.
36  	 */
37  	private final Map<Name, Collection<Operation>> classOperationMap;
38  	
39  	/**
40  	 * This list contains {@link ClassType} instances and those {@link Constructor} instances that have already been
41  	 * found.
42  	 */
43  	private final Map<ClassType, Collection<Constructor>> previouslyFoundConstructors;
44  	
45  	/**
46  	 * Constructor of {@link OverloadingCheck}.
47  	 * 
48  	 * @param m
49  	 *            model
50  	 * @param taskmanager
51  	 *            taskmanager
52  	 */
53  	private OverloadingCheck(final Model m, final TaskExecutor taskmanager) {
54  		super(m, taskmanager);
55  		this.classOperationMap = new HashMap<>();
56  		this.previouslyFoundConstructors = new HashMap<>();
57  	}
58  	
59  	/**
60  	 * Creates a {@link OverloadingCheck}-Object.
61  	 * 
62  	 * @param m
63  	 *            model
64  	 * @param taskmanager
65  	 *            taskmanager
66  	 * @return The {@link OverloadingCheck}-Object.
67  	 */
68  	public static OverloadingCheck create(final Model m, final TaskExecutor taskmanager) {
69  		return new OverloadingCheck(m, taskmanager);
70  	}
71  	
72  	@Override
73  	public void handleGroup(final Group g) throws TaskException {
74  		// Nothing to do here
75  	}
76  	
77  	@Override
78  	public void handleClass(final ClassType c) throws TaskException {
79  		// Nothing to do here
80  	}
81  	
82  	@Override
83  	public void handleAttribute(final Attribute a, final ClassType owner) throws TaskException {
84  		// Nothing to do here
85  	}
86  	
87  	@Override
88  	public void handleConstructorOrOperation(final ConstructorOrOperation coo, final ClassType owner)
89  			throws TaskException {
90  		coo.accept(new ConstructorOrOperationExceptionVisitor<TaskException>() {
91  			
92  			@Override
93  			public void handleOperation(final Operation operation) throws TaskException {
94  				Collection<Operation> operations = OverloadingCheck.this.classOperationMap.get(owner.getName());
95  				if (operations == null) {
96  					operations = new ArrayList<>();
97  					OverloadingCheck.this.classOperationMap.put(owner.getName(), operations);
98  				}
99  				for (final Operation current : operations) {
100 					if (current.getName().equals(operation.getName())) {
101 						if (current.getParameters().getElements().size() == operation.getParameters().getElements()
102 								.size()) {
103 							boolean isEqual = true;
104 							final Iterator<ProductElementType> iteratorCurrent =
105 									current.getParameters().getPrototype().getElements().iterator();
106 							final Iterator<ProductElementType> iteratorO =
107 									operation.getParameters().getPrototype().getElements().iterator();
108 							while (isEqual && iteratorCurrent.hasNext()) {
109 								isEqual = iteratorCurrent.next().getType().equals(iteratorO.next().getType());
110 							}
111 							if (isEqual) {
112 								throw InvalidOverloadingException.create(
113 										operation.getFirstToken(),
114 										operation.getLastToken());
115 							}
116 						}
117 					}
118 				}
119 				operations.add(operation);
120 				
121 			}
122 			
123 			@Override
124 			public void handleConstructor(final Constructor constructor) throws TaskException {
125 				OverloadingCheck.this.throwDuplicateConstructorExceptionIfExistsAlready(constructor, owner);
126 				OverloadingCheck.this.addConstructorToPreviouslyFoundConstructors(constructor, owner);
127 				
128 			}
129 		});
130 		
131 	}
132 	
133 	@Override
134 	public void finalizeTask() throws TaskException {
135 		// Nothing to do here
136 	}
137 	
138 	@Override
139 	public void beginTask() throws TaskException {
140 		// Nothing to do here
141 	}
142 	
143 	/**
144 	 * Throws a {@link DuplicateConstructorException} exception if a {@link Constructor} instance for the same type and
145 	 * with the same type as constructor exists in the previouslyFoundConstructors map.
146 	 * 
147 	 * @param constructor
148 	 *            the {@link Constructor} instance to check against.
149 	 * @param owner
150 	 *            the {@link ClassType} instance for constructor.
151 	 * @throws DuplicateConstructorException
152 	 *             if the above applies.
153 	 */
154 	private void throwDuplicateConstructorExceptionIfExistsAlready(final Constructor constructor, final ClassType owner)
155 			throws DuplicateConstructorException {
156 		if (this.previouslyFoundConstructors.containsKey(owner)) {
157 			final Iterator<Constructor> previouslyFoundConstructorsIterator =
158 					this.previouslyFoundConstructors.get(owner).iterator();
159 			while (previouslyFoundConstructorsIterator.hasNext()) {
160 				final Constructor current = previouslyFoundConstructorsIterator.next();
161 				if (current.getParameters().equals(constructor.getParameters())) {
162 					throw DuplicateConstructorException.create(constructor);
163 				}
164 			}
165 		}
166 		
167 	}
168 	
169 	/**
170 	 * Adds a new entry for constructor in the collection behind the key owner of the previouslyFoundConstructors map.
171 	 * Adds a new key entry with owner before in case that no key entry for owner has been found.
172 	 * 
173 	 * @param constructor
174 	 *            The new entry for the collection behind owner.
175 	 * @param owner
176 	 *            The type for constructor.
177 	 */
178 	private void addConstructorToPreviouslyFoundConstructors(final Constructor constructor, final ClassType owner) {
179 		if (this.previouslyFoundConstructors.containsKey(owner)) {
180 			this.previouslyFoundConstructors.get(owner).add(constructor);
181 		} else {
182 			final Collection<Constructor> list = new LinkedList<>();
183 			list.add(constructor);
184 			this.previouslyFoundConstructors.put(owner, list);
185 		}
186 		
187 	}
188 	
189 }