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.typeconstraints2;
15 
16 import java.util.Iterator;
17 import java.util.Stack;
18 
19 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.AbstractTypeVariable;
20 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.HierarchyType;
21 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType;
22 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TypeVariable;
23 
24 public class TTypes {
25 
26 	private static class AllSupertypesIterator implements Iterator<TType> {
27 		private final Stack<TType> fWorklist;
28 
AllSupertypesIterator(TType type)29 		public AllSupertypesIterator(TType type) {
30 			fWorklist= new Stack<>();
31 			pushSupertypes(type);
32 		}
33 
34 		@Override
hasNext()35 		public boolean hasNext() {
36 			return ! fWorklist.empty();
37 		}
38 
39 		@Override
next()40 		public TType next() {
41 			TType result= fWorklist.pop();
42 			pushSupertypes(result);
43 			return result;
44 		}
45 
pushSupertypes(TType type)46 		private void pushSupertypes(TType type) {
47 			if (type.isJavaLangObject())
48 				return;
49 
50 			if (type.isTypeVariable() || type.isCaptureType()) {
51 				for (TType bound : ((AbstractTypeVariable) type).getBounds()) {
52 					fWorklist.push(bound.getTypeDeclaration());
53 				}
54 
55 			} else {
56 				TType superclass= type.getSuperclass();
57 				if (superclass == null) {
58 					if (type.isInterface())
59 						fWorklist.push(type.getEnvironment().getJavaLangObject());
60 				} else {
61 					fWorklist.push(superclass.getTypeDeclaration());
62 				}
63 				for (TType intf : type.getInterfaces()) {
64 					fWorklist.push(intf.getTypeDeclaration());
65 				}
66 			}
67 		}
68 
69 		@Override
remove()70 		public void remove() {
71 			throw new UnsupportedOperationException();
72 		}
73 	}
74 
75 	private static class AllSubtypesIterator implements Iterator<TType> {
76 		private final Stack<TType> fWorklist;
77 
AllSubtypesIterator(TType type)78 		public AllSubtypesIterator(TType type) {
79 			fWorklist= new Stack<>();
80 			fWorklist.push(type.getTypeDeclaration());
81 		}
82 
83 		@Override
hasNext()84 		public boolean hasNext() {
85 			return ! fWorklist.empty();
86 		}
87 
88 		@Override
next()89 		public TType next() {
90 			TType result= fWorklist.pop();
91 			for (TType subType : result.getSubTypes()) {
92 				fWorklist.push(subType.getTypeDeclaration());
93 			}
94 
95 			return result;
96 		}
97 
98 		@Override
remove()99 		public void remove() {
100 			throw new UnsupportedOperationException();
101 		}
102 	}
103 
TTypes()104 	private TTypes() {
105 		// no instances
106 	}
107 
createArrayType(TType elementType, int dimensions)108 	public static TType createArrayType(TType elementType, int dimensions) {
109 		return elementType.getEnvironment().createArrayType(elementType, dimensions);
110 	}
111 
112 	/**
113 	 * @return all subtypes of this type (including this type)
114 	 */
getAllSubTypesIterator(TType type)115 	public static Iterator<TType> getAllSubTypesIterator(TType type) {
116 		return new AllSubtypesIterator(type);
117 	}
118 
119 	/**
120 	 * @return all proper supertypes of this type
121 	 */
getAllSuperTypesIterator(TType type)122 	public static Iterator<TType> getAllSuperTypesIterator(TType type) {
123 		return new AllSupertypesIterator(type);
124 	}
125 
126 	/**
127 	 * @param rhs
128 	 * @param lhs
129 	 * @return <code>true</code> iff an expression of type 'rhs' can be assigned to a variable of type 'lhs'.
130 	 * Type arguments of generic / raw / parameterized types are <b>not</b> considered.
131 	 */
canAssignTo(TType rhs, TType lhs)132 	public static boolean canAssignTo(TType rhs, TType lhs) {
133 		if (rhs.isHierarchyType() && lhs.isHierarchyType()) {
134 			HierarchyType rhsGeneric= (HierarchyType) rhs.getTypeDeclaration();
135 			HierarchyType lhsGeneric= (HierarchyType) lhs.getTypeDeclaration();
136 			return lhs.isJavaLangObject() || rhsGeneric.equals(lhsGeneric) || rhsGeneric.isSubType(lhsGeneric);
137 
138 		} else if (rhs.isTypeVariable()) {
139 			if (rhs.canAssignTo(lhs))
140 				return true;
141 			for (TType bound : ((TypeVariable) rhs).getBounds()) {
142 				if (canAssignTo(bound, lhs)) {
143 					return true;
144 				}
145 			}
146 			return lhs.isJavaLangObject();
147 
148 		} else {
149 			return rhs.canAssignTo(lhs);
150 		}
151 	}
152 
153 }
154