1 /*******************************************************************************
2  * Copyright (c) 2000, 2011 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.jdt.internal.corext.refactoring.structure.constraints;
15 
16 import org.eclipse.core.runtime.Assert;
17 
18 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.HierarchyType;
19 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType;
20 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeSet;
21 
22 /**
23  * Optimized type sets for supertype constraint problems.
24  */
25 public abstract class SuperTypeSet implements ITypeSet {
26 
27 	/** Implementation of an empty set */
28 	private static class SuperTypeEmptySet extends SuperTypeSet {
29 
30 		/*
31 		 * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeSet#chooseSingleType()
32 		 */
33 		@Override
chooseSingleType()34 		public final TType chooseSingleType() {
35 			return null;
36 		}
37 
38 		/*
39 		 * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeSet#isEmpty()
40 		 */
41 		@Override
isEmpty()42 		public final boolean isEmpty() {
43 			return true;
44 		}
45 
46 		/*
47 		 * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeSet#restrictedTo(org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeSet)
48 		 */
49 		@Override
restrictedTo(final ITypeSet set)50 		public final ITypeSet restrictedTo(final ITypeSet set) {
51 			return this;
52 		}
53 
54 		/*
55 		 * @see java.lang.Object#toString()
56 		 */
57 		@Override
toString()58 		public final String toString() {
59 			return "EMPTY"; //$NON-NLS-1$
60 		}
61 	}
62 
63 	/** Implementation of a singleton */
64 	private static class SuperTypeSingletonSet extends SuperTypeSet {
65 
66 		/** The type */
67 		private final TType fType;
68 
69 		/**
70 		 * Creates a new super type singleton set.
71 		 *
72 		 * @param type the type
73 		 */
SuperTypeSingletonSet(final TType type)74 		private SuperTypeSingletonSet(final TType type) {
75 			fType= type;
76 		}
77 
78 		/*
79 		 * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeSet#chooseSingleType()
80 		 */
81 		@Override
chooseSingleType()82 		public final TType chooseSingleType() {
83 			return fType;
84 		}
85 
86 		/*
87 		 * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeSet#isEmpty()
88 		 */
89 		@Override
isEmpty()90 		public final boolean isEmpty() {
91 			return false;
92 		}
93 
94 		/*
95 		 * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeSet#restrictedTo(org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeSet)
96 		 */
97 		@Override
restrictedTo(final ITypeSet set)98 		public final ITypeSet restrictedTo(final ITypeSet set) {
99 			final TType leftErasure= fType.getErasure();
100 			if (set instanceof SuperTypeUniverse) {
101 				return this;
102 			} else if (set instanceof SuperTypeSingletonSet) {
103 				if (this == set)
104 					return this;
105 				if (fType.isNullType())
106 					return this;
107 				final SuperTypeSingletonSet singleton= (SuperTypeSingletonSet) set;
108 				final TType rightErasure= singleton.fType.getErasure();
109 				if (leftErasure.isHierarchyType() && rightErasure.isHierarchyType()) {
110 					if (leftErasure.isGenericType() || rightErasure.isGenericType()) {
111 						if (rightErasure.equals(leftErasure) || ((HierarchyType) leftErasure).isSubType((HierarchyType) rightErasure))
112 							return this;
113 					}
114 				}
115 				if (rightErasure.isJavaLangObject())
116 					return this;
117 				if (leftErasure.canAssignTo(rightErasure))
118 					return this;
119 				return SuperTypeSet.getEmpty();
120 			} else if (set instanceof SuperTypeTuple) {
121 				if (fType.isNullType())
122 					return this;
123 				final SuperTypeTuple tuple= (SuperTypeTuple) set;
124 				final TType rightErasure= tuple.fSuperType.getErasure();
125 				if (leftErasure.isHierarchyType() && rightErasure.isHierarchyType()) {
126 					if (leftErasure.isGenericType() || rightErasure.isGenericType()) {
127 						if (rightErasure.equals(leftErasure) || ((HierarchyType) leftErasure).isSubType((HierarchyType) rightErasure))
128 							return this;
129 					}
130 				}
131 				if (rightErasure.isJavaLangObject())
132 					return this;
133 				if (leftErasure.canAssignTo(rightErasure))
134 					return this;
135 				return SuperTypeSet.createTypeSet(tuple.fSubType);
136 			} else if (set instanceof SuperTypeEmptySet) {
137 				return set;
138 			} else
139 				Assert.isTrue(false);
140 			return null;
141 		}
142 
143 		/*
144 		 * @see java.lang.Object#toString()
145 		 */
146 		@Override
toString()147 		public final String toString() {
148 			return fType.getPrettySignature();
149 		}
150 	}
151 
152 	/** Implementation of a tuple */
153 	private static class SuperTypeTuple extends SuperTypeSet {
154 
155 		/** The other type */
156 		private final TType fSubType;
157 
158 		/** The super type */
159 		private final TType fSuperType;
160 
161 		/**
162 		 * Creates a new super type tuple.
163 		 *
164 		 * @param subType the sub type
165 		 * @param superType the super type
166 		 */
SuperTypeTuple(final TType subType, final TType superType)167 		private SuperTypeTuple(final TType subType, final TType superType) {
168 			fSubType= subType;
169 			fSuperType= superType;
170 		}
171 
172 		/*
173 		 * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeSet#chooseSingleType()
174 		 */
175 		@Override
chooseSingleType()176 		public final TType chooseSingleType() {
177 			return fSuperType;
178 		}
179 
180 		/*
181 		 * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeSet#isEmpty()
182 		 */
183 		@Override
isEmpty()184 		public final boolean isEmpty() {
185 			return false;
186 		}
187 
188 		/*
189 		 * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeSet#restrictedTo(org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeSet)
190 		 */
191 		@Override
restrictedTo(final ITypeSet set)192 		public final ITypeSet restrictedTo(final ITypeSet set) {
193 			if (set instanceof SuperTypeUniverse) {
194 				return this;
195 			} else if (set instanceof SuperTypeSingletonSet) {
196 				final SuperTypeSingletonSet singleton= (SuperTypeSingletonSet) set;
197 				final TType rightErasure= singleton.fType.getErasure();
198 				final TType subErasure= fSubType.getErasure();
199 				final TType superErasure= fSuperType.getErasure();
200 				if (subErasure.isHierarchyType() && superErasure.isHierarchyType() && rightErasure.isHierarchyType()) {
201 					if (subErasure.isGenericType() || superErasure.isGenericType() || rightErasure.isGenericType()) {
202 						if ((rightErasure.equals(subErasure) || ((HierarchyType) subErasure).isSubType((HierarchyType) rightErasure))
203 								&& (rightErasure.equals(superErasure) || ((HierarchyType) superErasure).isSubType((HierarchyType) rightErasure)))
204 							return this;
205 					}
206 				}
207 				if (rightErasure.isJavaLangObject())
208 					return this;
209 				if (subErasure.canAssignTo(rightErasure) && superErasure.canAssignTo(rightErasure))
210 					return this;
211 				return SuperTypeSet.createTypeSet(fSubType);
212 			} else if (set instanceof SuperTypeTuple) {
213 				return this;
214 			} else if (set instanceof SuperTypeEmptySet) {
215 				return set;
216 			} else
217 				Assert.isTrue(false);
218 			return null;
219 		}
220 
221 		/*
222 		 * @see java.lang.Object#toString()
223 		 */
224 		@Override
toString()225 		public final String toString() {
226 			return "[" + fSubType.getPrettySignature() + ", " + fSuperType.getPrettySignature() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
227 		}
228 	}
229 
230 	/** Implementation of the type universe */
231 	private static class SuperTypeUniverse extends SuperTypeSet {
232 
233 		/*
234 		 * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeSet#chooseSingleType()
235 		 */
236 		@Override
chooseSingleType()237 		public final TType chooseSingleType() {
238 			return null;
239 		}
240 
241 		/*
242 		 * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeSet#isEmpty()
243 		 */
244 		@Override
isEmpty()245 		public final boolean isEmpty() {
246 			return false;
247 		}
248 
249 		/*
250 		 * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeSet#restrictedTo(org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeSet)
251 		 */
252 		@Override
restrictedTo(final ITypeSet set)253 		public final ITypeSet restrictedTo(final ITypeSet set) {
254 			return set;
255 		}
256 
257 		/*
258 		 * @see java.lang.Object#toString()
259 		 */
260 		@Override
toString()261 		public final String toString() {
262 			return "UNIVERSE"; //$NON-NLS-1$
263 		}
264 	}
265 
266 	/** The empty set */
267 	private static final ITypeSet fgEmpty= new SuperTypeEmptySet();
268 
269 	/** The universe */
270 	private static final ITypeSet fgUniverse= new SuperTypeUniverse();
271 
272 	/**
273 	 * Creates a new type set.
274 	 *
275 	 * @param type the type to contain, or <code>null</code>
276 	 * @return the type set, or the universe if <code>type</code> is <code>null</code>
277 	 */
createTypeSet(final TType type)278 	public static ITypeSet createTypeSet(final TType type) {
279 		if (type == null)
280 			return fgUniverse;
281 		return new SuperTypeSingletonSet(type);
282 	}
283 
284 	/**
285 	 * Creates a new type set.
286 	 *
287 	 * @param subType the sub type
288 	 * @param superType the super type
289 	 * @return the type set, or the universe if <code>type</code> is <code>null</code>
290 	 */
createTypeSet(final TType subType, final TType superType)291 	public static ITypeSet createTypeSet(final TType subType, final TType superType) {
292 		if (subType == null || superType == null)
293 			return fgUniverse;
294 		return new SuperTypeTuple(subType, superType);
295 	}
296 
297 	/**
298 	 * Returns the empty set.
299 	 *
300 	 * @return the empty set
301 	 */
getEmpty()302 	public static ITypeSet getEmpty() {
303 		return fgEmpty;
304 	}
305 
306 	/**
307 	 * Returns the universe set.
308 	 *
309 	 * @return the universe set
310 	 */
getUniverse()311 	public static ITypeSet getUniverse() {
312 		return fgUniverse;
313 	}
314 
SuperTypeSet()315 	private SuperTypeSet() {
316 	}
317 }
318