1 11 package org.eclipse.jdt.internal.compiler.ast; 12 13 import org.eclipse.jdt.internal.compiler.ASTVisitor; 14 import org.eclipse.jdt.internal.compiler.impl.*; 15 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; 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 20 public class FieldReference extends Reference implements InvocationSite { 21 22 public static final int READ = 0; 23 public static final int WRITE = 1; 24 public Expression receiver; 25 public char[] token; 26 public FieldBinding binding; protected FieldBinding codegenBinding; public MethodBinding[] syntheticAccessors; 30 public long nameSourcePosition; public TypeBinding receiverType; 32 public TypeBinding genericCast; 33 34 public FieldReference(char[] source, long pos) { 35 token = source; 36 nameSourcePosition = pos; 37 sourceStart = (int) (pos >>> 32); 39 sourceEnd = (int) (pos & 0x00000000FFFFFFFFL); 40 bits |= Binding.FIELD; 41 42 } 43 44 public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) { 45 if (isCompound) { if (binding.isBlankFinal() 48 && receiver.isThis() 49 && currentScope.allowBlankFinalFieldAssignment(binding) 50 && (!flowInfo.isDefinitelyAssigned(binding))) { 51 currentScope.problemReporter().uninitializedBlankFinalField(binding, this); 52 } 54 manageSyntheticAccessIfNecessary(currentScope, flowInfo, true ); 55 } 56 flowInfo = 57 receiver 58 .analyseCode(currentScope, flowContext, flowInfo, !binding.isStatic()) 59 .unconditionalInits(); 60 if (assignment.expression != null) { 61 flowInfo = 62 assignment 63 .expression 64 .analyseCode(currentScope, flowContext, flowInfo) 65 .unconditionalInits(); 66 } 67 manageSyntheticAccessIfNecessary(currentScope, flowInfo, false ); 68 69 if (binding.isFinal()) { 71 if (binding.isBlankFinal() 73 && !isCompound 74 && receiver.isThis() 75 && !(receiver instanceof QualifiedThisReference) 76 && ((receiver.bits & ParenthesizedMASK) == 0) && currentScope.allowBlankFinalFieldAssignment(binding)) { 78 if (flowInfo.isPotentiallyAssigned(binding)) { 79 currentScope.problemReporter().duplicateInitializationOfBlankFinalField( 80 binding, 81 this); 82 } else { 83 flowContext.recordSettingFinal(binding, this, flowInfo); 84 } 85 flowInfo.markAsDefinitelyAssigned(binding); 86 } else { 87 currentScope.problemReporter().cannotAssignToFinalField(binding, this); 89 } 90 } 91 return flowInfo; 92 } 93 94 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { 95 return analyseCode(currentScope, flowContext, flowInfo, true); 96 } 97 98 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { 99 boolean nonStatic = !binding.isStatic(); 100 receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic); 101 if (nonStatic) { 102 receiver.checkNPE(currentScope, flowContext, flowInfo); 103 } 104 105 if (valueRequired || currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) { 106 manageSyntheticAccessIfNecessary(currentScope, flowInfo, true ); 107 } 108 return flowInfo; 109 } 110 111 114 public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) { 115 if (runtimeTimeType == null || compileTimeType == null) 116 return; 117 if (this.binding != null && this.binding.isValidBinding()) { 119 FieldBinding originalBinding = this.binding.original(); 120 TypeBinding originalType = originalBinding.type; 121 if (originalBinding != this.binding 123 && originalType != this.binding.type 124 && runtimeTimeType.id != T_JavaLangObject 125 && (originalType.tagBits & TagBits.HasTypeVariable) != 0) { 126 TypeBinding targetType = (!compileTimeType.isBaseType() && runtimeTimeType.isBaseType()) 127 ? compileTimeType : runtimeTimeType; 129 this.genericCast = originalBinding.type.genericCast(targetType); 130 } 131 } 132 super.computeConversion(scope, runtimeTimeType, compileTimeType); 133 } 134 135 public FieldBinding fieldBinding() { 136 return binding; 137 } 138 139 public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) { 140 int pc = codeStream.position; 141 receiver.generateCode( 142 currentScope, 143 codeStream, 144 !this.codegenBinding.isStatic()); 145 codeStream.recordPositionsFrom(pc, this.sourceStart); 146 assignment.expression.generateCode(currentScope, codeStream, true); 147 fieldStore( 148 codeStream, 149 this.codegenBinding, 150 syntheticAccessors == null ? null : syntheticAccessors[WRITE], 151 valueRequired); 152 if (valueRequired) { 153 codeStream.generateImplicitConversion(assignment.implicitConversion); 154 } 155 } 157 158 165 public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { 166 int pc = codeStream.position; 167 if (constant != Constant.NotAConstant) { 168 if (valueRequired) { 169 codeStream.generateConstant(constant, implicitConversion); 170 } 171 codeStream.recordPositionsFrom(pc, this.sourceStart); 172 return; 173 } 174 boolean isStatic = this.codegenBinding.isStatic(); 175 boolean isThisReceiver = this.receiver instanceof ThisReference; 176 Constant fieldConstant = this.codegenBinding.constant(); 177 if (fieldConstant != Constant.NotAConstant) { 178 if (!isThisReceiver) { 179 receiver.generateCode(currentScope, codeStream, !isStatic); 180 if (!isStatic){ 181 codeStream.invokeObjectGetClass(); 182 codeStream.pop(); 183 } 184 } 185 if (valueRequired) { 186 codeStream.generateConstant(fieldConstant, implicitConversion); 187 } 188 codeStream.recordPositionsFrom(pc, this.sourceStart); 189 return; 190 } 191 if (valueRequired 192 || (!isThisReceiver && currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) 193 || ((implicitConversion & TypeIds.UNBOXING) != 0) 194 || (this.genericCast != null)) { 195 receiver.generateCode(currentScope, codeStream, !isStatic); 196 pc = codeStream.position; 197 if (this.codegenBinding.declaringClass == null) { codeStream.arraylength(); 199 if (valueRequired) { 200 codeStream.generateImplicitConversion(implicitConversion); 201 } else { 202 codeStream.pop(); 204 } 205 } else { 206 if (syntheticAccessors == null || syntheticAccessors[READ] == null) { 207 if (isStatic) { 208 codeStream.getstatic(this.codegenBinding); 209 } else { 210 codeStream.getfield(this.codegenBinding); 211 } 212 } else { 213 codeStream.invokestatic(syntheticAccessors[READ]); 214 } 215 if (this.genericCast != null) codeStream.checkcast(this.genericCast); 217 if (valueRequired) { 218 codeStream.generateImplicitConversion(implicitConversion); 219 } else { 220 boolean isUnboxing = (implicitConversion & TypeIds.UNBOXING) != 0; 221 if (isUnboxing) codeStream.generateImplicitConversion(implicitConversion); 223 switch (isUnboxing ? postConversionType(currentScope).id : this.codegenBinding.type.id) { 224 case T_long : 225 case T_double : 226 codeStream.pop2(); 227 break; 228 default : 229 codeStream.pop(); 230 } 231 } 232 } 233 } else { 234 if (isThisReceiver) { 235 if (isStatic){ 236 if (this.binding.original().declaringClass != this.receiverType.erasure()) { 238 MethodBinding accessor = syntheticAccessors == null ? null : syntheticAccessors[READ]; 239 if (accessor == null) { 240 codeStream.getstatic(this.codegenBinding); 241 } else { 242 codeStream.invokestatic(accessor); 243 } 244 switch (this.codegenBinding.type.id) { 245 case T_long : 246 case T_double : 247 codeStream.pop2(); 248 break; 249 default : 250 codeStream.pop(); 251 } 252 } 253 } 254 } else { 255 receiver.generateCode(currentScope, codeStream, !isStatic); 256 if (!isStatic){ 257 codeStream.invokeObjectGetClass(); codeStream.pop(); 259 } 260 } 261 } 262 codeStream.recordPositionsFrom(pc, this.sourceEnd); 263 } 264 265 public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { 266 boolean isStatic; 267 receiver.generateCode( 268 currentScope, 269 codeStream, 270 !(isStatic = this.codegenBinding.isStatic())); 271 if (isStatic) { 272 if (syntheticAccessors == null || syntheticAccessors[READ] == null) { 273 codeStream.getstatic(this.codegenBinding); 274 } else { 275 codeStream.invokestatic(syntheticAccessors[READ]); 276 } 277 } else { 278 codeStream.dup(); 279 if (syntheticAccessors == null || syntheticAccessors[READ] == null) { 280 codeStream.getfield(this.codegenBinding); 281 } else { 282 codeStream.invokestatic(syntheticAccessors[READ]); 283 } 284 } 285 int operationTypeID; 286 switch(operationTypeID = (implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) { 287 case T_JavaLangString : 288 case T_JavaLangObject : 289 case T_undefined : 290 codeStream.generateStringConcatenationAppend(currentScope, null, expression); 291 break; 292 default : 293 if (this.genericCast != null) 294 codeStream.checkcast(this.genericCast); 295 codeStream.generateImplicitConversion(implicitConversion); 297 if (expression == IntLiteral.One) { codeStream.generateConstant(expression.constant, implicitConversion); 300 } else { 301 expression.generateCode(currentScope, codeStream, true); 302 } 303 codeStream.sendOperator(operator, operationTypeID); 305 codeStream.generateImplicitConversion(assignmentImplicitConversion); 307 } 308 fieldStore( 309 codeStream, 310 this.codegenBinding, 311 syntheticAccessors == null ? null : syntheticAccessors[WRITE], 312 valueRequired); 313 } 315 316 public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) { 317 boolean isStatic; 318 receiver.generateCode( 319 currentScope, 320 codeStream, 321 !(isStatic = this.codegenBinding.isStatic())); 322 if (isStatic) { 323 if (syntheticAccessors == null || syntheticAccessors[READ] == null) { 324 codeStream.getstatic(this.codegenBinding); 325 } else { 326 codeStream.invokestatic(syntheticAccessors[READ]); 327 } 328 } else { 329 codeStream.dup(); 330 if (syntheticAccessors == null || syntheticAccessors[READ] == null) { 331 codeStream.getfield(this.codegenBinding); 332 } else { 333 codeStream.invokestatic(syntheticAccessors[READ]); 334 } 335 } 336 if (valueRequired) { 337 if (isStatic) { 338 if ((this.codegenBinding.type == TypeBinding.LONG) 339 || (this.codegenBinding.type == TypeBinding.DOUBLE)) { 340 codeStream.dup2(); 341 } else { 342 codeStream.dup(); 343 } 344 } else { if ((this.codegenBinding.type == TypeBinding.LONG) 346 || (this.codegenBinding.type == TypeBinding.DOUBLE)) { 347 codeStream.dup2_x1(); 348 } else { 349 codeStream.dup_x1(); 350 } 351 } 352 } 353 if (this.genericCast != null) 354 codeStream.checkcast(this.genericCast); 355 codeStream.generateImplicitConversion(this.implicitConversion); 356 codeStream.generateConstant( 357 postIncrement.expression.constant, 358 this.implicitConversion); 359 codeStream.sendOperator(postIncrement.operator, this.implicitConversion & COMPILE_TYPE_MASK); 360 codeStream.generateImplicitConversion( 361 postIncrement.preAssignImplicitConversion); 362 fieldStore(codeStream, this.codegenBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], false); 363 } 364 365 368 public TypeBinding[] genericTypeArguments() { 369 return null; 370 } 371 public boolean isSuperAccess() { 372 return receiver.isSuper(); 373 } 374 375 public boolean isTypeAccess() { 376 return receiver != null && receiver.isTypeReference(); 377 } 378 379 382 public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo, boolean isReadAccess) { 383 if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) return; 384 385 this.codegenBinding = this.binding.original(); 387 388 if (binding.isPrivate()) { 389 if ((currentScope.enclosingSourceType() != this.codegenBinding.declaringClass) 390 && binding.constant() == Constant.NotAConstant) { 391 if (syntheticAccessors == null) 392 syntheticAccessors = new MethodBinding[2]; 393 syntheticAccessors[isReadAccess ? READ : WRITE] = 394 ((SourceTypeBinding) this.codegenBinding.declaringClass).addSyntheticMethod(this.codegenBinding, isReadAccess); 395 currentScope.problemReporter().needToEmulateFieldAccess(this.codegenBinding, this, isReadAccess); 396 return; 397 } 398 399 } else if (receiver instanceof QualifiedSuperReference) { 401 SourceTypeBinding destinationType = 403 (SourceTypeBinding) (((QualifiedSuperReference) receiver) 404 .currentCompatibleType); 405 if (syntheticAccessors == null) 406 syntheticAccessors = new MethodBinding[2]; 407 syntheticAccessors[isReadAccess ? READ : WRITE] = destinationType.addSyntheticMethod(this.codegenBinding, isReadAccess); 408 currentScope.problemReporter().needToEmulateFieldAccess(this.codegenBinding, this, isReadAccess); 409 return; 410 411 } else if (binding.isProtected()) { 412 413 SourceTypeBinding enclosingSourceType; 414 if (((bits & DepthMASK) != 0) 415 && binding.declaringClass.getPackage() 416 != (enclosingSourceType = currentScope.enclosingSourceType()).getPackage()) { 417 418 SourceTypeBinding currentCompatibleType = 419 (SourceTypeBinding) enclosingSourceType.enclosingTypeAt( 420 (bits & DepthMASK) >> DepthSHIFT); 421 if (syntheticAccessors == null) 422 syntheticAccessors = new MethodBinding[2]; 423 syntheticAccessors[isReadAccess ? READ : WRITE] = currentCompatibleType.addSyntheticMethod(this.codegenBinding, isReadAccess); 424 currentScope.problemReporter().needToEmulateFieldAccess(this.codegenBinding, this, isReadAccess); 425 return; 426 } 427 } 428 if (this.binding.declaringClass != this.receiverType 433 && !this.receiverType.isArrayType() 434 && this.binding.declaringClass != null && this.binding.constant() == Constant.NotAConstant) { 436 CompilerOptions options = currentScope.compilerOptions(); 437 if ((options.targetJDK >= ClassFileConstants.JDK1_2 438 && (options.complianceLevel >= ClassFileConstants.JDK1_4 || !(receiver.isImplicitThis() && this.codegenBinding.isStatic())) 439 && this.binding.declaringClass.id != T_JavaLangObject) || !this.binding.declaringClass.canBeSeenBy(currentScope)) { 441 442 this.codegenBinding = 443 currentScope.enclosingSourceType().getUpdatedFieldBinding( 444 this.codegenBinding, 445 (ReferenceBinding) this.receiverType.erasure()); 446 } 447 } 448 } 449 450 public int nullStatus(FlowInfo flowInfo) { 451 return FlowInfo.UNKNOWN; 452 } 453 454 public Constant optimizedBooleanConstant() { 455 switch (this.resolvedType.id) { 456 case T_boolean : 457 case T_JavaLangBoolean : 458 return this.constant != Constant.NotAConstant ? this.constant : this.binding.constant(); 459 default : 460 return Constant.NotAConstant; 461 } 462 } 463 464 467 public TypeBinding postConversionType(Scope scope) { 468 TypeBinding convertedType = this.resolvedType; 469 if (this.genericCast != null) 470 convertedType = this.genericCast; 471 int runtimeType = (this.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4; 472 switch (runtimeType) { 473 case T_boolean : 474 convertedType = TypeBinding.BOOLEAN; 475 break; 476 case T_byte : 477 convertedType = TypeBinding.BYTE; 478 break; 479 case T_short : 480 convertedType = TypeBinding.SHORT; 481 break; 482 case T_char : 483 convertedType = TypeBinding.CHAR; 484 break; 485 case T_int : 486 convertedType = TypeBinding.INT; 487 break; 488 case T_float : 489 convertedType = TypeBinding.FLOAT; 490 break; 491 case T_long : 492 convertedType = TypeBinding.LONG; 493 break; 494 case T_double : 495 convertedType = TypeBinding.DOUBLE; 496 break; 497 default : 498 } 499 if ((this.implicitConversion & BOXING) != 0) { 500 convertedType = scope.environment().computeBoxingType(convertedType); 501 } 502 return convertedType; 503 } 504 505 public StringBuffer printExpression(int indent, StringBuffer output) { 506 return receiver.printExpression(0, output).append('.').append(token); 507 } 508 509 public TypeBinding resolveType(BlockScope scope) { 510 514 boolean receiverCast = false; 516 if (this.receiver instanceof CastExpression) { 517 this.receiver.bits |= DisableUnnecessaryCastCheck; receiverCast = true; 519 } 520 this.receiverType = receiver.resolveType(scope); 521 if (this.receiverType == null) { 522 constant = Constant.NotAConstant; 523 return null; 524 } 525 if (receiverCast) { 526 if (((CastExpression)this.receiver).expression.resolvedType == this.receiverType) { 528 scope.problemReporter().unnecessaryCast((CastExpression)this.receiver); 529 } 530 } 531 FieldBinding fieldBinding = this.codegenBinding = this.binding = scope.getField(this.receiverType, token, this); 533 if (!fieldBinding.isValidBinding()) { 534 constant = Constant.NotAConstant; 535 scope.problemReporter().invalidField(this, this.receiverType); 536 return null; 537 } 538 TypeBinding receiverErasure = this.receiverType.erasure(); 539 if (receiverErasure instanceof ReferenceBinding) { 540 if (receiverErasure.findSuperTypeWithSameErasure(fieldBinding.declaringClass) == null) { 541 this.receiverType = fieldBinding.declaringClass; } 543 } 544 this.receiver.computeConversion(scope, this.receiverType, this.receiverType); 545 if (isFieldUseDeprecated(fieldBinding, scope, (this.bits & IsStrictlyAssigned) !=0)) { 546 scope.problemReporter().deprecatedField(fieldBinding, this); 547 } 548 boolean isImplicitThisRcv = receiver.isImplicitThis(); 549 constant = isImplicitThisRcv ? fieldBinding.constant() : Constant.NotAConstant; 550 if (fieldBinding.isStatic()) { 551 if (!(isImplicitThisRcv 553 || (receiver instanceof NameReference 554 && (((NameReference) receiver).bits & Binding.TYPE) != 0))) { 555 scope.problemReporter().nonStaticAccessToStaticField(this, fieldBinding); 556 } 557 if (!isImplicitThisRcv 558 && fieldBinding.declaringClass != receiverType 559 && fieldBinding.declaringClass.canBeSeenBy(scope)) { 560 scope.problemReporter().indirectAccessToStaticField(this, fieldBinding); 561 } 562 } 563 return this.resolvedType = 565 (((this.bits & IsStrictlyAssigned) == 0) 566 ? fieldBinding.type.capture(scope, this.sourceEnd) 567 : fieldBinding.type); 568 } 569 570 public void setActualReceiverType(ReferenceBinding receiverType) { 571 } 573 574 public void setDepth(int depth) { 575 bits &= ~DepthMASK; if (depth > 0) { 577 bits |= (depth & 0xFF) << DepthSHIFT; } 579 } 580 581 public void setFieldIndex(int index) { 582 } 584 585 public void traverse(ASTVisitor visitor, BlockScope scope) { 586 if (visitor.visit(this, scope)) { 587 receiver.traverse(visitor, scope); 588 } 589 visitor.endVisit(this, scope); 590 } 591 } 592 | Popular Tags |