1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.ast;
12 
13 import org.eclipse.jdt.core.compiler.CharOperation;
14 import org.eclipse.jdt.internal.compiler.ASTVisitor;
15 import org.eclipse.jdt.internal.compiler.lookup.*;
16 
17 /**
18  * Syntactic representation of a reference to a generic type.
19  * Note that it might also have a dimension.
20  */
21 public class ParameterizedQualifiedTypeReference extends ArrayQualifiedTypeReference {
22 
23 	public TypeReference[][] typeArguments;
24 	private boolean didResolve = false;
25 
26 	/**
27 	 * @param tokens
28 	 * @param dim
29 	 * @param positions
30 	 */
ParameterizedQualifiedTypeReference(char[][] tokens, TypeReference[][] typeArguments, int dim, long[] positions)31 	public ParameterizedQualifiedTypeReference(char[][] tokens, TypeReference[][] typeArguments, int dim, long[] positions) {
32 
33 		super(tokens, dim, positions);
34 		this.typeArguments = typeArguments;
35 	}
checkBounds(Scope scope)36 	public void checkBounds(Scope scope) {
37 		if (this.resolvedType == null) return;
38 
39 		checkBounds(
40 			(ReferenceBinding) this.resolvedType.leafComponentType(),
41 			scope,
42 			this.typeArguments.length - 1);
43 	}
checkBounds(ReferenceBinding type, Scope scope, int index)44 	public void checkBounds(ReferenceBinding type, Scope scope, int index) {
45 		if (type.enclosingType() != null)
46 			checkBounds(type.enclosingType(), scope, index - 1);
47 
48 		if (type.isParameterizedType()) {
49 			ParameterizedTypeBinding parameterizedType = (ParameterizedTypeBinding) type;
50 			ReferenceBinding currentType = parameterizedType.type;
51 			TypeVariableBinding[] typeVariables = currentType.typeVariables();
52 			TypeBinding[] argTypes = parameterizedType.arguments;
53 			if (argTypes != null && typeVariables != null) { // argTypes may be null in error cases
54 				for (int i = 0, argLength = typeVariables.length; i < argLength; i++)
55 				    if (!typeVariables[i].boundCheck(parameterizedType, argTypes[i]))
56 						scope.problemReporter().typeMismatchError(argTypes[i], typeVariables[i], currentType, this.typeArguments[index][i]);
57 			}
58 		}
59 	}
copyDims(int dim)60 	public TypeReference copyDims(int dim){
61 		//return a type reference copy of me with some dimensions
62 		//warning : the new type ref has a null binding
63 		this.dimensions = dim;
64 		return this;
65 	}
66 
67 	/**
68 	 * @return char[][]
69 	 */
getParameterizedTypeName()70 	public char [][] getParameterizedTypeName(){
71 		int length = this.tokens.length;
72 		char[][] qParamName = new char[length][];
73 		for (int i = 0; i < length; i++) {
74 			TypeReference[] arguments = this.typeArguments[i];
75 			if (arguments == null) {
76 				qParamName[i] = this.tokens[i];
77 			} else {
78 				StringBuffer buffer = new StringBuffer(5);
79 				buffer.append(this.tokens[i]);
80 				buffer.append('<');
81 				for (int j = 0, argLength =arguments.length; j < argLength; j++) {
82 					if (j > 0) buffer.append(',');
83 					buffer.append(CharOperation.concatWith(arguments[j].getParameterizedTypeName(), '.'));
84 				}
85 				buffer.append('>');
86 				int nameLength = buffer.length();
87 				qParamName[i] = new char[nameLength];
88 				buffer.getChars(0, nameLength, qParamName[i], 0);
89 			}
90 		}
91 		int dim = this.dimensions;
92 		if (dim > 0) {
93 			char[] dimChars = new char[dim*2];
94 			for (int i = 0; i < dim; i++) {
95 				int index = i*2;
96 				dimChars[index] = '[';
97 				dimChars[index+1] = ']';
98 			}
99 			qParamName[length-1] = CharOperation.concat(qParamName[length-1], dimChars);
100 		}
101 		return qParamName;
102 	}
103 
104 	/* (non-Javadoc)
105      * @see org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference#getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.Scope)
106      */
getTypeBinding(Scope scope)107     protected TypeBinding getTypeBinding(Scope scope) {
108         return null; // not supported here - combined with resolveType(...)
109     }
110 
111     /*
112      * No need to check for reference to raw type per construction
113      */
internalResolveType(Scope scope)114 	private TypeBinding internalResolveType(Scope scope) {
115 
116 		// handle the error here
117 		this.constant = NotAConstant;
118 		if (this.didResolve) { // is a shared type reference which was already resolved
119 			if (this.resolvedType != null && !this.resolvedType.isValidBinding())
120 				return null; // already reported error
121 			return this.resolvedType;
122 		}
123 	    this.didResolve = true;
124 	    Binding binding = scope.getPackage(this.tokens);
125 	    if (binding != null && !binding.isValidBinding()) {
126 	    	this.resolvedType = (ReferenceBinding) binding;
127 			reportInvalidType(scope);
128 			return null;
129 		}
130 
131 	    PackageBinding packageBinding = binding == null ? null : (PackageBinding) binding;
132 	    boolean isClassScope = scope.kind == Scope.CLASS_SCOPE;
133 		boolean typeIsConsistent = true;
134 		ReferenceBinding qualifiedType = null;
135 	    for (int i = packageBinding == null ? 0 : packageBinding.compoundName.length, max = this.tokens.length; i < max; i++) {
136 			findNextTypeBinding(i, scope, packageBinding);
137 			if (!(this.resolvedType.isValidBinding())) {
138 				reportInvalidType(scope);
139 				return null;
140 			}
141 			ReferenceBinding currentType = (ReferenceBinding) this.resolvedType;
142 			if (typeIsConsistent && currentType.isStatic() && qualifiedType != null && (qualifiedType.isParameterizedType() || qualifiedType.isGenericType())) {
143 				scope.problemReporter().staticMemberOfParameterizedType(this, scope.createParameterizedType(currentType, null, qualifiedType));
144 				typeIsConsistent = false;
145 			}
146 			// check generic and arity
147 		    TypeReference[] args = this.typeArguments[i];
148 		    if (args != null) {
149 				int argLength = args.length;
150 				TypeBinding[] argTypes = new TypeBinding[argLength];
151 				boolean argHasError = false;
152 				for (int j = 0; j < argLength; j++) {
153 				    TypeReference arg = args[j];
154 				    TypeBinding argType = isClassScope
155 						? arg.resolveTypeArgument((ClassScope) scope, currentType, j)
156 						: arg.resolveTypeArgument((BlockScope) scope, currentType, j);
157 					if (argType == null) {
158 						argHasError = true;
159 					} else {
160 						argTypes[j] = argType;
161 					}
162 				}
163 				if (argHasError) return null;
164 // TODO (philippe)	if ((this.bits & ASTNode.IsSuperType) != 0)
165 				if (isClassScope)
166 					if (((ClassScope) scope).detectCycle(currentType, this, argTypes))
167 						return null;
168 
169 			    TypeVariableBinding[] typeVariables = currentType.typeVariables();
170 				if (typeVariables == NoTypeVariables) { // check generic
171 					scope.problemReporter().nonGenericTypeCannotBeParameterized(this, currentType, argTypes);
172 					return null;
173 				} else if (argLength != typeVariables.length) { // check arity
174 					scope.problemReporter().incorrectArityForParameterizedType(this, currentType, argTypes);
175 					return null;
176 				}
177 				// check parameterizing non-static member type of raw type
178 				if (typeIsConsistent && !currentType.isStatic() && qualifiedType != null && qualifiedType.isRawType()) {
179 					scope.problemReporter().rawMemberTypeCannotBeParameterized(
180 							this, scope.environment().createRawType(currentType, qualifiedType), argTypes);
181 					typeIsConsistent = false;
182 				}
183 				ParameterizedTypeBinding parameterizedType = scope.createParameterizedType(currentType, argTypes, qualifiedType);
184 				// check argument type compatibility now if not a class scope
185 				if (!isClassScope) // otherwise will do it in Scope.connectTypeVariables()
186 					for (int j = 0; j < argLength; j++)
187 					    if (!typeVariables[j].boundCheck(parameterizedType, argTypes[j]))
188 							scope.problemReporter().typeMismatchError(argTypes[j], typeVariables[j], currentType, args[j]);
189 				qualifiedType = parameterizedType;
190 		    } else {
191 // TODO (philippe)	if ((this.bits & ASTNode.IsSuperType) != 0)
192 				if (isClassScope)
193 					if (((ClassScope) scope).detectCycle(currentType, this, null))
194 						return null;
195 				if (currentType.isGenericType()) {
196 	   			    if (typeIsConsistent && qualifiedType != null && qualifiedType.isParameterizedType()) {
197 						scope.problemReporter().parameterizedMemberTypeMissingArguments(this, scope.createParameterizedType(currentType, null, qualifiedType));
198 						typeIsConsistent = false;
199 					}
200 	   			    qualifiedType = scope.environment().createRawType(currentType, qualifiedType); // raw type
201 				} else {
202 					qualifiedType = (qualifiedType != null && qualifiedType.isParameterizedType())
203 													? scope.createParameterizedType(currentType, null, qualifiedType)
204 													: currentType;
205 				}
206 			}
207 		}
208 		this.resolvedType = qualifiedType;
209 		if (isTypeUseDeprecated(this.resolvedType, scope))
210 			reportDeprecatedType(scope);
211 		// array type ?
212 		if (this.dimensions > 0) {
213 			if (dimensions > 255)
214 				scope.problemReporter().tooManyDimensions(this);
215 			this.resolvedType = scope.createArrayType(this.resolvedType, dimensions);
216 		}
217 		return this.resolvedType;
218 	}
219 
printExpression(int indent, StringBuffer output)220 	public StringBuffer printExpression(int indent, StringBuffer output) {
221 		int length = tokens.length;
222 		for (int i = 0; i < length - 1; i++) {
223 			output.append(tokens[i]);
224 			TypeReference[] typeArgument = typeArguments[i];
225 			if (typeArgument != null) {
226 				output.append('<');//$NON-NLS-1$
227 				int max = typeArgument.length - 1;
228 				for (int j = 0; j < max; j++) {
229 					typeArgument[j].print(0, output);
230 					output.append(", ");//$NON-NLS-1$
231 				}
232 				typeArgument[max].print(0, output);
233 				output.append('>');
234 			}
235 			output.append('.');
236 		}
237 		output.append(tokens[length - 1]);
238 		TypeReference[] typeArgument = typeArguments[length - 1];
239 		if (typeArgument != null) {
240 			output.append('<');//$NON-NLS-1$
241 			int max = typeArgument.length - 1;
242 			for (int j = 0; j < max; j++) {
243 				typeArgument[j].print(0, output);
244 				output.append(", ");//$NON-NLS-1$
245 			}
246 			typeArgument[max].print(0, output);
247 			output.append('>');
248 		}
249 		for (int i= 0 ; i < dimensions ; i++) {
250 			output.append("[]"); //$NON-NLS-1$
251 		}
252 		return output;
253 	}
254 
resolveType(BlockScope scope)255 	public TypeBinding resolveType(BlockScope scope) {
256 	    return internalResolveType(scope);
257 	}
resolveType(ClassScope scope)258 	public TypeBinding resolveType(ClassScope scope) {
259 	    return internalResolveType(scope);
260 	}
traverse(ASTVisitor visitor, BlockScope scope)261 	public void traverse(ASTVisitor visitor, BlockScope scope) {
262 		if (visitor.visit(this, scope)) {
263 			for (int i = 0, max = this.typeArguments.length; i < max; i++) {
264 				if (this.typeArguments[i] != null) {
265 					for (int j = 0, max2 = this.typeArguments[i].length; j < max2; j++) {
266 						this.typeArguments[i][j].traverse(visitor, scope);
267 					}
268 				}
269 			}
270 		}
271 		visitor.endVisit(this, scope);
272 	}
273 
traverse(ASTVisitor visitor, ClassScope scope)274 	public void traverse(ASTVisitor visitor, ClassScope scope) {
275 		if (visitor.visit(this, scope)) {
276 			for (int i = 0, max = this.typeArguments.length; i < max; i++) {
277 				if (this.typeArguments[i] != null) {
278 					for (int j = 0, max2 = this.typeArguments[i].length; j < max2; j++) {
279 						this.typeArguments[i][j].traverse(visitor, scope);
280 					}
281 				}
282 			}
283 		}
284 		visitor.endVisit(this, scope);
285 	}
286 
287 }
288