/******************************************************************************* | |
* Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Common Public License v0.5 | |
* which accompanies this distribution, and is available at | |
* http://www.eclipse.org/legal/cpl-v05.html | |
* | |
* Contributors: | |
* IBM Corporation - initial API and implementation | |
******************************************************************************/ | |
package org.eclipse.jdt.internal.eval; | |
import org.eclipse.jdt.internal.compiler.ast.Assignment; | |
import org.eclipse.jdt.internal.compiler.ast.BinaryExpression; | |
import org.eclipse.jdt.internal.compiler.ast.CompoundAssignment; | |
import org.eclipse.jdt.internal.compiler.ast.Expression; | |
import org.eclipse.jdt.internal.compiler.ast.FieldReference; | |
import org.eclipse.jdt.internal.compiler.ast.IntLiteral; | |
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; | |
import org.eclipse.jdt.internal.compiler.codegen.CodeStream; | |
import org.eclipse.jdt.internal.compiler.flow.FlowContext; | |
import org.eclipse.jdt.internal.compiler.flow.FlowInfo; | |
import org.eclipse.jdt.internal.compiler.impl.Constant; | |
import org.eclipse.jdt.internal.compiler.lookup.BlockScope; | |
import org.eclipse.jdt.internal.compiler.lookup.ClassScope; | |
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; | |
import org.eclipse.jdt.internal.compiler.lookup.InvocationSite; | |
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; | |
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; | |
import org.eclipse.jdt.internal.compiler.lookup.ProblemBinding; | |
import org.eclipse.jdt.internal.compiler.lookup.ProblemFieldBinding; | |
import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; | |
import org.eclipse.jdt.internal.compiler.lookup.Scope; | |
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; | |
import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; | |
/** | |
* A single name reference inside a code snippet can denote a field of a remote | |
* receiver object (i.e. the one of the context in the stack frame). | |
*/ | |
public class CodeSnippetSingleNameReference extends SingleNameReference implements EvaluationConstants, InvocationSite, ProblemReasons { | |
EvaluationContext evaluationContext; | |
FieldBinding delegateThis; | |
public CodeSnippetSingleNameReference(char[] source, long pos, EvaluationContext evaluationContext) { | |
super(source, pos); | |
this.evaluationContext = evaluationContext; | |
} | |
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { | |
switch (bits & RestrictiveFlagMASK) { | |
case FIELD : // reading a field | |
// check if reading a final blank field | |
FieldBinding fieldBinding; | |
if ((fieldBinding = (FieldBinding) binding).isFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) { | |
if (!flowInfo.isDefinitelyAssigned(fieldBinding)) { | |
currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); | |
} | |
} | |
break; | |
case LOCAL : // reading a local variable | |
LocalVariableBinding localBinding; | |
if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) { | |
currentScope.problemReporter().uninitializedLocalVariable(localBinding, this); | |
} | |
if (!flowInfo.isFakeReachable()) localBinding.used = true; | |
} | |
return flowInfo; | |
} | |
/** | |
* Check and/or redirect the field access to the delegate receiver if any | |
*/ | |
public TypeBinding checkFieldAccess(BlockScope scope) { | |
if (delegateThis == null) return super.checkFieldAccess(scope); | |
FieldBinding fieldBinding = (FieldBinding) binding; | |
bits &= ~RestrictiveFlagMASK; // clear bits | |
bits |= FIELD; | |
if (!fieldBinding.isStatic()) { | |
// must check for the static status.... | |
if (this.evaluationContext.isStatic) { | |
scope.problemReporter().staticFieldAccessToNonStaticVariable( | |
this, | |
fieldBinding); | |
constant = NotAConstant; | |
return null; | |
} | |
} | |
constant = FieldReference.getConstantFor(fieldBinding, true, this, scope, 0); | |
if (isFieldUseDeprecated(fieldBinding, scope)) | |
scope.problemReporter().deprecatedField(fieldBinding, this); | |
return fieldBinding.type; | |
} | |
public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) { | |
// optimizing assignment like: i = i + 1 or i = 1 + i | |
if (assignment.expression.isCompactableOperation()) { | |
BinaryExpression operation = (BinaryExpression) assignment.expression; | |
SingleNameReference variableReference; | |
if ((operation.left instanceof SingleNameReference) && ((variableReference = (SingleNameReference) operation.left).binding == binding)) { | |
// i = i + value, then use the variable on the right hand side, since it has the correct implicit conversion | |
variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.right, (operation.bits & OperatorMASK) >> OperatorSHIFT, operation.left.implicitConversion /*should be equivalent to no conversion*/, valueRequired); | |
return; | |
} | |
int operator = (operation.bits & OperatorMASK) >> OperatorSHIFT; | |
if ((operation.right instanceof SingleNameReference) | |
&& ((operator == PLUS) || (operator == MULTIPLY)) // only commutative operations | |
&& ((variableReference = (SingleNameReference) operation.right).binding == binding) | |
&& (operation.left.constant != NotAConstant) // exclude non constant expressions, since could have side-effect | |
&& ((operation.left.implicitConversion >> 4) != T_String) // exclude string concatenation which would occur backwards | |
&& ((operation.right.implicitConversion >> 4) != T_String)) { // exclude string concatenation which would occur backwards | |
// i = value + i, then use the variable on the right hand side, since it has the correct implicit conversion | |
variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.left, operator, operation.right.implicitConversion /*should be equivalent to no conversion*/, valueRequired); | |
return; | |
} | |
} | |
switch (bits & RestrictiveFlagMASK) { | |
case FIELD : // assigning to a field | |
FieldBinding fieldBinding = (FieldBinding) this.codegenBinding; | |
if (fieldBinding.canBeSeenBy(getReceiverType(currentScope), this, currentScope)) { | |
if (!fieldBinding.isStatic()) { // need a receiver? | |
if ((bits & DepthMASK) != 0) { | |
Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)); | |
if (emulationPath == null) { | |
// internal error, per construction we should have found it | |
currentScope.problemReporter().needImplementation(); | |
} else { | |
codeStream.generateOuterAccess(emulationPath, this, currentScope); | |
} | |
} else { | |
this.generateReceiver(codeStream); | |
} | |
} | |
assignment.expression.generateCode(currentScope, codeStream, true); | |
fieldStore(codeStream, fieldBinding, null, valueRequired); | |
if (valueRequired) { | |
codeStream.generateImplicitConversion(assignment.implicitConversion); | |
} | |
} else { | |
((CodeSnippetCodeStream) codeStream).generateEmulationForField(fieldBinding); | |
if (!fieldBinding.isStatic()) { // need a receiver? | |
if ((bits & DepthMASK) != 0) { | |
// internal error, per construction we should have found it | |
// not yet supported | |
currentScope.problemReporter().needImplementation(); | |
} else { | |
this.generateReceiver(codeStream); | |
} | |
} else { | |
codeStream.aconst_null(); | |
} | |
assignment.expression.generateCode(currentScope, codeStream, true); | |
if (valueRequired) { | |
if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) { | |
codeStream.dup2_x2(); | |
} else { | |
codeStream.dup_x2(); | |
} | |
} | |
((CodeSnippetCodeStream) codeStream).generateEmulatedWriteAccessForField(fieldBinding); | |
if (valueRequired) { | |
codeStream.generateImplicitConversion(assignment.implicitConversion); | |
} | |
} | |
return; | |
case LOCAL : // assigning to a local variable | |
LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; | |
if (localBinding.resolvedPosition != -1) { | |
assignment.expression.generateCode(currentScope, codeStream, true); | |
} else { | |
if (assignment.expression.constant != NotAConstant) { | |
// assigning an unused local to a constant value = no actual assignment is necessary | |
if (valueRequired) { | |
codeStream.generateConstant(assignment.expression.constant, assignment.implicitConversion); | |
} | |
} else { | |
assignment.expression.generateCode(currentScope, codeStream, true); | |
/* Even though the value may not be required, we force it to be produced, and discard it later | |
on if it was actually not necessary, so as to provide the same behavior as JDK1.2beta3. */ | |
if (valueRequired) { | |
codeStream.generateImplicitConversion(assignment.implicitConversion); // implicit conversion | |
} else { | |
if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) { | |
codeStream.pop2(); | |
} else { | |
codeStream.pop(); | |
} | |
} | |
} | |
return; | |
} | |
// normal local assignment (since cannot store in outer local which are final locations) | |
codeStream.store(localBinding, valueRequired); | |
if ((bits & FirstAssignmentToLocalMASK) != 0) { // for local variable debug attributes | |
localBinding.recordInitializationStartPC(codeStream.position); | |
} | |
// implicit conversion | |
if (valueRequired) { | |
codeStream.generateImplicitConversion(assignment.implicitConversion); | |
} | |
} | |
} | |
public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { | |
int pc = codeStream.position; | |
if (constant != NotAConstant) { | |
if (valueRequired) { | |
codeStream.generateConstant(constant, implicitConversion); | |
} | |
} else { | |
switch (bits & RestrictiveFlagMASK) { | |
case FIELD : // reading a field | |
FieldBinding fieldBinding; | |
if (valueRequired) { | |
if ((fieldBinding = (FieldBinding) this.codegenBinding).constant == NotAConstant) { // directly use inlined value for constant fields | |
if (fieldBinding.canBeSeenBy(getReceiverType(currentScope), this, currentScope)) { | |
// directly use inlined value for constant fields | |
boolean isStatic; | |
if (!(isStatic = fieldBinding.isStatic())) { | |
if ((bits & DepthMASK) != 0) { | |
Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)); | |
if (emulationPath == null) { | |
// internal error, per construction we should have found it | |
currentScope.problemReporter().needImplementation(); | |
} else { | |
codeStream.generateOuterAccess(emulationPath, this, currentScope); | |
} | |
} else { | |
generateReceiver(codeStream); | |
} | |
} | |
// managing private access | |
if (isStatic) { | |
codeStream.getstatic(fieldBinding); | |
} else { | |
codeStream.getfield(fieldBinding); | |
} | |
} else { | |
// managing private access | |
if (!fieldBinding.isStatic()) { | |
if ((bits & DepthMASK) != 0) { | |
// internal error, per construction we should have found it | |
// not yet supported | |
currentScope.problemReporter().needImplementation(); | |
} else { | |
generateReceiver(codeStream); | |
} | |
} else { | |
codeStream.aconst_null(); | |
} | |
((CodeSnippetCodeStream)codeStream).generateEmulatedReadAccessForField(fieldBinding); | |
} | |
codeStream.generateImplicitConversion(implicitConversion); | |
} else { // directly use the inlined value | |
codeStream.generateConstant(fieldBinding.constant, implicitConversion); | |
} | |
} | |
break; | |
case LOCAL : // reading a local | |
LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; | |
if (valueRequired) { | |
// outer local? | |
if ((bits & DepthMASK) != 0) { | |
// outer local can be reached either through a synthetic arg or a synthetic field | |
VariableBinding[] path = currentScope.getEmulationPath(localBinding); | |
if (path == null) { | |
// emulation was not possible (should not happen per construction) | |
currentScope.problemReporter().needImplementation(); | |
} else { | |
codeStream.generateOuterAccess(path, this, currentScope); | |
} | |
} else { | |
// regular local variable read | |
codeStream.load(localBinding); | |
} | |
codeStream.generateImplicitConversion(implicitConversion); | |
} | |
} | |
} | |
codeStream.recordPositionsFrom(pc, this.sourceStart); | |
} | |
/* | |
* The APIs with an extra argument is used whenever there are two references to the same variable which | |
* are optimized in one access: e.g "a = a + 1" optimized into "a++". | |
*/ | |
public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, MethodBinding writeAccessor, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { | |
switch (bits & RestrictiveFlagMASK) { | |
case FIELD : // assigning to a field | |
FieldBinding fieldBinding = (FieldBinding) this.codegenBinding; | |
if (fieldBinding.isStatic()) { | |
if (fieldBinding.canBeSeenBy(getReceiverType(currentScope), this, currentScope)) { | |
codeStream.getstatic(fieldBinding); | |
} else { | |
// used to store the value | |
((CodeSnippetCodeStream) codeStream).generateEmulationForField(fieldBinding); | |
codeStream.aconst_null(); | |
// used to retrieve the actual value | |
codeStream.aconst_null(); | |
((CodeSnippetCodeStream) codeStream).generateEmulatedReadAccessForField(fieldBinding); | |
} | |
} else { | |
if (fieldBinding.canBeSeenBy(getReceiverType(currentScope), this, currentScope)) { | |
if ((bits & DepthMASK) != 0) { | |
Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)); | |
if (emulationPath == null) { | |
// internal error, per construction we should have found it | |
currentScope.problemReporter().needImplementation(); | |
} else { | |
codeStream.generateOuterAccess(emulationPath, this, currentScope); | |
} | |
} else { | |
generateReceiver(codeStream); | |
} | |
codeStream.dup(); | |
codeStream.getfield(fieldBinding); | |
} else { | |
if ((bits & DepthMASK) != 0) { | |
// internal error, per construction we should have found it | |
// not yet supported | |
currentScope.problemReporter().needImplementation(); | |
} | |
// used to store the value | |
((CodeSnippetCodeStream) codeStream).generateEmulationForField(fieldBinding); | |
generateReceiver(codeStream); | |
// used to retrieve the actual value | |
codeStream.dup(); | |
((CodeSnippetCodeStream) codeStream).generateEmulatedReadAccessForField(fieldBinding); | |
} | |
} | |
break; | |
case LOCAL : // assigning to a local variable (cannot assign to outer local) | |
LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; | |
Constant assignConstant; | |
int increment; | |
// using incr bytecode if possible | |
switch (localBinding.type.id) { | |
case T_String : | |
codeStream.generateStringAppend(currentScope, this, expression); | |
if (valueRequired) { | |
codeStream.dup(); | |
} | |
codeStream.store(localBinding, false); | |
return; | |
case T_int : | |
if (((assignConstant = expression.constant) != NotAConstant) | |
&& (assignConstant.typeID() != T_float) // only for integral types | |
&& (assignConstant.typeID() != T_double) | |
&& ((increment = assignConstant.intValue()) == (short) increment)) { // 16 bits value | |
switch (operator) { | |
case PLUS : | |
codeStream.iinc(localBinding.resolvedPosition, increment); | |
if (valueRequired) { | |
codeStream.load(localBinding); | |
} | |
return; | |
case MINUS : | |
codeStream.iinc(localBinding.resolvedPosition, -increment); | |
if (valueRequired) { | |
codeStream.load(localBinding); | |
} | |
return; | |
} | |
} | |
default : | |
codeStream.load(localBinding); | |
} | |
} | |
// perform the actual compound operation | |
int operationTypeID; | |
if ((operationTypeID = implicitConversion >> 4) == T_String || operationTypeID == T_Object) { | |
codeStream.generateStringAppend(currentScope, null, expression); | |
} else { | |
// promote the array reference to the suitable operation type | |
codeStream.generateImplicitConversion(implicitConversion); | |
// generate the increment value (will by itself be promoted to the operation value) | |
if (expression == IntLiteral.One){ // prefix operation | |
codeStream.generateConstant(expression.constant, implicitConversion); | |
} else { | |
expression.generateCode(currentScope, codeStream, true); | |
} | |
// perform the operation | |
codeStream.sendOperator(operator, operationTypeID); | |
// cast the value back to the array reference type | |
codeStream.generateImplicitConversion(assignmentImplicitConversion); | |
} | |
// store the result back into the variable | |
switch (bits & RestrictiveFlagMASK) { | |
case FIELD : // assigning to a field | |
FieldBinding fieldBinding = (FieldBinding) this.codegenBinding; | |
if (fieldBinding.canBeSeenBy(getReceiverType(currentScope), this, currentScope)) { | |
fieldStore(codeStream, fieldBinding, writeAccessor, valueRequired); | |
} else { | |
// current stack is: | |
// field receiver value | |
if (valueRequired) { | |
if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) { | |
codeStream.dup2_x2(); | |
} else { | |
codeStream.dup_x2(); | |
} | |
} | |
// current stack is: | |
// value field receiver value | |
((CodeSnippetCodeStream) codeStream).generateEmulatedWriteAccessForField(fieldBinding); | |
} | |
return; | |
case LOCAL : // assigning to a local variable | |
LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; | |
if (valueRequired) { | |
if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) { | |
codeStream.dup2(); | |
} else { | |
codeStream.dup(); | |
} | |
} | |
codeStream.store(localBinding, false); | |
} | |
} | |
public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) { | |
switch (bits & RestrictiveFlagMASK) { | |
case FIELD : // assigning to a field | |
FieldBinding fieldBinding = (FieldBinding) this.codegenBinding; | |
if (fieldBinding.canBeSeenBy(getReceiverType(currentScope), this, currentScope)) { | |
if (fieldBinding.isStatic()) { | |
codeStream.getstatic(fieldBinding); | |
} else { | |
if ((bits & DepthMASK) != 0) { | |
Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)); | |
if (emulationPath == null) { | |
// internal error, per construction we should have found it | |
currentScope.problemReporter().needImplementation(); | |
} else { | |
codeStream.generateOuterAccess(emulationPath, this, currentScope); | |
} | |
} else { | |
generateReceiver(codeStream); | |
} | |
codeStream.dup(); | |
codeStream.getfield(fieldBinding); | |
} | |
if (valueRequired) { | |
if (fieldBinding.isStatic()) { | |
if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) { | |
codeStream.dup2(); | |
} else { | |
codeStream.dup(); | |
} | |
} else { // Stack: [owner][old field value] ---> [old field value][owner][old field value] | |
if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) { | |
codeStream.dup2_x1(); | |
} else { | |
codeStream.dup_x1(); | |
} | |
} | |
} | |
codeStream.generateConstant(postIncrement.expression.constant, implicitConversion); | |
codeStream.sendOperator(postIncrement.operator, fieldBinding.type.id); | |
codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion); | |
fieldStore(codeStream, fieldBinding, null, false); | |
} else { | |
if (fieldBinding.isStatic()) { | |
codeStream.aconst_null(); | |
} else { | |
if ((bits & DepthMASK) != 0) { | |
// internal error, per construction we should have found it | |
// not yet supported | |
currentScope.problemReporter().needImplementation(); | |
} else { | |
generateReceiver(codeStream); | |
} | |
} | |
((CodeSnippetCodeStream) codeStream).generateEmulatedReadAccessForField(fieldBinding); | |
if (valueRequired) { | |
if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) { | |
codeStream.dup2(); | |
} else { | |
codeStream.dup(); | |
} | |
} | |
((CodeSnippetCodeStream) codeStream).generateEmulationForField(fieldBinding); | |
if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) { | |
codeStream.dup_x2(); | |
codeStream.pop(); | |
if (fieldBinding.isStatic()) { | |
codeStream.aconst_null(); | |
} else { | |
generateReceiver(codeStream); | |
} | |
codeStream.dup_x2(); | |
codeStream.pop(); | |
} else { | |
codeStream.dup_x1(); | |
codeStream.pop(); | |
if (fieldBinding.isStatic()) { | |
codeStream.aconst_null(); | |
} else { | |
generateReceiver(codeStream); | |
} | |
codeStream.dup_x1(); | |
codeStream.pop(); | |
} | |
codeStream.generateConstant(postIncrement.expression.constant, implicitConversion); | |
codeStream.sendOperator(postIncrement.operator, fieldBinding.type.id); | |
codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion); | |
((CodeSnippetCodeStream) codeStream).generateEmulatedWriteAccessForField(fieldBinding); | |
} | |
return; | |
case LOCAL : // assigning to a local variable | |
LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding; | |
// using incr bytecode if possible | |
if (localBinding.type == IntBinding) { | |
if (valueRequired) { | |
codeStream.load(localBinding); | |
} | |
if (postIncrement.operator == PLUS) { | |
codeStream.iinc(localBinding.resolvedPosition, 1); | |
} else { | |
codeStream.iinc(localBinding.resolvedPosition, -1); | |
} | |
} else { | |
codeStream.load(localBinding); | |
if (valueRequired){ | |
if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) { | |
codeStream.dup2(); | |
} else { | |
codeStream.dup(); | |
} | |
} | |
codeStream.generateConstant(postIncrement.expression.constant, implicitConversion); | |
codeStream.sendOperator(postIncrement.operator, localBinding.type.id); | |
codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion); | |
codeStream.store(localBinding, false); | |
} | |
} | |
} | |
public void generateReceiver(CodeStream codeStream) { | |
codeStream.aload_0(); | |
if (delegateThis != null) codeStream.getfield(delegateThis); // delegated field access | |
} | |
/** | |
* Check and/or redirect the field access to the delegate receiver if any | |
*/ | |
public TypeBinding getReceiverType(BlockScope currentScope) { | |
if (receiverType != null) return receiverType; | |
Scope scope = currentScope.parent; | |
while (true) { | |
switch (scope.kind) { | |
case Scope.CLASS_SCOPE : | |
return receiverType = ((ClassScope) scope).referenceContext.binding; | |
default: | |
scope = scope.parent; | |
} | |
} | |
} | |
/** | |
* Normal field binding did not work, try to bind to a field of the delegate receiver. | |
*/ | |
public TypeBinding reportError(BlockScope scope) { | |
constant = Constant.NotAConstant; | |
if (binding instanceof ProblemFieldBinding && ((ProblemFieldBinding) binding).problemId() == NotFound){ | |
if (this.evaluationContext.declaringTypeName != null) { | |
delegateThis = scope.getField(scope.enclosingSourceType(), DELEGATE_THIS, this); | |
if (delegateThis != null){ ; // if not found then internal error, field should have been found | |
// will not support innerclass emulation inside delegate | |
this.codegenBinding = binding = scope.getField(delegateThis.type, this.token, this); | |
if (!binding.isValidBinding()) return super.reportError(scope); | |
return checkFieldAccess(scope); | |
} | |
} | |
} | |
if (binding instanceof ProblemBinding && ((ProblemBinding) binding).problemId() == NotFound){ | |
if (this.evaluationContext.declaringTypeName != null) { | |
delegateThis = scope.getField(scope.enclosingSourceType(), DELEGATE_THIS, this); | |
if (delegateThis != null){ ; // if not found then internal error, field should have been found | |
// will not support innerclass emulation inside delegate | |
FieldBinding fieldBinding = scope.getField(delegateThis.type, this.token, this); | |
if (!fieldBinding.isValidBinding()) { | |
if (((ProblemFieldBinding) fieldBinding).problemId() == NotVisible) { | |
// manage the access to a private field of the enclosing type | |
CodeSnippetScope localScope = new CodeSnippetScope(scope); | |
this.codegenBinding = binding = localScope.getFieldForCodeSnippet(delegateThis.type, this.token, this); | |
return checkFieldAccess(scope); | |
} else { | |
return super.reportError(scope); | |
} | |
} | |
this.codegenBinding = binding = fieldBinding; | |
return checkFieldAccess(scope); | |
} | |
} | |
} | |
return super.reportError(scope); | |
} | |
} |