1 /*******************************************************************************
2  * Copyright (c) 2000, 2014 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 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis
13  *								Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099
14  *								Bug 416181 – [1.8][compiler][null] Invalid assignment is not rejected by the compiler
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 ParameterizedQualifiedTypeReference extends ArrayQualifiedTypeReference {
33 
34 	public TypeReference[][] typeArguments;
35 
36 	/**
37 	 * @param tokens
38 	 * @param dim
39 	 * @param positions
40 	 */
ParameterizedQualifiedTypeReference(char[][] tokens, TypeReference[][] typeArguments, int dim, long[] positions)41 	public ParameterizedQualifiedTypeReference(char[][] tokens, TypeReference[][] typeArguments, int dim, long[] positions) {
42 
43 		super(tokens, dim, positions);
44 		this.typeArguments = typeArguments;
45 		annotationSearch: for (int i = 0, max = typeArguments.length; i < max; i++) {
46 			TypeReference[] typeArgumentsOnTypeComponent = typeArguments[i];
47 			if (typeArgumentsOnTypeComponent != null) {
48 				for (int j = 0, max2 = typeArgumentsOnTypeComponent.length; j < max2; j++) {
49 					if ((typeArgumentsOnTypeComponent[j].bits & ASTNode.HasTypeAnnotations) != 0) {
50 						this.bits |= ASTNode.HasTypeAnnotations;
51 						break annotationSearch;
52 					}
53 				}
54 			}
55 		}
56 	}
ParameterizedQualifiedTypeReference(char[][] tokens, TypeReference[][] typeArguments, int dim, Annotation[][] annotationsOnDimensions, long[] positions)57 	public ParameterizedQualifiedTypeReference(char[][] tokens, TypeReference[][] typeArguments, int dim, Annotation[][] annotationsOnDimensions, long[] positions) {
58 		this(tokens, typeArguments, dim, positions);
59 		setAnnotationsOnDimensions(annotationsOnDimensions);
60 		if (annotationsOnDimensions != null) {
61 			this.bits |= ASTNode.HasTypeAnnotations;
62 		}
63 	}
checkBounds(Scope scope)64 	public void checkBounds(Scope scope) {
65 		if (this.resolvedType == null) return;
66 
67 		checkBounds(
68 			(ReferenceBinding) this.resolvedType.leafComponentType(),
69 			scope,
70 			this.typeArguments.length - 1);
71 	}
checkBounds(ReferenceBinding type, Scope scope, int index)72 	public void checkBounds(ReferenceBinding type, Scope scope, int index) {
73 		// recurse on enclosing type if any, and assuming explictly  part of the reference (index>0)
74 		if (index > 0 &&  type.enclosingType() != null) {
75 			checkBounds(type.enclosingType(), scope, index - 1);
76 		}
77 		if (type.isParameterizedTypeWithActualArguments()) {
78 			ParameterizedTypeBinding parameterizedType = (ParameterizedTypeBinding) type;
79 			ReferenceBinding currentType = parameterizedType.genericType();
80 			TypeVariableBinding[] typeVariables = currentType.typeVariables();
81 			if (typeVariables != null) { // argTypes may be null in error cases
82 				parameterizedType.boundCheck(scope, this.typeArguments[index]);
83 			}
84 		}
85 		checkNullConstraints(scope, this.typeArguments[index]);
86 	}
augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs)87 	public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs) {
88 		int totalDimensions = this.dimensions() + additionalDimensions;
89 		Annotation [][] allAnnotations = getMergedAnnotationsOnDimensions(additionalDimensions, additionalAnnotations);
90 		ParameterizedQualifiedTypeReference pqtr = new ParameterizedQualifiedTypeReference(this.tokens, this.typeArguments, totalDimensions, allAnnotations, this.sourcePositions);
91 		pqtr.annotations = this.annotations;
92 		pqtr.bits |= (this.bits & ASTNode.HasTypeAnnotations);
93 		if (!isVarargs)
94 			pqtr.extendedDimensions = additionalDimensions;
95 		return pqtr;
96 	}
isParameterizedTypeReference()97 	public boolean isParameterizedTypeReference() {
98 		return true;
99 	}
100 
101 	/**
102 	 * @return char[][]
103 	 */
getParameterizedTypeName()104 	public char [][] getParameterizedTypeName(){
105 		int length = this.tokens.length;
106 		char[][] qParamName = new char[length][];
107 		for (int i = 0; i < length; i++) {
108 			TypeReference[] arguments = this.typeArguments[i];
109 			if (arguments == null) {
110 				qParamName[i] = this.tokens[i];
111 			} else {
112 				StringBuffer buffer = new StringBuffer(5);
113 				buffer.append(this.tokens[i]);
114 				buffer.append('<');
115 				for (int j = 0, argLength =arguments.length; j < argLength; j++) {
116 					if (j > 0) buffer.append(',');
117 					buffer.append(CharOperation.concatWith(arguments[j].getParameterizedTypeName(), '.'));
118 				}
119 				buffer.append('>');
120 				int nameLength = buffer.length();
121 				qParamName[i] = new char[nameLength];
122 				buffer.getChars(0, nameLength, qParamName[i], 0);
123 			}
124 		}
125 		int dim = this.dimensions;
126 		if (dim > 0) {
127 			char[] dimChars = new char[dim*2];
128 			for (int i = 0; i < dim; i++) {
129 				int index = i*2;
130 				dimChars[index] = '[';
131 				dimChars[index+1] = ']';
132 			}
133 			qParamName[length-1] = CharOperation.concat(qParamName[length-1], dimChars);
134 		}
135 		return qParamName;
136 	}
137 
getTypeArguments()138 	public TypeReference[][] getTypeArguments() {
139 		return this.typeArguments;
140 	}
141 
142 	/* (non-Javadoc)
143      * @see org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference#getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.Scope)
144      */
getTypeBinding(Scope scope)145     protected TypeBinding getTypeBinding(Scope scope) {
146         return null; // not supported here - combined with resolveType(...)
147     }
148 
149     /*
150      * No need to check for reference to raw type per construction
151      */
internalResolveType(Scope scope, boolean checkBounds, int location)152 	private TypeBinding internalResolveType(Scope scope, boolean checkBounds, int location) {
153 		// handle the error here
154 		this.constant = Constant.NotAConstant;
155 		if ((this.bits & ASTNode.DidResolve) != 0) { // is a shared type reference which was already resolved
156 			if (this.resolvedType != null) { // is a shared type reference which was already resolved
157 				if (this.resolvedType.isValidBinding()) {
158 					return this.resolvedType;
159 				} else {
160 					switch (this.resolvedType.problemId()) {
161 						case ProblemReasons.NotFound :
162 						case ProblemReasons.NotVisible :
163 						case ProblemReasons.InheritedNameHidesEnclosingName :
164 							TypeBinding type = this.resolvedType.closestMatch();
165 							return type;
166 						default :
167 							return null;
168 					}
169 				}
170 			}
171 		}
172 		this.bits |= ASTNode.DidResolve;
173 		TypeBinding type = internalResolveLeafType(scope, checkBounds);
174 		createArrayType(scope);
175 		resolveAnnotations(scope, location);
176 		if (this.typeArguments != null && checkBounds)
177 			// relevant null annotations are on the inner most type:
178 			checkNullConstraints(scope, this.typeArguments[this.typeArguments.length-1]);
179 		return type == null ? type : this.resolvedType;
180 	}
internalResolveLeafType(Scope scope, boolean checkBounds)181 	private TypeBinding internalResolveLeafType(Scope scope, boolean checkBounds) {
182 		boolean isClassScope = scope.kind == Scope.CLASS_SCOPE;
183 		Binding binding = scope.getPackage(this.tokens);
184 		if (binding != null && !binding.isValidBinding()) {
185 			this.resolvedType = (ReferenceBinding) binding;
186 			reportInvalidType(scope);
187 			// be resilient, still attempt resolving arguments
188 			for (int i = 0, max = this.tokens.length; i < max; i++) {
189 				TypeReference[] args = this.typeArguments[i];
190 				if (args != null) {
191 					int argLength = args.length;
192 					for (int j = 0; j < argLength; j++) {
193 						TypeReference typeArgument = args[j];
194 						if (isClassScope) {
195 							typeArgument.resolveType((ClassScope) scope);
196 						} else {
197 							typeArgument.resolveType((BlockScope) scope, checkBounds);
198 						}
199 					}
200 				}
201 			}
202 			return null;
203 		}
204 
205 		PackageBinding packageBinding = binding == null ? null : (PackageBinding) binding;
206 		rejectAnnotationsOnPackageQualifiers(scope, packageBinding);
207 
208 		boolean typeIsConsistent = true;
209 		ReferenceBinding qualifyingType = null;
210 		for (int i = packageBinding == null ? 0 : packageBinding.compoundName.length, max = this.tokens.length; i < max; i++) {
211 			findNextTypeBinding(i, scope, packageBinding);
212 			if (!(this.resolvedType.isValidBinding())) {
213 				reportInvalidType(scope);
214 				// be resilient, still attempt resolving arguments
215 				for (int j = i; j < max; j++) {
216 				    TypeReference[] args = this.typeArguments[j];
217 				    if (args != null) {
218 						int argLength = args.length;
219 						for (int k = 0; k < argLength; k++) {
220 						    TypeReference typeArgument = args[k];
221 						    if (isClassScope) {
222 						    	typeArgument.resolveType((ClassScope) scope);
223 						    } else {
224 						    	typeArgument.resolveType((BlockScope) scope);
225 						    }
226 						}
227 				    }
228 				}
229 				return null;
230 			}
231 			ReferenceBinding currentType = (ReferenceBinding) this.resolvedType;
232 			if (qualifyingType == null) {
233 				qualifyingType = currentType.enclosingType(); // if member type
234 				if (qualifyingType != null) {
235 					qualifyingType = currentType.isStatic()
236 						? (ReferenceBinding) scope.environment().convertToRawType(qualifyingType, false /*do not force conversion of enclosing types*/)
237 						: scope.environment().convertToParameterizedType(qualifyingType);
238 				}
239 			} else {
240 				if (this.annotations != null)
241 					rejectAnnotationsOnStaticMemberQualififer(scope, currentType, this.annotations[i-1]);
242 				if (typeIsConsistent && currentType.isStatic()
243 						&& (qualifyingType.isParameterizedTypeWithActualArguments() || qualifyingType.isGenericType())) {
244 					scope.problemReporter().staticMemberOfParameterizedType(this, scope.environment().createParameterizedType((ReferenceBinding)currentType.erasure(), null, qualifyingType), i);
245 					typeIsConsistent = false;
246 				}
247 				ReferenceBinding enclosingType = currentType.enclosingType();
248 				if (enclosingType != null && TypeBinding.notEquals(enclosingType.erasure(), qualifyingType.erasure())) { // qualifier != declaring/enclosing
249 					qualifyingType = enclosingType; // inherited member type, leave it associated with its enclosing rather than subtype
250 				}
251 			}
252 
253 			// check generic and arity
254 		    TypeReference[] args = this.typeArguments[i];
255 		    if (args != null) {
256 			    TypeReference keep = null;
257 			    if (isClassScope) {
258 			    	keep = ((ClassScope) scope).superTypeReference;
259 			    	((ClassScope) scope).superTypeReference = null;
260 			    }
261 				int argLength = args.length;
262 				boolean isDiamond = argLength == 0 && (i == (max -1)) && ((this.bits & ASTNode.IsDiamond) != 0);
263 				TypeBinding[] argTypes = new TypeBinding[argLength];
264 				boolean argHasError = false;
265 				ReferenceBinding currentOriginal = (ReferenceBinding)currentType.original();
266 				for (int j = 0; j < argLength; j++) {
267 				    TypeReference arg = args[j];
268 				    TypeBinding argType = isClassScope
269 						? arg.resolveTypeArgument((ClassScope) scope, currentOriginal, j)
270 						: arg.resolveTypeArgument((BlockScope) scope, currentOriginal, j);
271 					if (argType == null) {
272 						argHasError = true;
273 					} else {
274 						argTypes[j] = argType;
275 					}
276 				}
277 				if (argHasError) {
278 					return null;
279 				}
280 				if (isClassScope) {
281 					((ClassScope) scope).superTypeReference = keep;
282 					if (((ClassScope) scope).detectHierarchyCycle(currentOriginal, this))
283 						return null;
284 				}
285 
286 			    TypeVariableBinding[] typeVariables = currentOriginal.typeVariables();
287 				if (typeVariables == Binding.NO_TYPE_VARIABLES) { // check generic
288 					if (scope.compilerOptions().originalSourceLevel >= ClassFileConstants.JDK1_5) { // below 1.5, already reported as syntax error
289 						scope.problemReporter().nonGenericTypeCannotBeParameterized(i, this, currentType, argTypes);
290 						return null;
291 					}
292 					this.resolvedType =  (qualifyingType != null && qualifyingType.isParameterizedType())
293 						? scope.environment().createParameterizedType(currentOriginal, null, qualifyingType)
294 						: currentType;
295 					return this.resolvedType;
296 				} else if (argLength != typeVariables.length) {
297 					if (!isDiamond) { // check arity
298 						scope.problemReporter().incorrectArityForParameterizedType(this, currentType, argTypes, i);
299 						return null;
300 					}
301 				}
302 				// check parameterizing non-static member type of raw type
303 				if (typeIsConsistent && !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 						typeIsConsistent = false;
309 					}
310 				}
311 				ParameterizedTypeBinding parameterizedType = scope.environment().createParameterizedType(currentOriginal, argTypes, qualifyingType);
312 				// check argument type compatibility for non <> cases - <> case needs no bounds check, we will scream foul if needed during inference.
313 				if (!isDiamond) {
314 					if (checkBounds) // otherwise will do it in Scope.connectTypeVariables() or generic method resolution
315 						parameterizedType.boundCheck(scope, args);
316 					else
317 						scope.deferBoundCheck(this);
318 				}
319 				qualifyingType = parameterizedType;
320 		    } else {
321 				ReferenceBinding currentOriginal = (ReferenceBinding)currentType.original();
322 				if (isClassScope)
323 					if (((ClassScope) scope).detectHierarchyCycle(currentOriginal, this))
324 						return null;
325 				if (currentOriginal.isGenericType()) {
326 	   			    if (typeIsConsistent && qualifyingType != null && qualifyingType.isParameterizedType()) {
327 						scope.problemReporter().parameterizedMemberTypeMissingArguments(this, scope.environment().createParameterizedType(currentOriginal, null, qualifyingType), i);
328 						typeIsConsistent = false;
329 					}
330 	   			    qualifyingType = scope.environment().createRawType(currentOriginal, qualifyingType); // raw type
331 				} else {
332 					qualifyingType = (qualifyingType != null && qualifyingType.isParameterizedType())
333 													? scope.environment().createParameterizedType(currentOriginal, null, qualifyingType)
334 													: currentType;
335 				}
336 			}
337 			if (isTypeUseDeprecated(qualifyingType, scope))
338 				reportDeprecatedType(qualifyingType, scope, i);
339 			this.resolvedType = qualifyingType;
340 			recordResolution(scope.environment(), this.resolvedType);
341 		}
342 		return this.resolvedType;
343 	}
createArrayType(Scope scope)344 	private void createArrayType(Scope scope) {
345 		if (this.dimensions > 0) {
346 			if (this.dimensions > 255)
347 				scope.problemReporter().tooManyDimensions(this);
348 			this.resolvedType = scope.createArrayType(this.resolvedType, this.dimensions);
349 		}
350 	}
351 
printExpression(int indent, StringBuffer output)352 	public StringBuffer printExpression(int indent, StringBuffer output) {
353 		int length = this.tokens.length;
354 		for (int i = 0; i < length - 1; i++) {
355 			if (this.annotations != null && this.annotations[i] != null) {
356 				printAnnotations(this.annotations[i], output);
357 				output.append(' ');
358 			}
359 			output.append(this.tokens[i]);
360 			TypeReference[] typeArgument = this.typeArguments[i];
361 			if (typeArgument != null) {
362 				output.append('<');
363 				int typeArgumentLength = typeArgument.length;
364 				if (typeArgumentLength > 0) {
365 					int max = typeArgumentLength - 1;
366 					for (int j = 0; j < max; j++) {
367 						typeArgument[j].print(0, output);
368 						output.append(", ");//$NON-NLS-1$
369 					}
370 					typeArgument[max].print(0, output);
371 				}
372 				output.append('>');
373 			}
374 			output.append('.');
375 		}
376 		if (this.annotations != null && this.annotations[length - 1] != null) {
377 			output.append(" "); //$NON-NLS-1$
378 			printAnnotations(this.annotations[length - 1], output);
379 			output.append(' ');
380 		}
381 		output.append(this.tokens[length - 1]);
382 		TypeReference[] typeArgument = this.typeArguments[length - 1];
383 		if (typeArgument != null) {
384 			output.append('<');
385 			int typeArgumentLength = typeArgument.length;
386 			if (typeArgumentLength > 0) {
387 				int max = typeArgumentLength - 1;
388 				for (int j = 0; j < max; j++) {
389 					typeArgument[j].print(0, output);
390 					output.append(", ");//$NON-NLS-1$
391 				}
392 				typeArgument[max].print(0, output);
393 			}
394 			output.append('>');
395 		}
396 		Annotation [][] annotationsOnDimensions = this.getAnnotationsOnDimensions();
397 		if ((this.bits & IsVarArgs) != 0) {
398 			for (int i= 0 ; i < this.dimensions - 1; i++) {
399 				if (annotationsOnDimensions != null && annotationsOnDimensions[i] != null) {
400 					output.append(" "); //$NON-NLS-1$
401 					printAnnotations(annotationsOnDimensions[i], output);
402 					output.append(" "); //$NON-NLS-1$
403 				}
404 				output.append("[]"); //$NON-NLS-1$
405 			}
406 			if (annotationsOnDimensions != null && annotationsOnDimensions[this.dimensions - 1] != null) {
407 				output.append(" "); //$NON-NLS-1$
408 				printAnnotations(annotationsOnDimensions[this.dimensions - 1], output);
409 				output.append(" "); //$NON-NLS-1$
410 			}
411 			output.append("..."); //$NON-NLS-1$
412 		} else {
413 			for (int i= 0 ; i < this.dimensions; i++) {
414 				if (annotationsOnDimensions != null && annotationsOnDimensions[i] != null) {
415 					output.append(" "); //$NON-NLS-1$
416 					printAnnotations(annotationsOnDimensions[i], output);
417 					output.append(" "); //$NON-NLS-1$
418 				}
419 				output.append("[]"); //$NON-NLS-1$
420 			}
421 		}
422 		return output;
423 	}
424 
resolveType(BlockScope scope, boolean checkBounds, int location)425 	public TypeBinding resolveType(BlockScope scope, boolean checkBounds, int location) {
426 	    return internalResolveType(scope, checkBounds, location);
427 	}
resolveType(ClassScope scope, int location)428 	public TypeBinding resolveType(ClassScope scope, int location) {
429 	    return internalResolveType(scope, false, location);
430 	}
traverse(ASTVisitor visitor, BlockScope scope)431 	public void traverse(ASTVisitor visitor, BlockScope scope) {
432 		if (visitor.visit(this, scope)) {
433 			if (this.annotations != null) {
434 				int annotationsLevels = this.annotations.length;
435 				for (int i = 0; i < annotationsLevels; i++) {
436 					int annotationsLength = this.annotations[i] == null ? 0 : this.annotations[i].length;
437 					for (int j = 0; j < annotationsLength; j++)
438 						this.annotations[i][j].traverse(visitor, scope);
439 				}
440 			}
441 			Annotation [][] annotationsOnDimensions = getAnnotationsOnDimensions(true);
442 			if (annotationsOnDimensions != null) {
443 				for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) {
444 					Annotation[] annotations2 = annotationsOnDimensions[i];
445 					for (int j = 0, max2 = annotations2 == null ? 0 : annotations2.length; j < max2; j++) {
446 						Annotation annotation = annotations2[j];
447 						annotation.traverse(visitor, scope);
448 					}
449 				}
450 			}
451 			for (int i = 0, max = this.typeArguments.length; i < max; i++) {
452 				if (this.typeArguments[i] != null) {
453 					for (int j = 0, max2 = this.typeArguments[i].length; j < max2; j++) {
454 						this.typeArguments[i][j].traverse(visitor, scope);
455 					}
456 				}
457 			}
458 		}
459 		visitor.endVisit(this, scope);
460 	}
461 
traverse(ASTVisitor visitor, ClassScope scope)462 	public void traverse(ASTVisitor visitor, ClassScope scope) {
463 		if (visitor.visit(this, scope)) {
464 			if (this.annotations != null) {
465 				int annotationsLevels = this.annotations.length;
466 				for (int i = 0; i < annotationsLevels; i++) {
467 					int annotationsLength = this.annotations[i] == null ? 0 : this.annotations[i].length;
468 					for (int j = 0; j < annotationsLength; j++)
469 						this.annotations[i][j].traverse(visitor, scope);
470 				}
471 			}
472 			Annotation [][] annotationsOnDimensions = getAnnotationsOnDimensions(true);
473 			if (annotationsOnDimensions != null) {
474 				for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) {
475 					Annotation[] annotations2 = annotationsOnDimensions[i];
476 					for (int j = 0, max2 = annotations2 == null ? 0 : annotations2.length; j < max2; j++) {
477 						Annotation annotation = annotations2[j];
478 						annotation.traverse(visitor, scope);
479 					}
480 				}
481 			}
482 			for (int i = 0, max = this.typeArguments.length; i < max; i++) {
483 				if (this.typeArguments[i] != null) {
484 					for (int j = 0, max2 = this.typeArguments[i].length; j < max2; j++) {
485 						this.typeArguments[i][j].traverse(visitor, scope);
486 					}
487 				}
488 			}
489 		}
490 		visitor.endVisit(this, scope);
491 	}
492 
493 }
494