1 /*******************************************************************************
2  * Copyright (c) 2000, 2013 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *     Stephan Herrmann - Contributions for
11  *								bug 342671 - ClassCastException: org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding cannot be cast to org.eclipse.jdt.internal.compiler.lookup.ArrayBinding
12  *								Bug 420894 - ClassCastException in DefaultBindingResolver.resolveType(Type)
13  *								bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis
14  *								Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099
15  *								Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault
16  *								Bug 434600 - Incorrect null analysis error reporting on type parameters
17  *        Andy Clement - Contributions for
18  *                          Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work)
19  *******************************************************************************/
20 package org.eclipse.jdt.internal.compiler.ast;
21 
22 import org.eclipse.jdt.core.compiler.CharOperation;
23 import org.eclipse.jdt.internal.compiler.ASTVisitor;
24 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
25 import org.eclipse.jdt.internal.compiler.impl.Constant;
26 import org.eclipse.jdt.internal.compiler.lookup.*;
27 
28 /**
29  * Syntactic representation of a reference to a generic type.
30  * Note that it might also have a dimension.
31  */
32 public class ParameterizedSingleTypeReference extends ArrayTypeReference {
33 
34 	public TypeReference[] typeArguments;
35 
ParameterizedSingleTypeReference(char[] name, TypeReference[] typeArguments, int dim, long pos)36 	public ParameterizedSingleTypeReference(char[] name, TypeReference[] typeArguments, int dim, long pos){
37 		super(name, dim, pos);
38 		this.originalSourceEnd = this.sourceEnd;
39 		this.typeArguments = typeArguments;
40 		for (int i = 0, max = typeArguments.length; i < max; i++) {
41 			if ((typeArguments[i].bits & ASTNode.HasTypeAnnotations) != 0) {
42 				this.bits |= ASTNode.HasTypeAnnotations;
43 				break;
44 			}
45 		}
46 	}
ParameterizedSingleTypeReference(char[] name, TypeReference[] typeArguments, int dim, Annotation[][] annotationsOnDimensions, long pos)47 	public ParameterizedSingleTypeReference(char[] name, TypeReference[] typeArguments, int dim, Annotation[][] annotationsOnDimensions, long pos) {
48 		this(name, typeArguments, dim, pos);
49 		setAnnotationsOnDimensions(annotationsOnDimensions);
50 		if (annotationsOnDimensions != null) {
51 			this.bits |= ASTNode.HasTypeAnnotations;
52 		}
53 	}
checkBounds(Scope scope)54 	public void checkBounds(Scope scope) {
55 		if (this.resolvedType == null) return;
56 
57 		if (this.resolvedType.leafComponentType() instanceof ParameterizedTypeBinding) {
58 			ParameterizedTypeBinding parameterizedType = (ParameterizedTypeBinding) this.resolvedType.leafComponentType();
59 			ReferenceBinding currentType = parameterizedType.genericType();
60 			TypeVariableBinding[] typeVariables = currentType.typeVariables();
61 			TypeBinding[] argTypes = parameterizedType.arguments;
62 			if (argTypes != null && typeVariables != null) { // may be null in error cases
63 				parameterizedType.boundCheck(scope, this.typeArguments);
64 			}
65 		}
66 		checkNullConstraints(scope, this.typeArguments);
67 	}
68 
augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation [][] additionalAnnotations, boolean isVarargs)69 	public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation [][] additionalAnnotations, boolean isVarargs) {
70 		int totalDimensions = this.dimensions() + additionalDimensions;
71 		Annotation [][] allAnnotations = getMergedAnnotationsOnDimensions(additionalDimensions, additionalAnnotations);
72 		ParameterizedSingleTypeReference parameterizedSingleTypeReference = new ParameterizedSingleTypeReference(this.token, this.typeArguments, totalDimensions, allAnnotations, (((long) this.sourceStart) << 32) + this.sourceEnd);
73 		parameterizedSingleTypeReference.annotations = this.annotations;
74 		parameterizedSingleTypeReference.bits |= (this.bits & ASTNode.HasTypeAnnotations);
75 		if (!isVarargs)
76 			parameterizedSingleTypeReference.extendedDimensions = additionalDimensions;
77 		return parameterizedSingleTypeReference;
78 	}
79 
80 	/**
81 	 * @return char[][]
82 	 */
getParameterizedTypeName()83 	public char [][] getParameterizedTypeName(){
84 		StringBuffer buffer = new StringBuffer(5);
85 		buffer.append(this.token).append('<');
86 		for (int i = 0, length = this.typeArguments.length; i < length; i++) {
87 			if (i > 0) buffer.append(',');
88 			buffer.append(CharOperation.concatWith(this.typeArguments[i].getParameterizedTypeName(), '.'));
89 		}
90 		buffer.append('>');
91 		int nameLength = buffer.length();
92 		char[] name = new char[nameLength];
93 		buffer.getChars(0, nameLength, name, 0);
94 		int dim = this.dimensions;
95 		if (dim > 0) {
96 			char[] dimChars = new char[dim*2];
97 			for (int i = 0; i < dim; i++) {
98 				int index = i*2;
99 				dimChars[index] = '[';
100 				dimChars[index+1] = ']';
101 			}
102 			name = CharOperation.concat(name, dimChars);
103 		}
104 		return new char[][]{ name };
105 	}
106 
getTypeArguments()107 	public TypeReference[][] getTypeArguments() {
108 		return new TypeReference[][] { this.typeArguments };
109 	}
110 
111 	/**
112      * @see org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference#getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.Scope)
113      */
getTypeBinding(Scope scope)114     protected TypeBinding getTypeBinding(Scope scope) {
115         return null; // not supported here - combined with resolveType(...)
116     }
117 
isParameterizedTypeReference()118     public boolean isParameterizedTypeReference() {
119     	return true;
120     }
121 
122     /*
123      * No need to check for reference to raw type per construction
124      */
internalResolveType(Scope scope, ReferenceBinding enclosingType, boolean checkBounds, int location)125 	private TypeBinding internalResolveType(Scope scope, ReferenceBinding enclosingType, boolean checkBounds, int location) {
126 		// handle the error here
127 		this.constant = Constant.NotAConstant;
128 		if ((this.bits & ASTNode.DidResolve) != 0) { // is a shared type reference which was already resolved
129 			if (this.resolvedType != null) { // is a shared type reference which was already resolved
130 				if (this.resolvedType.isValidBinding()) {
131 					return this.resolvedType;
132 				} else {
133 					switch (this.resolvedType.problemId()) {
134 						case ProblemReasons.NotFound :
135 						case ProblemReasons.NotVisible :
136 						case ProblemReasons.InheritedNameHidesEnclosingName :
137 							TypeBinding type = this.resolvedType.closestMatch();
138 							return type;
139 						default :
140 							return null;
141 					}
142 				}
143 			}
144 		}
145 		this.bits |= ASTNode.DidResolve;
146 		TypeBinding type = internalResolveLeafType(scope, enclosingType, checkBounds);
147 
148 		// handle three different outcomes:
149 		if (type == null) {
150 			this.resolvedType = createArrayType(scope, this.resolvedType);
151 			resolveAnnotations(scope, 0); // no defaultNullness for buggy type
152 			if (checkBounds)
153 				checkNullConstraints(scope, this.typeArguments);
154 			return null;							// (1) no useful type, but still captured dimensions into this.resolvedType
155 		} else {
156 			type = createArrayType(scope, type);
157 			if (!this.resolvedType.isValidBinding() && this.resolvedType.dimensions() == type.dimensions()) {
158 				resolveAnnotations(scope, 0); // no defaultNullness for buggy type
159 				if (checkBounds)
160 					checkNullConstraints(scope, this.typeArguments);
161 				return type;						// (2) found some error, but could recover useful type (like closestMatch)
162 			} else {
163 				this.resolvedType = type; 			// (3) no complaint, keep fully resolved type (incl. dimensions)
164 				resolveAnnotations(scope, location);
165 				if (checkBounds)
166 					checkNullConstraints(scope, this.typeArguments);
167 				return this.resolvedType; // pick up any annotated type.
168 			}
169 		}
170 	}
internalResolveLeafType(Scope scope, ReferenceBinding enclosingType, boolean checkBounds)171 	private TypeBinding internalResolveLeafType(Scope scope, ReferenceBinding enclosingType, boolean checkBounds) {
172 		ReferenceBinding currentType;
173 		if (enclosingType == null) {
174 			this.resolvedType = scope.getType(this.token);
175 			if (this.resolvedType.isValidBinding()) {
176 				currentType = (ReferenceBinding) this.resolvedType;
177 			} else {
178 				reportInvalidType(scope);
179 				switch (this.resolvedType.problemId()) {
180 					case ProblemReasons.NotFound :
181 					case ProblemReasons.NotVisible :
182 					case ProblemReasons.InheritedNameHidesEnclosingName :
183 						TypeBinding type = this.resolvedType.closestMatch();
184 						if (type instanceof ReferenceBinding) {
185 							currentType = (ReferenceBinding) type;
186 							break;
187 						}
188 						//$FALL-THROUGH$ - unable to complete type binding, but still resolve type arguments
189 					default :
190 						boolean isClassScope = scope.kind == Scope.CLASS_SCOPE;
191 					int argLength = this.typeArguments.length;
192 					for (int i = 0; i < argLength; i++) {
193 						TypeReference typeArgument = this.typeArguments[i];
194 						if (isClassScope) {
195 							typeArgument.resolveType((ClassScope) scope);
196 						} else {
197 							typeArgument.resolveType((BlockScope) scope, checkBounds);
198 						}
199 					}
200 					return null;
201 				}
202 				// be resilient, still attempt resolving arguments
203 			}
204 			enclosingType = currentType.enclosingType(); // if member type
205 			if (enclosingType != null) {
206 				enclosingType = currentType.isStatic()
207 					? (ReferenceBinding) scope.environment().convertToRawType(enclosingType, false /*do not force conversion of enclosing types*/)
208 					: scope.environment().convertToParameterizedType(enclosingType);
209 				currentType = scope.environment().createParameterizedType((ReferenceBinding) currentType.erasure(), null /* no arg */, enclosingType);
210 			}
211 		} else { // resolving member type (relatively to enclosingType)
212 			this.resolvedType = currentType = scope.getMemberType(this.token, enclosingType);
213 			if (!this.resolvedType.isValidBinding()) {
214 				scope.problemReporter().invalidEnclosingType(this, currentType, enclosingType);
215 				return null;
216 			}
217 			if (isTypeUseDeprecated(currentType, scope))
218 				scope.problemReporter().deprecatedType(currentType, this);
219 			ReferenceBinding currentEnclosing = currentType.enclosingType();
220 			if (currentEnclosing != null && TypeBinding.notEquals(currentEnclosing.erasure(), enclosingType.erasure())) {
221 				enclosingType = currentEnclosing; // inherited member type, leave it associated with its enclosing rather than subtype
222 			}
223 		}
224 
225 		// check generic and arity
226 	    boolean isClassScope = scope.kind == Scope.CLASS_SCOPE;
227 	    TypeReference keep = null;
228 	    if (isClassScope) {
229 	    	keep = ((ClassScope) scope).superTypeReference;
230 	    	((ClassScope) scope).superTypeReference = null;
231 	    }
232 	    final boolean isDiamond = (this.bits & ASTNode.IsDiamond) != 0;
233 		int argLength = this.typeArguments.length;
234 		TypeBinding[] argTypes = new TypeBinding[argLength];
235 		boolean argHasError = false;
236 		ReferenceBinding currentOriginal = (ReferenceBinding)currentType.original();
237 		for (int i = 0; i < argLength; i++) {
238 		    TypeReference typeArgument = this.typeArguments[i];
239 		    TypeBinding argType = isClassScope
240 				? typeArgument.resolveTypeArgument((ClassScope) scope, currentOriginal, i)
241 				: typeArgument.resolveTypeArgument((BlockScope) scope, currentOriginal, i);
242 			this.bits |= (typeArgument.bits & ASTNode.HasTypeAnnotations);
243 		     if (argType == null) {
244 		         argHasError = true;
245 		     } else {
246 		    	 argTypes[i] = argType;
247 		     }
248 		}
249 		if (argHasError) {
250 			return null;
251 		}
252 		if (isClassScope) {
253 	    	((ClassScope) scope).superTypeReference = keep;
254 			if (((ClassScope) scope).detectHierarchyCycle(currentOriginal, this))
255 				return null;
256 		}
257 
258 		TypeVariableBinding[] typeVariables = currentOriginal.typeVariables();
259 		if (typeVariables == Binding.NO_TYPE_VARIABLES) { // non generic invoked with arguments
260 			boolean isCompliant15 = scope.compilerOptions().originalSourceLevel >= ClassFileConstants.JDK1_5;
261 			if ((currentOriginal.tagBits & TagBits.HasMissingType) == 0) {
262 				if (isCompliant15) { // below 1.5, already reported as syntax error
263 					this.resolvedType = currentType;
264 					scope.problemReporter().nonGenericTypeCannotBeParameterized(0, this, currentType, argTypes);
265 					return null;
266 				}
267 			}
268 			// resilience do not rebuild a parameterized type unless compliance is allowing it
269 			if (!isCompliant15) {
270 				if (!this.resolvedType.isValidBinding())
271 					return currentType;
272 				return this.resolvedType = currentType;
273 			}
274 			// if missing generic type, and compliance >= 1.5, then will rebuild a parameterized binding
275 		} else if (argLength != typeVariables.length) {
276 			if (!isDiamond) { // check arity, IsDiamond never set for 1.6-
277 				scope.problemReporter().incorrectArityForParameterizedType(this, currentType, argTypes);
278 				return null;
279 			}
280 		} else if (!currentType.isStatic()) {
281 			ReferenceBinding actualEnclosing = currentType.enclosingType();
282 			if (actualEnclosing != null && actualEnclosing.isRawType()){
283 				scope.problemReporter().rawMemberTypeCannotBeParameterized(
284 						this, scope.environment().createRawType(currentOriginal, actualEnclosing), argTypes);
285 				return null;
286 			}
287 		}
288 
289     	ParameterizedTypeBinding parameterizedType = scope.environment().createParameterizedType(currentOriginal, argTypes, enclosingType);
290 		// check argument type compatibility for non <> cases - <> case needs no bounds check, we will scream foul if needed during inference.
291     	if (!isDiamond) {
292     		if (checkBounds) // otherwise will do it in Scope.connectTypeVariables() or generic method resolution
293     			parameterizedType.boundCheck(scope, this.typeArguments);
294     		else
295     			scope.deferBoundCheck(this);
296     	}
297 		if (isTypeUseDeprecated(parameterizedType, scope))
298 			reportDeprecatedType(parameterizedType, scope);
299 
300 		if (!this.resolvedType.isValidBinding()) {
301 			return parameterizedType;
302 		}
303 		return this.resolvedType = parameterizedType;
304 	}
createArrayType(Scope scope, TypeBinding type)305 	private TypeBinding createArrayType(Scope scope, TypeBinding type) {
306 		if (this.dimensions > 0) {
307 			if (this.dimensions > 255)
308 				scope.problemReporter().tooManyDimensions(this);
309 			return scope.createArrayType(type, this.dimensions);
310 		}
311 		return type;
312 	}
313 
printExpression(int indent, StringBuffer output)314 	public StringBuffer printExpression(int indent, StringBuffer output){
315 		if (this.annotations != null && this.annotations[0] != null) {
316 			printAnnotations(this.annotations[0], output);
317 			output.append(' ');
318 		}
319 		output.append(this.token);
320 		output.append("<"); //$NON-NLS-1$
321 		int length = this.typeArguments.length;
322 		if (length > 0) {
323 			int max = length - 1;
324 			for (int i= 0; i < max; i++) {
325 				this.typeArguments[i].print(0, output);
326 				output.append(", ");//$NON-NLS-1$
327 			}
328 			this.typeArguments[max].print(0, output);
329 		}
330 		output.append(">"); //$NON-NLS-1$
331 		Annotation [][] annotationsOnDimensions = getAnnotationsOnDimensions();
332 		if ((this.bits & IsVarArgs) != 0) {
333 			for (int i= 0 ; i < this.dimensions - 1; i++) {
334 				if (annotationsOnDimensions != null && annotationsOnDimensions[i] != null) {
335 					output.append(" "); //$NON-NLS-1$
336 					printAnnotations(annotationsOnDimensions[i], output);
337 					output.append(" "); //$NON-NLS-1$
338 				}
339 				output.append("[]"); //$NON-NLS-1$
340 			}
341 			if (annotationsOnDimensions != null && annotationsOnDimensions[this.dimensions - 1] != null) {
342 				output.append(" "); //$NON-NLS-1$
343 				printAnnotations(annotationsOnDimensions[this.dimensions - 1], output);
344 				output.append(" "); //$NON-NLS-1$
345 			}
346 			output.append("..."); //$NON-NLS-1$
347 		} else {
348 			for (int i= 0 ; i < this.dimensions; i++) {
349 				if (annotationsOnDimensions != null && annotationsOnDimensions[i] != null) {
350 					output.append(" "); //$NON-NLS-1$
351 					printAnnotations(annotationsOnDimensions[i], output);
352 					output.append(" "); //$NON-NLS-1$
353 				}
354 				output.append("[]"); //$NON-NLS-1$
355 			}
356 		}
357 		return output;
358 	}
359 
resolveType(BlockScope scope, boolean checkBounds, int location)360 	public TypeBinding resolveType(BlockScope scope, boolean checkBounds, int location) {
361 	    return internalResolveType(scope, null, checkBounds, location);
362 	}
363 
resolveType(ClassScope scope, int location)364 	public TypeBinding resolveType(ClassScope scope, int location) {
365 	    return internalResolveType(scope, null, false /*no bounds check in classScope*/, location);
366 	}
367 
resolveTypeEnclosing(BlockScope scope, ReferenceBinding enclosingType)368 	public TypeBinding resolveTypeEnclosing(BlockScope scope, ReferenceBinding enclosingType) {
369 	    return internalResolveType(scope, enclosingType, true/*check bounds*/, 0);
370 	}
371 
traverse(ASTVisitor visitor, BlockScope scope)372 	public void traverse(ASTVisitor visitor, BlockScope scope) {
373 		if (visitor.visit(this, scope)) {
374 			if (this.annotations != null) {
375 				Annotation [] typeAnnotations = this.annotations[0];
376 				for (int i = 0, length = typeAnnotations == null ? 0 : typeAnnotations.length; i < length; i++) {
377 					typeAnnotations[i].traverse(visitor, scope);
378 				}
379 			}
380 			Annotation [][] annotationsOnDimensions = getAnnotationsOnDimensions(true);
381 			if (annotationsOnDimensions != null) {
382 				for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) {
383 					Annotation[] annotations2 = annotationsOnDimensions[i];
384 					if (annotations2 != null) {
385 						for (int j = 0, max2 = annotations2.length; j < max2; j++) {
386 							Annotation annotation = annotations2[j];
387 							annotation.traverse(visitor, scope);
388 						}
389 					}
390 				}
391 			}
392 			for (int i = 0, max = this.typeArguments.length; i < max; i++) {
393 				this.typeArguments[i].traverse(visitor, scope);
394 			}
395 		}
396 		visitor.endVisit(this, scope);
397 	}
398 
traverse(ASTVisitor visitor, ClassScope scope)399 	public void traverse(ASTVisitor visitor, ClassScope scope) {
400 		if (visitor.visit(this, scope)) {
401 			if (this.annotations != null) {
402 				Annotation [] typeAnnotations = this.annotations[0];
403 				for (int i = 0, length = typeAnnotations == null ? 0 : typeAnnotations.length; i < length; i++) {
404 					typeAnnotations[i].traverse(visitor, scope);
405 				}
406 			}
407 			Annotation [][] annotationsOnDimensions = getAnnotationsOnDimensions(true);
408 			if (annotationsOnDimensions != null) {
409 				for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) {
410 					Annotation[] annotations2 = annotationsOnDimensions[i];
411 					for (int j = 0, max2 = annotations2.length; j < max2; j++) {
412 						Annotation annotation = annotations2[j];
413 						annotation.traverse(visitor, scope);
414 					}
415 				}
416 			}
417 			for (int i = 0, max = this.typeArguments.length; i < max; i++) {
418 				this.typeArguments[i].traverse(visitor, scope);
419 			}
420 		}
421 		visitor.endVisit(this, scope);
422 	}
423 }
424