1 11 package org.eclipse.jdt.internal.eval; 12 13 import org.eclipse.jdt.internal.compiler.ast.Assignment; 14 import org.eclipse.jdt.internal.compiler.ast.CompoundAssignment; 15 import org.eclipse.jdt.internal.compiler.ast.Expression; 16 import org.eclipse.jdt.internal.compiler.ast.IntLiteral; 17 import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; 18 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; 19 import org.eclipse.jdt.internal.compiler.codegen.CodeStream; 20 import org.eclipse.jdt.internal.compiler.flow.FlowInfo; 21 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; 22 import org.eclipse.jdt.internal.compiler.impl.Constant; 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.ClassScope; 26 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; 27 import org.eclipse.jdt.internal.compiler.lookup.InvocationSite; 28 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; 29 import org.eclipse.jdt.internal.compiler.lookup.ProblemBinding; 30 import org.eclipse.jdt.internal.compiler.lookup.ProblemFieldBinding; 31 import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; 32 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; 33 import org.eclipse.jdt.internal.compiler.lookup.Scope; 34 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; 35 import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; 36 37 public class CodeSnippetQualifiedNameReference extends QualifiedNameReference implements EvaluationConstants, InvocationSite, ProblemReasons { 38 39 EvaluationContext evaluationContext; 40 FieldBinding delegateThis; 41 47 public CodeSnippetQualifiedNameReference(char[][] sources, long[] positions, int sourceStart, int sourceEnd, EvaluationContext evaluationContext) { 48 super(sources, positions, sourceStart, sourceEnd); 49 this.evaluationContext = evaluationContext; 50 } 51 54 public TypeBinding checkFieldAccess(BlockScope scope) { 55 this.bits &= ~RestrictiveFlagMASK; this.bits |= Binding.FIELD; 58 return getOtherFieldBindings(scope); 59 } 60 public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) { 61 62 FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream); 63 if (lastFieldBinding.canBeSeenBy(getReceiverType(currentScope), this, currentScope)) { 64 assignment.expression.generateCode(currentScope, codeStream, true); 66 fieldStore(codeStream, lastFieldBinding, null, valueRequired); 67 } else { 68 codeStream.generateEmulationForField(lastFieldBinding); 69 codeStream.swap(); 70 assignment.expression.generateCode(currentScope, codeStream, true); 71 if (valueRequired) { 72 if ((lastFieldBinding.type == TypeBinding.LONG) || (lastFieldBinding.type == TypeBinding.DOUBLE)) { 73 codeStream.dup2_x2(); 74 } else { 75 codeStream.dup_x2(); 76 } 77 } 78 codeStream.generateEmulatedWriteAccessForField(lastFieldBinding); 79 } 80 if (valueRequired) { 81 codeStream.generateImplicitConversion(assignment.implicitConversion); 82 } 83 } 84 public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { 85 int pc = codeStream.position; 86 if (this.constant != Constant.NotAConstant) { 87 if (valueRequired) { 88 codeStream.generateConstant(this.constant, this.implicitConversion); 89 } 90 } else { 91 FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream); 92 if (valueRequired) { 93 if (lastFieldBinding.declaringClass == null) { codeStream.arraylength(); 95 codeStream.generateImplicitConversion(this.implicitConversion); 96 } else { 97 Constant fieldConstant = lastFieldBinding.constant(); 98 if (fieldConstant != Constant.NotAConstant) { 99 if (!lastFieldBinding.isStatic()){ 100 codeStream.invokeObjectGetClass(); 101 codeStream.pop(); 102 } 103 codeStream.generateConstant(fieldConstant, this.implicitConversion); 105 } else { 106 if (lastFieldBinding.canBeSeenBy(getReceiverType(currentScope), this, currentScope)) { 107 if (lastFieldBinding.isStatic()) { 108 codeStream.getstatic(lastFieldBinding); 109 } else { 110 codeStream.getfield(lastFieldBinding); 111 } 112 } else { 113 codeStream.generateEmulatedReadAccessForField(lastFieldBinding); 114 } 115 codeStream.generateImplicitConversion(this.implicitConversion); 116 } 117 } 118 } else { 119 if (lastFieldBinding != null && !lastFieldBinding.isStatic()){ 120 codeStream.invokeObjectGetClass(); codeStream.pop(); 122 } 123 } 124 } 125 codeStream.recordPositionsFrom(pc, this.sourceStart); 126 } 127 public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { 128 129 FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream); 130 if (lastFieldBinding.canBeSeenBy(getReceiverType(currentScope), this, currentScope)) { 131 if (lastFieldBinding.isStatic()){ 132 codeStream.getstatic(lastFieldBinding); 133 } else { 134 codeStream.dup(); 135 codeStream.getfield(lastFieldBinding); 136 } 137 int operationTypeID; 140 switch(operationTypeID = (this.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) { 141 case T_JavaLangString : 142 case T_JavaLangObject : 143 case T_undefined : 144 codeStream.generateStringConcatenationAppend(currentScope, null, expression); 145 break; 146 default : 147 codeStream.generateImplicitConversion(this.implicitConversion); 149 if (expression == IntLiteral.One){ codeStream.generateConstant(expression.constant, this.implicitConversion); 152 } else { 153 expression.generateCode(currentScope, codeStream, true); 154 } 155 codeStream.sendOperator(operator, operationTypeID); 157 codeStream.generateImplicitConversion(assignmentImplicitConversion); 159 } 160 fieldStore(codeStream, lastFieldBinding, null, valueRequired); 162 } else { 163 if (lastFieldBinding.isStatic()){ 164 codeStream.generateEmulationForField(lastFieldBinding); 165 codeStream.swap(); 166 codeStream.aconst_null(); 167 codeStream.swap(); 168 169 codeStream.generateEmulatedReadAccessForField(lastFieldBinding); 170 } else { 171 codeStream.generateEmulationForField(lastFieldBinding); 172 codeStream.swap(); 173 codeStream.dup(); 174 175 codeStream.generateEmulatedReadAccessForField(lastFieldBinding); 176 } 177 int operationTypeID; 180 if ((operationTypeID = (this.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) == T_JavaLangString) { 181 codeStream.generateStringConcatenationAppend(currentScope, null, expression); 182 } else { 183 codeStream.generateImplicitConversion(this.implicitConversion); 185 if (expression == IntLiteral.One){ codeStream.generateConstant(expression.constant, this.implicitConversion); 188 } else { 189 expression.generateCode(currentScope, codeStream, true); 190 } 191 codeStream.sendOperator(operator, operationTypeID); 193 codeStream.generateImplicitConversion(assignmentImplicitConversion); 195 } 196 198 if (valueRequired) { 201 if ((lastFieldBinding.type == TypeBinding.LONG) || (lastFieldBinding.type == TypeBinding.DOUBLE)) { 202 codeStream.dup2_x2(); 203 } else { 204 codeStream.dup_x2(); 205 } 206 } 207 codeStream.generateEmulatedWriteAccessForField(lastFieldBinding); 210 } 211 } 212 public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) { 213 214 FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream); 215 if (lastFieldBinding.canBeSeenBy(getReceiverType(currentScope), this, currentScope)) { 216 if (lastFieldBinding.isStatic()){ 217 codeStream.getstatic(lastFieldBinding); 218 } else { 219 codeStream.dup(); 220 codeStream.getfield(lastFieldBinding); 221 } 222 if (valueRequired) { 224 if (lastFieldBinding.isStatic()) { 225 if ((lastFieldBinding.type == TypeBinding.LONG) || (lastFieldBinding.type == TypeBinding.DOUBLE)) { 226 codeStream.dup2(); 227 } else { 228 codeStream.dup(); 229 } 230 } else { if ((lastFieldBinding.type == TypeBinding.LONG) || (lastFieldBinding.type == TypeBinding.DOUBLE)) { 232 codeStream.dup2_x1(); 233 } else { 234 codeStream.dup_x1(); 235 } 236 } 237 } 238 codeStream.generateConstant(postIncrement.expression.constant, this.implicitConversion); 239 codeStream.sendOperator(postIncrement.operator, lastFieldBinding.type.id); 240 codeStream.generateImplicitConversion(postIncrement.preAssignImplicitConversion); 241 242 fieldStore(codeStream, lastFieldBinding, null, false); 243 } else { 244 codeStream.generateEmulatedReadAccessForField(lastFieldBinding); 245 if (valueRequired) { 246 if ((lastFieldBinding.type == TypeBinding.LONG) || (lastFieldBinding.type == TypeBinding.DOUBLE)) { 247 codeStream.dup2(); 248 } else { 249 codeStream.dup(); 250 } 251 } 252 codeStream.generateEmulationForField(lastFieldBinding); 253 if ((lastFieldBinding.type == TypeBinding.LONG) || (lastFieldBinding.type == TypeBinding.DOUBLE)) { 254 codeStream.dup_x2(); 255 codeStream.pop(); 256 if (lastFieldBinding.isStatic()) { 257 codeStream.aconst_null(); 258 } else { 259 generateReadSequence(currentScope, codeStream); 260 } 261 codeStream.dup_x2(); 262 codeStream.pop(); 263 } else { 264 codeStream.dup_x1(); 265 codeStream.pop(); 266 if (lastFieldBinding.isStatic()) { 267 codeStream.aconst_null(); 268 } else { 269 generateReadSequence(currentScope, codeStream); 270 } 271 codeStream.dup_x1(); 272 codeStream.pop(); 273 } 274 codeStream.generateConstant(postIncrement.expression.constant, this.implicitConversion); 275 codeStream.sendOperator(postIncrement.operator, lastFieldBinding.type.id); 276 codeStream.generateImplicitConversion(postIncrement.preAssignImplicitConversion); 277 codeStream.generateEmulatedWriteAccessForField(lastFieldBinding); 278 } 279 } 280 284 public FieldBinding generateReadSequence(BlockScope currentScope, CodeStream codeStream) { 285 286 int otherBindingsCount = this.otherCodegenBindings == null ? 0 : this.otherCodegenBindings.length; 288 boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic(); 289 FieldBinding lastFieldBinding = null; 290 TypeBinding lastGenericCast = null; 291 292 switch (this.bits & RestrictiveFlagMASK) { 293 case Binding.FIELD : 294 lastFieldBinding = (FieldBinding) this.codegenBinding; 295 lastGenericCast = this.genericCast; 296 if (lastFieldBinding.constant() != Constant.NotAConstant) { 298 break; 299 } 300 if (needValue) { 301 if (lastFieldBinding.canBeSeenBy(getReceiverType(currentScope), this, currentScope)) { 302 if (!lastFieldBinding.isStatic()) { 303 if ((this.bits & DepthMASK) != 0) { 304 ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((this.bits & DepthMASK) >> DepthSHIFT); 305 Object [] emulationPath = currentScope.getEmulationPath(targetType, true , false); 306 codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope); 307 } else { 308 generateReceiver(codeStream); 309 } 310 } 311 } else { 312 if (!lastFieldBinding.isStatic()) { 313 if ((this.bits & DepthMASK) != 0) { 314 currentScope.problemReporter().needImplementation(); 317 } else { 318 generateReceiver(codeStream); 319 } 320 } else { 321 codeStream.aconst_null(); 322 } 323 } 324 } 325 break; 326 case Binding.LOCAL : if (!needValue) break; LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; 329 Constant localConstant = localBinding.constant(); 331 if (localConstant != Constant.NotAConstant) { 332 codeStream.generateConstant(localConstant, 0); 333 } else { 335 if ((bits & DepthMASK) != 0) { 337 VariableBinding[] path = currentScope.getEmulationPath(localBinding); 339 codeStream.generateOuterAccess(path, this, localBinding, currentScope); 340 } else { 341 codeStream.load(localBinding); 342 } 343 } 344 } 345 346 if (this.otherCodegenBindings != null) { 349 for (int i = 0; i < otherBindingsCount; i++) { 350 FieldBinding nextField = this.otherCodegenBindings[i]; 351 TypeBinding nextGenericCast = this.otherGenericCasts == null ? null : this.otherGenericCasts[i]; 352 if (lastFieldBinding != null) { 353 needValue = !nextField.isStatic(); 354 if (needValue) { 355 if (lastFieldBinding.canBeSeenBy(getReceiverType(currentScope), this, currentScope)) { 356 Constant fieldConstant = lastFieldBinding.constant(); 357 if (fieldConstant != Constant.NotAConstant) { 358 if (lastFieldBinding != this.codegenBinding && !lastFieldBinding.isStatic()) { 359 codeStream.invokeObjectGetClass(); codeStream.pop(); 361 } 362 codeStream.generateConstant(fieldConstant, 0); 363 } else if (lastFieldBinding.isStatic()) { 364 codeStream.getstatic(lastFieldBinding); 365 } else { 366 codeStream.getfield(lastFieldBinding); 367 } 368 } else { 369 codeStream.generateEmulatedReadAccessForField(lastFieldBinding); 370 } 371 if (lastGenericCast != null) codeStream.checkcast(lastGenericCast); 372 } else { 373 if (this.codegenBinding != lastFieldBinding && !lastFieldBinding.isStatic()){ 374 codeStream.invokeObjectGetClass(); codeStream.pop(); 376 } 377 } 378 } 379 lastFieldBinding = nextField; 380 lastGenericCast = nextGenericCast; 381 if (lastFieldBinding != null && !lastFieldBinding.canBeSeenBy(getReceiverType(currentScope), this, currentScope)) { 382 if (lastFieldBinding.isStatic()) { 383 codeStream.aconst_null(); 384 } 385 } 386 } 387 } 388 return lastFieldBinding; 389 } 390 391 public void generateReceiver(CodeStream codeStream) { 392 codeStream.aload_0(); 393 if (this.delegateThis != null) { 394 codeStream.getfield(this.delegateThis); } 396 } 397 public TypeBinding getOtherFieldBindings(BlockScope scope) { 398 400 int length = this.tokens.length; 401 if ((this.bits & Binding.FIELD) != 0) { 402 if (!((FieldBinding) this.binding).isStatic()) { if (this.indexOfFirstFieldBinding == 1) { 404 if (scope.methodScope().isStatic) { 406 scope.problemReporter().staticFieldAccessToNonStaticVariable(this, (FieldBinding) this.binding); 407 return null; 408 } 409 } else { scope.problemReporter().staticFieldAccessToNonStaticVariable(this, (FieldBinding) this.binding); 411 return null; 412 } 413 } 414 if (isFieldUseDeprecated((FieldBinding) this.binding, scope, (this.bits & IsStrictlyAssigned) !=0 && this.indexOfFirstFieldBinding == length)) { 416 scope.problemReporter().deprecatedField((FieldBinding) this.binding, this); 417 } 418 } 419 420 TypeBinding type = ((VariableBinding) this.binding).type; 421 int index = this.indexOfFirstFieldBinding; 422 if (index == length) { this.constant = ((FieldBinding) this.binding).constant(); 424 return type; 425 } 426 427 int otherBindingsLength = length - index; 429 this.otherCodegenBindings = this.otherBindings = new FieldBinding[otherBindingsLength]; 430 431 this.constant =((VariableBinding) this.binding).constant(); 433 434 while (index < length) { 436 char[] token = this.tokens[index]; 437 if (type == null) return null; FieldBinding field = scope.getField(type, token, this); 439 int place = index - this.indexOfFirstFieldBinding; 440 this.otherBindings[place] = field; 441 if (!field.isValidBinding()) { 442 CodeSnippetScope localScope = new CodeSnippetScope(scope); 444 if (this.delegateThis == null) { 445 if (this.evaluationContext.declaringTypeName != null) { 446 this.delegateThis = scope.getField(scope.enclosingSourceType(), DELEGATE_THIS, this); 447 if (this.delegateThis == null){ return super.reportError(scope); 449 } 450 } else { 451 this.constant = Constant.NotAConstant; scope.problemReporter().invalidField(this, field, index, type); 453 return null; 454 } 455 } 456 field = localScope.getFieldForCodeSnippet(this.delegateThis.type, token, this); 457 this.otherBindings[place] = field; 458 } 459 if (field.isValidBinding()) { 460 if (isFieldUseDeprecated(field, scope, (this.bits & IsStrictlyAssigned) !=0 && index+1 == length)) { 462 scope.problemReporter().deprecatedField(field, this); 463 } 464 if (this.constant != Constant.NotAConstant){ 466 this.constant = field.constant(); 467 } 468 type = field.type; 469 index++; 470 } else { 471 this.constant = Constant.NotAConstant; scope.problemReporter().invalidField(this, field, index, type); 473 return null; 474 } 475 } 476 return (this.otherBindings[otherBindingsLength - 1]).type; 477 } 478 481 public TypeBinding getReceiverType(BlockScope currentScope) { 482 Scope scope = currentScope.parent; 483 while (true) { 484 switch (scope.kind) { 485 case Scope.CLASS_SCOPE : 486 return ((ClassScope) scope).referenceContext.binding; 487 default: 488 scope = scope.parent; 489 } 490 } 491 } 492 495 public void manageSyntheticAccessIfNecessary( 496 BlockScope currentScope, 497 FieldBinding fieldBinding, 498 TypeBinding lastReceiverType, 499 int index, 500 FlowInfo flowInfo) { 501 502 if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) return; 503 504 boolean useDelegate; 508 if (index < 0) { useDelegate = fieldBinding == this.binding && this.delegateThis != null; 510 } else { 511 useDelegate = index == 0 && this.delegateThis != null; 512 } 513 514 if (useDelegate) { 515 lastReceiverType = this.delegateThis.type; 516 } 517 if (fieldBinding.declaringClass != lastReceiverType 522 && !lastReceiverType.isArrayType() 523 && fieldBinding.declaringClass != null && fieldBinding.constant() == Constant.NotAConstant) { 525 CompilerOptions options = currentScope.compilerOptions(); 526 if ((options.targetJDK >= ClassFileConstants.JDK1_2 527 && (options.complianceLevel >= ClassFileConstants.JDK1_4 || (index < 0 ? fieldBinding != binding : index > 0) || this.indexOfFirstFieldBinding > 1 || !fieldBinding.isStatic()) 528 && fieldBinding.declaringClass.id != T_JavaLangObject) || !(useDelegate 530 ? new CodeSnippetScope(currentScope).canBeSeenByForCodeSnippet(fieldBinding.declaringClass, (ReferenceBinding) this.delegateThis.type) 531 : fieldBinding.declaringClass.canBeSeenBy(currentScope))) { 532 533 if (index < 0) { if (fieldBinding == this.binding){ 535 this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType.erasure()); 536 } else { 537 if (this.otherCodegenBindings == this.otherBindings){ 538 int l = this.otherBindings.length; 539 System.arraycopy(this.otherBindings, 0, this.otherCodegenBindings = new FieldBinding[l], 0, l); 540 } 541 this.otherCodegenBindings[this.otherCodegenBindings.length-1] = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType.erasure()); 542 } 543 } if (index == 0){ 544 this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType.erasure()); 545 } else { 546 if (this.otherCodegenBindings == this.otherBindings){ 547 int l = this.otherBindings.length; 548 System.arraycopy(this.otherBindings, 0, this.otherCodegenBindings = new FieldBinding[l], 0, l); 549 } 550 this.otherCodegenBindings[index-1] = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType.erasure()); 551 } 552 } 553 } 554 } 555 558 public TypeBinding reportError(BlockScope scope) { 559 560 if (this.evaluationContext.declaringTypeName != null) { 561 this.delegateThis = scope.getField(scope.enclosingSourceType(), DELEGATE_THIS, this); 562 if (this.delegateThis == null){ return super.reportError(scope); 564 } 565 } else { 566 return super.reportError(scope); 567 } 568 569 if ((this.binding instanceof ProblemFieldBinding && ((ProblemFieldBinding) this.binding).problemId() == NotFound) 570 || (this.binding instanceof ProblemBinding && ((ProblemBinding) this.binding).problemId() == NotFound)){ 571 FieldBinding fieldBinding = scope.getField(this.delegateThis.type, this.tokens[0], this); 573 if (!fieldBinding.isValidBinding()) { 574 if (((ProblemFieldBinding) fieldBinding).problemId() == NotVisible) { 575 CodeSnippetScope localScope = new CodeSnippetScope(scope); 577 this.codegenBinding = this.binding = localScope.getFieldForCodeSnippet(this.delegateThis.type, this.tokens[0], this); 578 if (this.binding.isValidBinding()) { 579 return checkFieldAccess(scope); 580 } else { 581 return super.reportError(scope); 582 } 583 } else { 584 return super.reportError(scope); 585 } 586 } 587 this.codegenBinding = this.binding = fieldBinding; 588 return checkFieldAccess(scope); 589 } 590 591 TypeBinding result; 592 if (this.binding instanceof ProblemFieldBinding 593 && ((ProblemFieldBinding) this.binding).problemId() == NotVisible) { 594 result = resolveTypeVisibility(scope); 595 if (result == null) { 596 return super.reportError(scope); 597 } 598 if (result.isValidBinding()) { 599 return result; 600 } 601 } 602 603 return super.reportError(scope); 604 } 605 public TypeBinding resolveTypeVisibility(BlockScope scope) { 606 608 611 CodeSnippetScope localScope = new CodeSnippetScope(scope); 612 if ((this.codegenBinding = this.binding = localScope.getBinding(this.tokens, this.bits & RestrictiveFlagMASK, this, (ReferenceBinding) this.delegateThis.type)).isValidBinding()) { 613 this.bits &= ~RestrictiveFlagMASK; this.bits |= Binding.FIELD; 615 return getOtherFieldBindings(scope); 616 } 617 return super.reportError(scope); 619 } 620 } 621 | Popular Tags |