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