1 12 package org.eclipse.jdt.internal.compiler.ast; 13 14 import org.eclipse.jdt.internal.compiler.ASTVisitor; 15 import org.eclipse.jdt.internal.compiler.impl.*; 16 import org.eclipse.jdt.internal.compiler.codegen.*; 17 import org.eclipse.jdt.internal.compiler.flow.*; 18 import org.eclipse.jdt.internal.compiler.lookup.*; 19 import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; 20 21 public class CastExpression extends Expression { 22 23 public Expression expression; 24 public Expression type; 25 public TypeBinding expectedType; 27 public CastExpression(Expression expression, Expression type) { 29 this.expression = expression; 30 this.type = type; 31 type.bits |= IgnoreRawTypeCheck; } 33 34 public FlowInfo analyseCode( 35 BlockScope currentScope, 36 FlowContext flowContext, 37 FlowInfo flowInfo) { 38 39 return expression 40 .analyseCode(currentScope, flowContext, flowInfo) 41 .unconditionalInits(); 42 } 43 44 47 public static void checkNeedForAssignedCast(BlockScope scope, TypeBinding expectedType, CastExpression rhs) { 48 49 if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return; 50 51 TypeBinding castedExpressionType = rhs.expression.resolvedType; 52 if (castedExpressionType == null || rhs.resolvedType.isBaseType()) return; 55 if (castedExpressionType.isCompatibleWith(expectedType)) { 57 scope.problemReporter().unnecessaryCast(rhs); 58 } 59 } 60 61 64 public static void checkNeedForEnclosingInstanceCast(BlockScope scope, Expression enclosingInstance, TypeBinding enclosingInstanceType, TypeBinding memberType) { 65 66 if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return; 67 68 TypeBinding castedExpressionType = ((CastExpression)enclosingInstance).expression.resolvedType; 69 if (castedExpressionType == null) return; if (castedExpressionType == enclosingInstanceType) { 72 scope.problemReporter().unnecessaryCast((CastExpression)enclosingInstance); 73 } else if (castedExpressionType == TypeBinding.NULL){ 74 return; } else { 76 TypeBinding alternateEnclosingInstanceType = castedExpressionType; 77 if (castedExpressionType.isBaseType() || castedExpressionType.isArrayType()) return; if (memberType == scope.getMemberType(memberType.sourceName(), (ReferenceBinding) alternateEnclosingInstanceType)) { 79 scope.problemReporter().unnecessaryCast((CastExpression)enclosingInstance); 80 } 81 } 82 } 83 84 87 public static void checkNeedForArgumentCast(BlockScope scope, int operator, int operatorSignature, Expression expression, int expressionTypeId) { 88 89 if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return; 90 91 int alternateLeftTypeId = expressionTypeId; 93 if ((expression.bits & UnnecessaryCast) == 0 && expression.resolvedType.isBaseType()) { 94 return; 96 } else { 97 TypeBinding alternateLeftType = ((CastExpression)expression).expression.resolvedType; 98 if (alternateLeftType == null) return; if ((alternateLeftTypeId = alternateLeftType.id) == expressionTypeId) { scope.problemReporter().unnecessaryCast((CastExpression)expression); 101 return; 102 } else if (alternateLeftTypeId == T_null) { 103 alternateLeftTypeId = expressionTypeId; return; 105 } 106 } 107 117 } 118 119 123 public static void checkNeedForArgumentCasts(BlockScope scope, Expression receiver, TypeBinding receiverType, MethodBinding binding, Expression[] arguments, TypeBinding[] argumentTypes, final InvocationSite invocationSite) { 124 125 if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return; 126 127 int length = argumentTypes.length; 128 129 TypeBinding[] rawArgumentTypes = argumentTypes; 131 for (int i = 0; i < length; i++) { 132 Expression argument = arguments[i]; 133 if (argument instanceof CastExpression) { 134 if ((argument.bits & UnnecessaryCast) == 0 && argument.resolvedType.isBaseType()) { 136 continue; 137 } 138 TypeBinding castedExpressionType = ((CastExpression)argument).expression.resolvedType; 139 if (castedExpressionType == null) return; if (castedExpressionType == argumentTypes[i]) { 142 scope.problemReporter().unnecessaryCast((CastExpression)argument); 143 } else if (castedExpressionType == TypeBinding.NULL){ 144 continue; } else if ((argument.implicitConversion & BOXING) != 0) { 146 continue; } else { 148 if (rawArgumentTypes == argumentTypes) { 149 System.arraycopy(rawArgumentTypes, 0, rawArgumentTypes = new TypeBinding[length], 0, length); 150 } 151 rawArgumentTypes[i] = castedExpressionType; 153 } 154 } 155 } 156 if (rawArgumentTypes != argumentTypes) { 158 checkAlternateBinding(scope, receiver, receiverType, binding, arguments, argumentTypes, rawArgumentTypes, invocationSite); 159 } 160 } 161 162 165 public static void checkNeedForArgumentCasts(BlockScope scope, int operator, int operatorSignature, Expression left, int leftTypeId, boolean leftIsCast, Expression right, int rightTypeId, boolean rightIsCast) { 166 167 if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return; 168 169 int alternateLeftTypeId = leftTypeId; 171 if (leftIsCast) { 172 if ((left.bits & UnnecessaryCast) == 0 && left.resolvedType.isBaseType()) { 173 leftIsCast = false; 175 } else { 176 TypeBinding alternateLeftType = ((CastExpression)left).expression.resolvedType; 177 if (alternateLeftType == null) return; if ((alternateLeftTypeId = alternateLeftType.id) == leftTypeId) { scope.problemReporter().unnecessaryCast((CastExpression)left); 180 leftIsCast = false; 181 } else if (alternateLeftTypeId == T_null) { 182 alternateLeftTypeId = leftTypeId; leftIsCast = false; 184 } 185 } 186 } 187 int alternateRightTypeId = rightTypeId; 189 if (rightIsCast) { 190 if ((right.bits & UnnecessaryCast) == 0 && right.resolvedType.isBaseType()) { 191 rightIsCast = false; 193 } else { 194 TypeBinding alternateRightType = ((CastExpression)right).expression.resolvedType; 195 if (alternateRightType == null) return; if ((alternateRightTypeId = alternateRightType.id) == rightTypeId) { scope.problemReporter().unnecessaryCast((CastExpression)right); 198 rightIsCast = false; 199 } else if (alternateRightTypeId == T_null) { 200 alternateRightTypeId = rightTypeId; rightIsCast = false; 202 } 203 } 204 } 205 if (leftIsCast || rightIsCast) { 206 if (alternateLeftTypeId > 15 || alternateRightTypeId > 15) { if (alternateLeftTypeId == T_JavaLangString) { 208 alternateRightTypeId = T_JavaLangObject; 209 } else if (alternateRightTypeId == T_JavaLangString) { 210 alternateLeftTypeId = T_JavaLangObject; 211 } else { 212 return; } 214 } 215 int alternateOperatorSignature = OperatorExpression.OperatorSignatures[operator][(alternateLeftTypeId << 4) + alternateRightTypeId]; 216 final int CompareMASK = (0xF<<16) + (0xF<<8) + 0xF; if ((operatorSignature & CompareMASK) == (alternateOperatorSignature & CompareMASK)) { if (leftIsCast) scope.problemReporter().unnecessaryCast((CastExpression)left); 222 if (rightIsCast) scope.problemReporter().unnecessaryCast((CastExpression)right); 223 } 224 } 225 } 226 227 private static void checkAlternateBinding(BlockScope scope, Expression receiver, TypeBinding receiverType, MethodBinding binding, Expression[] arguments, TypeBinding[] originalArgumentTypes, TypeBinding[] alternateArgumentTypes, final InvocationSite invocationSite) { 228 229 InvocationSite fakeInvocationSite = new InvocationSite(){ 230 public TypeBinding[] genericTypeArguments() { return null; } 231 public boolean isSuperAccess(){ return invocationSite.isSuperAccess(); } 232 public boolean isTypeAccess() { return invocationSite.isTypeAccess(); } 233 public void setActualReceiverType(ReferenceBinding actualReceiverType) { } 234 public void setDepth(int depth) { } 235 public void setFieldIndex(int depth){ } 236 public int sourceStart() { return 0; } 237 public int sourceEnd() { return 0; } 238 }; 239 MethodBinding bindingIfNoCast; 240 if (binding.isConstructor()) { 241 bindingIfNoCast = scope.getConstructor((ReferenceBinding)receiverType, alternateArgumentTypes, fakeInvocationSite); 242 } else { 243 bindingIfNoCast = receiver.isImplicitThis() 244 ? scope.getImplicitMethod(binding.selector, alternateArgumentTypes, fakeInvocationSite) 245 : scope.getMethod(receiverType, binding.selector, alternateArgumentTypes, fakeInvocationSite); 246 } 247 if (bindingIfNoCast == binding) { 248 int argumentLength = originalArgumentTypes.length; 249 if (binding.isVarargs()) { 250 int paramLength = binding.parameters.length; 251 if (paramLength == argumentLength) { 252 int varargsIndex = paramLength - 1; 253 ArrayBinding varargsType = (ArrayBinding) binding.parameters[varargsIndex]; 254 TypeBinding lastArgType = alternateArgumentTypes[varargsIndex]; 255 if (varargsType.dimensions != lastArgType.dimensions()) { 258 return; 259 } 260 if (lastArgType.isCompatibleWith(varargsType.elementsType()) 261 && lastArgType.isCompatibleWith(varargsType)) { 262 return; 263 } 264 } 265 } 266 for (int i = 0; i < argumentLength; i++) { 267 if (originalArgumentTypes[i] != alternateArgumentTypes[i]) { 268 scope.problemReporter().unnecessaryCast((CastExpression)arguments[i]); 269 } 270 } 271 } 272 } 273 274 public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding expressionType, TypeBinding match, boolean isNarrowing) { 275 if (match == castType) { 276 if (!isNarrowing && match == this.resolvedType.leafComponentType()) { tagAsUnnecessaryCast(scope, castType); 278 } 279 return true; 280 } 281 if (match != null && match.isProvablyDistinctFrom(isNarrowing ? expressionType : castType, 0)) { 282 return false; 283 } 284 switch (castType.kind()) { 285 case Binding.PARAMETERIZED_TYPE : 286 if (castType.isBoundParameterizedType()) { 287 if (match == null) { this.bits |= UnsafeCast; 289 return true; 290 } 291 switch (match.kind()) { 292 case Binding.PARAMETERIZED_TYPE : 293 if (isNarrowing) { 294 if (expressionType.isRawType() || !expressionType.isEquivalentTo(match)) { 296 this.bits |= UnsafeCast; 297 return true; 298 } 299 TypeBinding genericCastType = castType.erasure(); TypeBinding genericMatch = genericCastType.findSuperTypeWithSameErasure(expressionType); 302 if (genericMatch == match) { 303 this.bits |= UnsafeCast; 304 } 305 return true; 306 } else { 307 if (!match.isEquivalentTo(castType)) { 309 this.bits |= UnsafeCast; 310 return true; 311 } 312 } 313 break; 314 case Binding.RAW_TYPE : 315 this.bits |= UnsafeCast; return true; 317 default : 318 if (isNarrowing){ 319 this.bits |= UnsafeCast; 321 return true; 322 } 323 break; 324 } 325 } 326 break; 327 case Binding.ARRAY_TYPE : 328 TypeBinding leafType = castType.leafComponentType(); 329 if (isNarrowing && (leafType.isBoundParameterizedType() || leafType.isTypeVariable())) { 330 this.bits |= UnsafeCast; 331 return true; 332 } 333 break; 334 case Binding.TYPE_PARAMETER : 335 this.bits |= UnsafeCast; 336 return true; 337 } 338 if (!isNarrowing && match == this.resolvedType.leafComponentType()) { tagAsUnnecessaryCast(scope, castType); 340 } 341 return true; 342 } 343 344 351 public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { 352 353 int pc = codeStream.position; 354 boolean needRuntimeCheckcast = (this.bits & GenerateCheckcast) != 0; 355 if (constant != Constant.NotAConstant) { 356 if (valueRequired || needRuntimeCheckcast) { codeStream.generateConstant(constant, implicitConversion); 358 if (needRuntimeCheckcast) { 359 codeStream.checkcast(this.resolvedType); 360 } 361 if (!valueRequired) { 362 codeStream.pop(); 364 } 365 } 366 codeStream.recordPositionsFrom(pc, this.sourceStart); 367 return; 368 } 369 expression.generateCode(currentScope, codeStream, valueRequired || needRuntimeCheckcast); 370 if (needRuntimeCheckcast && this.expression.postConversionType(currentScope) != this.resolvedType.erasure()) { codeStream.checkcast(this.resolvedType); 372 } 373 if (valueRequired) { 374 codeStream.generateImplicitConversion(implicitConversion); 375 } else if (needRuntimeCheckcast) { 376 codeStream.pop(); 377 } 378 codeStream.recordPositionsFrom(pc, this.sourceStart); 379 } 380 381 public Expression innermostCastedExpression(){ 382 Expression current = this.expression; 383 while (current instanceof CastExpression) { 384 current = ((CastExpression) current).expression; 385 } 386 return current; 387 } 388 389 392 public LocalVariableBinding localVariableBinding() { 393 return this.expression.localVariableBinding(); 394 } 395 396 public int nullStatus(FlowInfo flowInfo) { 397 return this.expression.nullStatus(flowInfo); 398 } 399 400 403 public Constant optimizedBooleanConstant() { 404 switch(this.resolvedType.id) { 405 case T_boolean : 406 case T_JavaLangBoolean : 407 return this.expression.optimizedBooleanConstant(); 408 } 409 return Constant.NotAConstant; 410 } 411 412 public StringBuffer printExpression(int indent, StringBuffer output) { 413 414 output.append('('); 415 type.print(0, output).append(") "); return expression.printExpression(0, output); 417 } 418 419 public TypeBinding resolveType(BlockScope scope) { 420 422 426 constant = Constant.NotAConstant; 427 implicitConversion = T_undefined; 428 429 if ((type instanceof TypeReference) || (type instanceof NameReference) 430 && ((type.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT) == 0) { 432 TypeBinding castType = this.resolvedType = type.resolveType(scope); 433 TypeBinding expressionType = expression.resolveType(scope); 435 if (castType != null) { 436 if (expressionType != null) { 437 boolean isLegal = checkCastTypesCompatibility(scope, castType, expressionType, this.expression); 438 if (isLegal) { 439 this.expression.computeConversion(scope, castType, expressionType); 440 if ((this.bits & UnsafeCast) != 0) { scope.problemReporter().unsafeCast(this, scope); 442 } else { 443 if (castType.isRawType() && scope.compilerOptions().getSeverity(CompilerOptions.RawTypeReference) != ProblemSeverities.Ignore){ 444 scope.problemReporter().rawTypeReference(this.type, castType); 445 } 446 if ((this.bits & (UnnecessaryCast|DisableUnnecessaryCastCheck)) == UnnecessaryCast) { if (!isIndirectlyUsed()) scope.problemReporter().unnecessaryCast(this); 449 } 450 } 451 } else { scope.problemReporter().typeCastError(this, castType, expressionType); 453 this.bits |= DisableUnnecessaryCastCheck; } 455 } 456 this.resolvedType = castType.capture(scope, this.sourceEnd); 457 } 458 return this.resolvedType; 459 } else { TypeBinding expressionType = expression.resolveType(scope); 461 if (expressionType == null) return null; 462 scope.problemReporter().invalidTypeReference(type); 463 return null; 464 } 465 } 466 467 470 public void setExpectedType(TypeBinding expectedType) { 471 this.expectedType = expectedType; 472 } 473 474 478 private boolean isIndirectlyUsed() { 479 if (this.expression instanceof MessageSend) { 480 MethodBinding method = ((MessageSend)this.expression).binding; 481 if (method instanceof ParameterizedGenericMethodBinding 482 && ((ParameterizedGenericMethodBinding)method).inferredReturnType) { 483 if (this.expectedType == null) 484 return true; 485 if (this.resolvedType != this.expectedType) 486 return true; 487 } 488 } 489 if (this.expectedType != null && this.resolvedType.isBaseType() && !this.resolvedType.isCompatibleWith(this.expectedType)) { 490 return true; 492 } 493 return false; 494 } 495 496 499 public void tagAsNeedCheckCast() { 500 this.bits |= GenerateCheckcast; 501 } 502 503 506 public void tagAsUnnecessaryCast(Scope scope, TypeBinding castType) { 507 if (this.expression.resolvedType == null) return; this.bits |= UnnecessaryCast; 509 } 510 511 public void traverse( 512 ASTVisitor visitor, 513 BlockScope blockScope) { 514 515 if (visitor.visit(this, blockScope)) { 516 type.traverse(visitor, blockScope); 517 expression.traverse(visitor, blockScope); 518 } 519 visitor.endVisit(this, blockScope); 520 } 521 } 522 | Popular Tags |