1 12 package org.eclipse.jdt.internal.compiler.ast; 13 14 import org.eclipse.jdt.core.compiler.CharOperation; 15 import org.eclipse.jdt.internal.compiler.ASTVisitor; 16 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; 17 import org.eclipse.jdt.internal.compiler.codegen.CodeStream; 18 import org.eclipse.jdt.internal.compiler.flow.FlowContext; 19 import org.eclipse.jdt.internal.compiler.flow.FlowInfo; 20 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; 21 import org.eclipse.jdt.internal.compiler.impl.Constant; 22 import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; 23 import org.eclipse.jdt.internal.compiler.lookup.Binding; 24 import org.eclipse.jdt.internal.compiler.lookup.BlockScope; 25 import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; 26 import org.eclipse.jdt.internal.compiler.lookup.InvocationSite; 27 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; 28 import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding; 29 import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; 30 import org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding; 31 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; 32 import org.eclipse.jdt.internal.compiler.lookup.Scope; 33 import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; 34 import org.eclipse.jdt.internal.compiler.lookup.TagBits; 35 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; 36 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; 37 import org.eclipse.jdt.internal.compiler.lookup.TypeIds; 38 import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; 39 40 public class MessageSend extends Expression implements InvocationSite { 41 42 public Expression receiver; 43 public char[] selector; 44 public Expression[] arguments; 45 public MethodBinding binding; protected MethodBinding codegenBinding; MethodBinding syntheticAccessor; public TypeBinding expectedType; 50 public long nameSourcePosition ; 52 public TypeBinding actualReceiverType; 53 public TypeBinding receiverGenericCast; public TypeBinding valueCast; public TypeReference[] typeArguments; 56 public TypeBinding[] genericTypeArguments; 57 58 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { 59 60 boolean nonStatic = !this.binding.isStatic(); 61 flowInfo = this.receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic).unconditionalInits(); 62 if (nonStatic) { 63 this.receiver.checkNPE(currentScope, flowContext, flowInfo); 64 } 65 66 if (this.arguments != null) { 67 int length = this.arguments.length; 68 for (int i = 0; i < length; i++) { 69 flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); 70 } 71 } 72 ReferenceBinding[] thrownExceptions; 73 if ((thrownExceptions = this.binding.thrownExceptions) != Binding.NO_EXCEPTIONS) { 74 flowContext.checkExceptionHandlers(thrownExceptions, this, flowInfo.copy(), currentScope); 76 } 80 manageSyntheticAccessIfNecessary(currentScope, flowInfo); 81 return flowInfo; 82 } 83 86 public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) { 87 if (runtimeTimeType == null || compileTimeType == null) 88 return; 89 if (this.binding != null && this.binding.isValidBinding()) { 91 MethodBinding originalBinding = this.binding.original(); 92 TypeBinding originalType = originalBinding.returnType; 93 if (originalBinding != this.binding 95 && originalType != this.binding.returnType 96 && runtimeTimeType.id != TypeIds.T_JavaLangObject 97 && (originalType.tagBits & TagBits.HasTypeVariable) != 0) { 98 TypeBinding targetType = (!compileTimeType.isBaseType() && runtimeTimeType.isBaseType()) 99 ? compileTimeType : runtimeTimeType; 101 this.valueCast = originalType.genericCast(targetType); 102 } else if (this.actualReceiverType.isArrayType() 103 && runtimeTimeType.id != TypeIds.T_JavaLangObject 104 && this.binding.parameters == Binding.NO_PARAMETERS 105 && scope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_5 106 && CharOperation.equals(this.binding.selector, TypeConstants.CLONE)) { 107 this.valueCast = runtimeTimeType; 109 } 110 } 111 super.computeConversion(scope, runtimeTimeType, compileTimeType); 112 } 113 114 121 public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { 122 123 int pc = codeStream.position; 124 125 boolean isStatic = this.codegenBinding.isStatic(); 127 if (isStatic) { 128 this.receiver.generateCode(currentScope, codeStream, false); 129 codeStream.recordPositionsFrom(pc, this.sourceStart); 130 } else if ((this.bits & ASTNode.DepthMASK) != 0 && this.receiver.isImplicitThis()) { ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT); 133 Object [] path = currentScope.getEmulationPath(targetType, true , false); 134 codeStream.generateOuterAccess(path, this, targetType, currentScope); 135 } else { 136 this.receiver.generateCode(currentScope, codeStream, true); 137 if (this.receiverGenericCast != null) 138 codeStream.checkcast(this.receiverGenericCast); 139 codeStream.recordPositionsFrom(pc, this.sourceStart); 140 141 } 142 generateArguments(this.binding, this.arguments, currentScope, codeStream); 144 if (this.syntheticAccessor == null){ 146 if (isStatic){ 147 codeStream.invokestatic(this.codegenBinding); 148 } else { 149 if( (this.receiver.isSuper()) || this.codegenBinding.isPrivate()){ 150 codeStream.invokespecial(this.codegenBinding); 151 } else { 152 if (this.codegenBinding.declaringClass.isInterface()) { codeStream.invokeinterface(this.codegenBinding); 154 } else { 155 codeStream.invokevirtual(this.codegenBinding); 156 } 157 } 158 } 159 } else { 160 codeStream.invokestatic(this.syntheticAccessor); 161 } 162 if (this.valueCast != null) codeStream.checkcast(this.valueCast); 164 if (valueRequired){ 165 codeStream.generateImplicitConversion(this.implicitConversion); 167 } else { 168 boolean isUnboxing = (this.implicitConversion & TypeIds.UNBOXING) != 0; 169 if (isUnboxing) codeStream.generateImplicitConversion(this.implicitConversion); 171 switch (isUnboxing ? postConversionType(currentScope).id : this.codegenBinding.returnType.id) { 172 case T_long : 173 case T_double : 174 codeStream.pop2(); 175 break; 176 case T_void : 177 break; 178 default : 179 codeStream.pop(); 180 } 181 } 182 codeStream.recordPositionsFrom(pc, (int)(this.nameSourcePosition >>> 32)); } 184 185 188 public TypeBinding[] genericTypeArguments() { 189 return this.genericTypeArguments; 190 } 191 192 public boolean isSuperAccess() { 193 return this.receiver.isSuper(); 194 } 195 public boolean isTypeAccess() { 196 return this.receiver != null && this.receiver.isTypeReference(); 197 } 198 public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo){ 199 200 if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) return; 201 202 this.codegenBinding = this.binding.original(); 204 if (this.binding.isPrivate()){ 205 206 if (currentScope.enclosingSourceType() != this.codegenBinding.declaringClass){ 208 209 this.syntheticAccessor = ((SourceTypeBinding)this.codegenBinding.declaringClass).addSyntheticMethod(this.codegenBinding, isSuperAccess()); 210 currentScope.problemReporter().needToEmulateMethodAccess(this.codegenBinding, this); 211 return; 212 } 213 214 } else if (this.receiver instanceof QualifiedSuperReference){ 216 SourceTypeBinding destinationType = (SourceTypeBinding)(((QualifiedSuperReference)this.receiver).currentCompatibleType); 218 this.syntheticAccessor = destinationType.addSyntheticMethod(this.codegenBinding, isSuperAccess()); 219 currentScope.problemReporter().needToEmulateMethodAccess(this.codegenBinding, this); 220 return; 221 222 } else if (this.binding.isProtected()){ 223 224 SourceTypeBinding enclosingSourceType; 225 if (((this.bits & ASTNode.DepthMASK) != 0) 226 && this.codegenBinding.declaringClass.getPackage() 227 != (enclosingSourceType = currentScope.enclosingSourceType()).getPackage()){ 228 229 SourceTypeBinding currentCompatibleType = (SourceTypeBinding)enclosingSourceType.enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT); 230 this.syntheticAccessor = currentCompatibleType.addSyntheticMethod(this.codegenBinding, isSuperAccess()); 231 currentScope.problemReporter().needToEmulateMethodAccess(this.codegenBinding, this); 232 return; 233 } 234 } 235 236 if (this.binding.declaringClass != this.actualReceiverType 241 && this.receiverGenericCast == null 242 && !this.actualReceiverType.isArrayType()) { 243 CompilerOptions options = currentScope.compilerOptions(); 244 if ((options.targetJDK >= ClassFileConstants.JDK1_2 245 && (options.complianceLevel >= ClassFileConstants.JDK1_4 || !(this.receiver.isImplicitThis() && this.codegenBinding.isStatic())) 246 && this.binding.declaringClass.id != TypeIds.T_JavaLangObject) || !this.binding.declaringClass.canBeSeenBy(currentScope)) { 248 249 this.codegenBinding = currentScope.enclosingSourceType().getUpdatedMethodBinding( 250 this.codegenBinding, (ReferenceBinding) this.actualReceiverType.erasure()); 251 } 252 } 255 } 256 public int nullStatus(FlowInfo flowInfo) { 257 return FlowInfo.UNKNOWN; 258 } 259 260 263 public TypeBinding postConversionType(Scope scope) { 264 TypeBinding convertedType = this.resolvedType; 265 if (this.valueCast != null) 266 convertedType = this.valueCast; 267 int runtimeType = (this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4; 268 switch (runtimeType) { 269 case T_boolean : 270 convertedType = TypeBinding.BOOLEAN; 271 break; 272 case T_byte : 273 convertedType = TypeBinding.BYTE; 274 break; 275 case T_short : 276 convertedType = TypeBinding.SHORT; 277 break; 278 case T_char : 279 convertedType = TypeBinding.CHAR; 280 break; 281 case T_int : 282 convertedType = TypeBinding.INT; 283 break; 284 case T_float : 285 convertedType = TypeBinding.FLOAT; 286 break; 287 case T_long : 288 convertedType = TypeBinding.LONG; 289 break; 290 case T_double : 291 convertedType = TypeBinding.DOUBLE; 292 break; 293 default : 294 } 295 if ((this.implicitConversion & TypeIds.BOXING) != 0) { 296 convertedType = scope.environment().computeBoxingType(convertedType); 297 } 298 return convertedType; 299 } 300 301 public StringBuffer printExpression(int indent, StringBuffer output){ 302 303 if (!this.receiver.isImplicitThis()) this.receiver.printExpression(0, output).append('.'); 304 if (this.typeArguments != null) { 305 output.append('<'); 306 int max = this.typeArguments.length - 1; 307 for (int j = 0; j < max; j++) { 308 this.typeArguments[j].print(0, output); 309 output.append(", "); } 311 this.typeArguments[max].print(0, output); 312 output.append('>'); 313 } 314 output.append(this.selector).append('(') ; 315 if (this.arguments != null) { 316 for (int i = 0; i < this.arguments.length ; i ++) { 317 if (i > 0) output.append(", "); this.arguments[i].printExpression(0, output); 319 } 320 } 321 return output.append(')'); 322 } 323 324 public TypeBinding resolveType(BlockScope scope) { 325 328 this.constant = Constant.NotAConstant; 329 boolean receiverCast = false, argsContainCast = false; 330 if (this.receiver instanceof CastExpression) { 331 this.receiver.bits |= ASTNode.DisableUnnecessaryCastCheck; receiverCast = true; 333 } 334 this.actualReceiverType = this.receiver.resolveType(scope); 335 boolean receiverIsType = this.receiver instanceof NameReference && (((NameReference) this.receiver).bits & Binding.TYPE) != 0; 336 if (receiverCast && this.actualReceiverType != null) { 337 if (((CastExpression)this.receiver).expression.resolvedType == this.actualReceiverType) { 339 scope.problemReporter().unnecessaryCast((CastExpression)this.receiver); 340 } 341 } 342 if (this.typeArguments != null) { 344 int length = this.typeArguments.length; 345 boolean argHasError = false; this.genericTypeArguments = new TypeBinding[length]; 347 for (int i = 0; i < length; i++) { 348 TypeReference typeReference = this.typeArguments[i]; 349 if ((this.genericTypeArguments[i] = typeReference.resolveType(scope, true )) == null) { 350 argHasError = true; 351 } 352 if (argHasError && typeReference instanceof Wildcard) { 353 scope.problemReporter().illegalUsageOfWildcard(typeReference); 354 } 355 } 356 if (argHasError) { 357 return null; 358 } 359 } 360 TypeBinding[] argumentTypes = Binding.NO_PARAMETERS; 362 if (this.arguments != null) { 363 boolean argHasError = false; int length = this.arguments.length; 365 argumentTypes = new TypeBinding[length]; 366 for (int i = 0; i < length; i++){ 367 Expression argument = this.arguments[i]; 368 if (argument instanceof CastExpression) { 369 argument.bits |= ASTNode.DisableUnnecessaryCastCheck; argsContainCast = true; 371 } 372 if ((argumentTypes[i] = argument.resolveType(scope)) == null){ 373 argHasError = true; 374 } 375 } 376 if (argHasError) { 377 if (this.actualReceiverType instanceof ReferenceBinding) { 378 TypeBinding[] pseudoArgs = new TypeBinding[length]; 380 for (int i = length; --i >= 0;) 381 pseudoArgs[i] = argumentTypes[i] == null ? TypeBinding.NULL : argumentTypes[i]; this.binding = 383 this.receiver.isImplicitThis() 384 ? scope.getImplicitMethod(this.selector, pseudoArgs, this) 385 : scope.findMethod((ReferenceBinding) this.actualReceiverType, this.selector, pseudoArgs, this); 386 if (this.binding != null && !this.binding.isValidBinding()) { 387 MethodBinding closestMatch = ((ProblemMethodBinding)this.binding).closestMatch; 388 if (closestMatch != null) { 390 if (closestMatch.original().typeVariables != Binding.NO_TYPE_VARIABLES) { closestMatch = scope.environment().createParameterizedGenericMethod(closestMatch.original(), (RawTypeBinding)null); 393 } 394 this.binding = closestMatch; 395 MethodBinding closestMatchOriginal = closestMatch.original(); 396 if ((closestMatchOriginal.isPrivate() || closestMatchOriginal.declaringClass.isLocalType()) && !scope.isDefinedInMethod(closestMatchOriginal)) { 397 closestMatchOriginal.modifiers |= ExtraCompilerModifiers.AccLocallyUsed; 399 } 400 } 401 } 402 } 403 return null; 404 } 405 } 406 if (this.actualReceiverType == null) { 407 return null; 408 } 409 if (this.actualReceiverType.isBaseType()) { 411 scope.problemReporter().errorNoMethodFor(this, this.actualReceiverType, argumentTypes); 412 return null; 413 } 414 this.binding = 415 this.receiver.isImplicitThis() 416 ? scope.getImplicitMethod(this.selector, argumentTypes, this) 417 : scope.getMethod(this.actualReceiverType, this.selector, argumentTypes, this); 418 if (!this.binding.isValidBinding()) { 419 if (this.binding.declaringClass == null) { 420 if (this.actualReceiverType instanceof ReferenceBinding) { 421 this.binding.declaringClass = (ReferenceBinding) this.actualReceiverType; 422 } else { 423 scope.problemReporter().errorNoMethodFor(this, this.actualReceiverType, argumentTypes); 424 return null; 425 } 426 } 427 scope.problemReporter().invalidMethod(this, this.binding); 428 MethodBinding closestMatch = ((ProblemMethodBinding)this.binding).closestMatch; 429 switch (this.binding.problemId()) { 430 case ProblemReasons.Ambiguous : 431 break; case ProblemReasons.NotVisible : 433 case ProblemReasons.NonStaticReferenceInConstructorInvocation : 434 case ProblemReasons.NonStaticReferenceInStaticContext : 435 case ProblemReasons.ReceiverTypeNotVisible : 436 case ProblemReasons.ParameterBoundMismatch : 437 if (closestMatch != null) this.resolvedType = closestMatch.returnType; 439 default : 440 } 441 if (closestMatch != null) { 443 this.binding = closestMatch; 444 MethodBinding closestMatchOriginal = closestMatch.original(); 445 if ((closestMatchOriginal.isPrivate() || closestMatchOriginal.declaringClass.isLocalType()) && !scope.isDefinedInMethod(closestMatchOriginal)) { 446 closestMatchOriginal.modifiers |= ExtraCompilerModifiers.AccLocallyUsed; 448 } 449 } 450 return this.resolvedType; 451 } 452 final CompilerOptions compilerOptions = scope.compilerOptions(); 453 if (!this.binding.isStatic()) { 454 if (receiverIsType) { 456 scope.problemReporter().mustUseAStaticMethod(this, this.binding); 457 if (this.actualReceiverType.isRawType() 458 && (this.receiver.bits & ASTNode.IgnoreRawTypeCheck) == 0 459 && compilerOptions.getSeverity(CompilerOptions.RawTypeReference) != ProblemSeverities.Ignore) { 460 scope.problemReporter().rawTypeReference(this.receiver, this.actualReceiverType); 461 } 462 } else { 463 this.receiver.computeConversion(scope, this.actualReceiverType, this.actualReceiverType); 464 TypeBinding receiverErasure = this.actualReceiverType.erasure(); 466 if (receiverErasure instanceof ReferenceBinding) { 467 if (receiverErasure.findSuperTypeWithSameErasure(this.binding.declaringClass) == null) { 468 this.receiverGenericCast = this.binding.declaringClass; } 470 } 471 } 472 } else { 473 if (!(this.receiver.isImplicitThis() || this.receiver.isSuper() || receiverIsType)) { 475 scope.problemReporter().nonStaticAccessToStaticMethod(this, this.binding); 476 } 477 if (!this.receiver.isImplicitThis() && this.binding.declaringClass != this.actualReceiverType) { 478 scope.problemReporter().indirectAccessToStaticMethod(this, this.binding); 479 } 480 } 481 checkInvocationArguments(scope, this.receiver, this.actualReceiverType, this.binding, this.arguments, argumentTypes, argsContainCast, this); 482 483 if (this.binding.isAbstract()) { 485 if (this.receiver.isSuper()) { 486 scope.problemReporter().cannotDireclyInvokeAbstractMethod(this, this.binding); 487 } 488 } 490 if (isMethodUseDeprecated(this.binding, scope, true)) 491 scope.problemReporter().deprecatedMethod(this.binding, this); 492 493 if (this.actualReceiverType.isArrayType() 495 && this.binding.parameters == Binding.NO_PARAMETERS 496 && compilerOptions.complianceLevel >= ClassFileConstants.JDK1_5 497 && CharOperation.equals(this.binding.selector, TypeConstants.CLONE)) { 498 this.resolvedType = this.actualReceiverType; 499 } else { 500 TypeBinding returnType = this.binding.returnType; 501 if (returnType != null) returnType = returnType.capture(scope, this.sourceEnd); 502 this.resolvedType = returnType; 503 } 504 if (this.receiver.isSuper() && compilerOptions.getSeverity(CompilerOptions.OverridingMethodWithoutSuperInvocation) != ProblemSeverities.Ignore) { 505 final ReferenceContext referenceContext = scope.methodScope().referenceContext; 506 if (referenceContext instanceof AbstractMethodDeclaration) { 507 final AbstractMethodDeclaration abstractMethodDeclaration = (AbstractMethodDeclaration) referenceContext; 508 MethodBinding enclosingMethodBinding = abstractMethodDeclaration.binding; 509 if (enclosingMethodBinding.isOverriding() 510 && CharOperation.equals(this.binding.selector, enclosingMethodBinding.selector) 511 && this.binding.areParametersEqual(enclosingMethodBinding)) { 512 abstractMethodDeclaration.bits |= ASTNode.OverridingMethodWithSupercall; 513 } 514 } 515 } 516 return this.resolvedType; 517 } 518 519 public void setActualReceiverType(ReferenceBinding receiverType) { 520 if (receiverType == null) return; this.actualReceiverType = receiverType; 522 } 523 public void setDepth(int depth) { 524 this.bits &= ~ASTNode.DepthMASK; if (depth > 0) { 526 this.bits |= (depth & 0xFF) << ASTNode.DepthSHIFT; } 528 } 529 530 533 public void setExpectedType(TypeBinding expectedType) { 534 this.expectedType = expectedType; 535 } 536 public void setFieldIndex(int depth) { 537 } 539 540 public void traverse(ASTVisitor visitor, BlockScope blockScope) { 541 if (visitor.visit(this, blockScope)) { 542 this.receiver.traverse(visitor, blockScope); 543 if (this.typeArguments != null) { 544 for (int i = 0, typeArgumentsLength = this.typeArguments.length; i < typeArgumentsLength; i++) { 545 this.typeArguments[i].traverse(visitor, blockScope); 546 } 547 } 548 if (this.arguments != null) { 549 int argumentsLength = this.arguments.length; 550 for (int i = 0; i < argumentsLength; i++) 551 this.arguments[i].traverse(visitor, blockScope); 552 } 553 } 554 visitor.endVisit(this, blockScope); 555 } 556 } 557 | Popular Tags |