1 /*******************************************************************************
2  * Copyright (c) 2000, 2016 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.typeconstraints.types;
15 
16 import org.eclipse.core.runtime.Assert;
17 
18 import org.eclipse.jdt.core.dom.ITypeBinding;
19 
20 
21 public final class ArrayType extends TType {
22 	private TType fElementType;
23 	private int fDimensions;
24 
25 	private TType fErasure;
26 
ArrayType(TypeEnvironment environment)27 	protected ArrayType(TypeEnvironment environment) {
28 		super(environment);
29 	}
30 
ArrayType(TypeEnvironment environment, String key)31 	protected ArrayType(TypeEnvironment environment, String key) {
32 		super(environment, key);
33 	}
34 
initialize(ITypeBinding binding, TType elementType)35 	protected void initialize(ITypeBinding binding, TType elementType) {
36 		Assert.isTrue(binding.isArray());
37 		super.initialize(binding);
38 		fElementType= elementType;
39 		fDimensions= binding.getDimensions();
40 		if (fElementType.isStandardType() || fElementType.isGenericType() || fElementType.isPrimitiveType()) {
41 			fErasure= this;
42 		} else {
43 			fErasure= getEnvironment().create(binding.getErasure());
44 		}
45 	}
46 
initialize(TType elementType, int dimensions)47 	protected void initialize(TType elementType, int dimensions) {
48 		fElementType= elementType;
49 		fDimensions= dimensions;
50 		if (fElementType.isStandardType() || fElementType.isGenericType() || fElementType.isPrimitiveType()) {
51 			fErasure= this;
52 		} else {
53 			fErasure= getEnvironment().createArrayType(elementType.getErasure(), dimensions);
54 		}
55 	}
56 
getElementType()57 	public TType getElementType() {
58 		return fElementType;
59 	}
60 
61 	/**
62 	 * Returns the component type of this array.
63 	 * If getDimensions() is 1, the component type is the element type.
64 	 * If getDimensions() is > 1, the component type is an array type
65 	 * with element type getElementType() and dimensions getDimensions() - 1.
66 	 *
67 	 * @return the component type
68 	 */
getComponentType()69 	public TType getComponentType() {
70 		if (fDimensions > 1)
71 			return getEnvironment().createArrayType(fElementType, fDimensions - 1);
72 		else
73 			return fElementType;
74 	}
75 
getDimensions()76 	public int getDimensions() {
77 		return fDimensions;
78 	}
79 
80 	@Override
getKind()81 	public int getKind() {
82 		return ARRAY_TYPE;
83 	}
84 
85 	@Override
getSubTypes()86 	public TType[] getSubTypes() {
87 		TType[] subTypes= fElementType.getSubTypes();
88 		TType[] result= new TType[subTypes.length];
89 		for (int i= 0; i < subTypes.length; i++) {
90 			result[i]= getEnvironment().createArrayType(subTypes[i], fDimensions);
91 		}
92 		return result;
93 	}
94 
95 	@Override
getErasure()96 	public TType getErasure() {
97 		return fErasure;
98 	}
99 
100 	@Override
doEquals(TType other)101 	public boolean doEquals(TType other) {
102 		ArrayType arrayType= (ArrayType)other;
103 		return fElementType.equals(arrayType.fElementType) && fDimensions == arrayType.fDimensions;
104 	}
105 
106 	@Override
hashCode()107 	public int hashCode() {
108 		return fElementType.hashCode() << ARRAY_TYPE_SHIFT;
109 	}
110 
111 	@Override
doCanAssignTo(TType lhs)112 	protected boolean doCanAssignTo(TType lhs) {
113 		switch (lhs.getKind()) {
114 			case NULL_TYPE: return false;
115 			case VOID_TYPE: return false;
116 			case PRIMITIVE_TYPE: return false;
117 
118 			case ARRAY_TYPE: return canAssignToArrayType((ArrayType)lhs);
119 
120 			case GENERIC_TYPE: return false;
121 			case STANDARD_TYPE: return isArrayLhsCompatible(lhs);
122 			case PARAMETERIZED_TYPE: return false;
123 			case RAW_TYPE: return false;
124 
125 			case UNBOUND_WILDCARD_TYPE:
126 			case EXTENDS_WILDCARD_TYPE:
127 			case SUPER_WILDCARD_TYPE:
128 				return ((WildcardType)lhs).checkAssignmentBound(this);
129 
130 			case TYPE_VARIABLE: return false;
131 			case CAPTURE_TYPE:
132 				return ((CaptureType)lhs).checkLowerBound(this);
133 		}
134 		return false;
135 	}
136 
canAssignToArrayType(ArrayType lhs)137 	private boolean canAssignToArrayType(ArrayType lhs) {
138 		if (fDimensions == lhs.fDimensions) {
139 			// primitive type don't have any conversion for arrays.
140 			if (fElementType.getKind() == PRIMITIVE_TYPE || lhs.fElementType.getKind() == PRIMITIVE_TYPE)
141 				return fElementType.isTypeEquivalentTo(lhs.fElementType);
142 			return fElementType.canAssignTo(lhs.fElementType);
143 		}
144 		if (fDimensions < lhs.fDimensions)
145 			return false;
146 		return isArrayLhsCompatible(lhs.fElementType);
147 	}
148 
isArrayLhsCompatible(TType lhsElementType)149 	private boolean isArrayLhsCompatible(TType lhsElementType) {
150 		return lhsElementType.isJavaLangObject() || lhsElementType.isJavaLangCloneable() || lhsElementType.isJavaIoSerializable();
151 	}
152 
153 	@Override
getPlainPrettySignature()154 	protected String getPlainPrettySignature() {
155 		StringBuilder result= new StringBuilder(fElementType.getPlainPrettySignature());
156 		for (int i= 0; i < fDimensions; i++) {
157 			result.append("[]"); //$NON-NLS-1$
158 		}
159 		return result.toString();
160 	}
161 
162 	@Override
getName()163 	public String getName() {
164 		StringBuilder result= new StringBuilder(fElementType.getName());
165 		for (int i= 0; i < fDimensions; i++) {
166 			result.append("[]"); //$NON-NLS-1$
167 		}
168 		return result.toString();
169 	}
170 
171 }
172