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