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