diff options
Diffstat (limited to 'bundles/org.eclipse.wst.jsdt.core/src/org/eclipse/wst/jsdt/internal/compiler/ast/FieldReference.java')
-rw-r--r-- | bundles/org.eclipse.wst.jsdt.core/src/org/eclipse/wst/jsdt/internal/compiler/ast/FieldReference.java | 808 |
1 files changed, 332 insertions, 476 deletions
diff --git a/bundles/org.eclipse.wst.jsdt.core/src/org/eclipse/wst/jsdt/internal/compiler/ast/FieldReference.java b/bundles/org.eclipse.wst.jsdt.core/src/org/eclipse/wst/jsdt/internal/compiler/ast/FieldReference.java index 0b00db60..6948dae6 100644 --- a/bundles/org.eclipse.wst.jsdt.core/src/org/eclipse/wst/jsdt/internal/compiler/ast/FieldReference.java +++ b/bundles/org.eclipse.wst.jsdt.core/src/org/eclipse/wst/jsdt/internal/compiler/ast/FieldReference.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2011 IBM Corporation and others. + * Copyright (c) 2007, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -17,22 +17,25 @@ import org.eclipse.wst.jsdt.core.ast.IASTNode; import org.eclipse.wst.jsdt.core.ast.IExpression; import org.eclipse.wst.jsdt.core.ast.IFieldReference; import org.eclipse.wst.jsdt.core.compiler.CharOperation; +import org.eclipse.wst.jsdt.core.infer.InferredMethod; +import org.eclipse.wst.jsdt.core.infer.InferredType; import org.eclipse.wst.jsdt.internal.compiler.ASTVisitor; -import org.eclipse.wst.jsdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.wst.jsdt.internal.compiler.flow.FlowContext; import org.eclipse.wst.jsdt.internal.compiler.flow.FlowInfo; import org.eclipse.wst.jsdt.internal.compiler.impl.Constant; import org.eclipse.wst.jsdt.internal.compiler.lookup.Binding; import org.eclipse.wst.jsdt.internal.compiler.lookup.BlockScope; import org.eclipse.wst.jsdt.internal.compiler.lookup.FieldBinding; +import org.eclipse.wst.jsdt.internal.compiler.lookup.FunctionTypeBinding; import org.eclipse.wst.jsdt.internal.compiler.lookup.InvocationSite; +import org.eclipse.wst.jsdt.internal.compiler.lookup.LocalFunctionBinding; import org.eclipse.wst.jsdt.internal.compiler.lookup.LocalVariableBinding; import org.eclipse.wst.jsdt.internal.compiler.lookup.MethodBinding; import org.eclipse.wst.jsdt.internal.compiler.lookup.ProblemFieldBinding; import org.eclipse.wst.jsdt.internal.compiler.lookup.ProblemReasons; import org.eclipse.wst.jsdt.internal.compiler.lookup.ProblemReferenceBinding; import org.eclipse.wst.jsdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.wst.jsdt.internal.compiler.lookup.Scope; +import org.eclipse.wst.jsdt.internal.compiler.lookup.SourceTypeBinding; import org.eclipse.wst.jsdt.internal.compiler.lookup.TypeBinding; import org.eclipse.wst.jsdt.internal.compiler.lookup.TypeConstants; import org.eclipse.wst.jsdt.internal.compiler.lookup.TypeIds; @@ -40,539 +43,392 @@ import org.eclipse.wst.jsdt.internal.compiler.util.Util; public class FieldReference extends Reference implements InvocationSite, IFieldReference { - public static final int READ = 0; - public static final int WRITE = 1; public Expression receiver; public char[] token; - public FieldBinding binding; // exact binding resulting from lookup - public TypeBinding typeBinding; // exact binding resulting from lookup -// protected FieldBinding codegenBinding; // actual binding used for code generation (if no synthetic accessor) -// public FunctionBinding[] syntheticAccessors; // [0]=read accessor [1]=write accessor + + /** + * <p> + * exact binding resulting from lookup + * </p> + */ + public FieldBinding binding; + + /** + * <p> + * exact binding resulting from lookup + * </p> + */ + public TypeBinding typeBinding; - public long nameSourcePosition; //(start<<32)+end + /** + * (start<<32)+end + */ + public long nameSourcePosition; public TypeBinding receiverType; -// public TypeBinding genericCast; - -public FieldReference(char[] source, long pos) { - token = source; - nameSourcePosition = pos; - //by default the position are the one of the field (not true for super access) - sourceStart = (int) (pos >>> 32); - sourceEnd = (int) (pos & 0x00000000FFFFFFFFL); - bits |= Binding.FIELD; - -} - -public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) { - // compound assignment extra work -// if (isCompound) { // check the variable part is initialized if blank final -// if (binding.isBlankFinal() -// && receiver.isThis() -// && currentScope.allowBlankFinalFieldAssignment(binding) -// && (!flowInfo.isDefinitelyAssigned(binding))) { -// currentScope.problemReporter().uninitializedBlankFinalField(binding, this); -// // we could improve error msg here telling "cannot use compound assignment on final blank field" -// } -// manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/); -// } - if (receiver instanceof SingleNameReference && ((SingleNameReference)receiver).binding instanceof LocalVariableBinding) - { - flowInfo.markAsDefinitelyNonNull((LocalVariableBinding)((SingleNameReference)receiver).binding); - flowInfo.markAsDefinitelyAssigned((LocalVariableBinding)((SingleNameReference)receiver).binding); + + public FieldReference(char[] source, long pos) { + token = source; + nameSourcePosition = pos; + // by default the position are the one of the field (not true for super access) + sourceStart = (int) (pos >>> 32); + sourceEnd = (int) (pos & 0x00000000FFFFFFFFL); + bits |= Binding.FIELD; } - flowInfo = - receiver - .analyseCode(currentScope, flowContext, flowInfo, binding==null || !binding.isStatic()) - .unconditionalInits(); - if (assignment.expression != null) { - flowInfo = - assignment - .expression - .analyseCode(currentScope, flowContext, flowInfo) - .unconditionalInits(); + + public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) { + if (receiver instanceof SingleNameReference && ((SingleNameReference) receiver).binding instanceof LocalVariableBinding) { + flowInfo.markAsDefinitelyNonNull((LocalVariableBinding) ((SingleNameReference) receiver).binding); + flowInfo.markAsDefinitelyAssigned((LocalVariableBinding) ((SingleNameReference) receiver).binding); + } + flowInfo = receiver.analyseCode(currentScope, flowContext, flowInfo, binding == null || !binding.isStatic()).unconditionalInits(); + if (assignment.expression != null) { + flowInfo = assignment.expression.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); + } + + return flowInfo; } - manageSyntheticAccessIfNecessary(currentScope, flowInfo, false /*write-access*/); - return flowInfo; -} + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { + return analyseCode(currentScope, flowContext, flowInfo, true); + } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - return analyseCode(currentScope, flowContext, flowInfo, true); -} + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { + boolean nonStatic = binding == null || !binding.isStatic(); + receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic); + if (nonStatic) { + receiver.checkNPE(currentScope, flowContext, flowInfo); + } -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { - boolean nonStatic = binding==null || !binding.isStatic(); - receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic); - if (nonStatic) { - receiver.checkNPE(currentScope, flowContext, flowInfo); + return flowInfo; } - if (valueRequired || currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) { - manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/); + public FieldBinding fieldBinding() { + return binding; } - return flowInfo; -} - -/** - * @see org.eclipse.wst.jsdt.internal.compiler.ast.Expression#computeConversion(org.eclipse.wst.jsdt.internal.compiler.lookup.Scope, org.eclipse.wst.jsdt.internal.compiler.lookup.TypeBinding, org.eclipse.wst.jsdt.internal.compiler.lookup.TypeBinding) - */ -public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) { - if (runtimeTimeType == null || compileTimeType == null) - return; - // set the generic cast after the fact, once the type expectation is fully known (no need for strict cast) - if (this.binding != null && this.binding.isValidBinding()) { - FieldBinding originalBinding = this.binding.original(); + + /** + * @see org.eclipse.wst.jsdt.internal.compiler.lookup.InvocationSite#genericTypeArguments() + */ + public TypeBinding[] genericTypeArguments() { + return null; } -} - -public FieldBinding fieldBinding() { - return binding; -} - -/** - * @see org.eclipse.wst.jsdt.internal.compiler.lookup.InvocationSite#genericTypeArguments() - */ -public TypeBinding[] genericTypeArguments() { - return null; -} -public boolean isSuperAccess() { - return receiver.isSuper(); -} - -public boolean isTypeAccess() { - return receiver != null && receiver.isTypeReference(); -} - -/* - * No need to emulate access to protected fields since not implicitly accessed - */ -public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo, boolean isReadAccess) { - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) return; - - // if field from parameterized type got found, use the original field at codegen time -// this.codegenBinding = this.binding.original(); -// -// if (binding.isPrivate()) { -// if ((currentScope.enclosingSourceType() != this.codegenBinding.declaringClass) -// && binding.constant() == Constant.NotAConstant) { -// if (syntheticAccessors == null) -// syntheticAccessors = new FunctionBinding[2]; -// syntheticAccessors[isReadAccess ? READ : WRITE] = -// ((SourceTypeBinding) this.codegenBinding.declaringClass).addSyntheticMethod(this.codegenBinding, isReadAccess); -// currentScope.problemReporter().needToEmulateFieldAccess(this.codegenBinding, this, isReadAccess); -// return; -// } -// -// } else if (receiver instanceof QualifiedSuperReference) { // qualified super -// -// // qualified super need emulation always -// SourceTypeBinding destinationType = -// (SourceTypeBinding) (((QualifiedSuperReference) receiver) -// .currentCompatibleType); -// if (syntheticAccessors == null) -// syntheticAccessors = new FunctionBinding[2]; -// syntheticAccessors[isReadAccess ? READ : WRITE] = destinationType.addSyntheticMethod(this.codegenBinding, isReadAccess); -// currentScope.problemReporter().needToEmulateFieldAccess(this.codegenBinding, this, isReadAccess); -// return; -// -// } else if (binding.isProtected()) { -// -// SourceTypeBinding enclosingSourceType; -// if (((bits & DepthMASK) != 0) -// && binding.declaringClass.getPackage() -// != (enclosingSourceType = currentScope.enclosingSourceType()).getPackage()) { -// -// SourceTypeBinding currentCompatibleType = -// (SourceTypeBinding) enclosingSourceType.enclosingTypeAt( -// (bits & DepthMASK) >> DepthSHIFT); -// if (syntheticAccessors == null) -// syntheticAccessors = new FunctionBinding[2]; -// syntheticAccessors[isReadAccess ? READ : WRITE] = currentCompatibleType.addSyntheticMethod(this.codegenBinding, isReadAccess); -// currentScope.problemReporter().needToEmulateFieldAccess(this.codegenBinding, this, isReadAccess); -// return; -// } -// } - // if the binding declaring class is not visible, need special action - // for runtime compatibility on 1.2 VMs : change the declaring class of the binding - // NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type - // and not from Object or implicit static field access. -// if (this.binding.declaringClass != this.receiverType -// && !this.receiverType.isArrayType() -// && this.binding.declaringClass != null // array.length -// && this.binding.constant() == Constant.NotAConstant) { -// CompilerOptions options = currentScope.compilerOptions(); -// if ((options.targetJDK >= ClassFileConstants.JDK1_2 -// && (options.complianceLevel >= ClassFileConstants.JDK1_4 || !(receiver.isImplicitThis() && this.codegenBinding.isStatic())) -// && this.binding.declaringClass.id != T_JavaLangObject) // no change for Object fields -// || !this.binding.declaringClass.canBeSeenBy(currentScope)) { -// -// this.codegenBinding = -// currentScope.enclosingSourceType().getUpdatedFieldBinding( -// this.codegenBinding, -// (ReferenceBinding) this.receiverType.erasure()); -// } -// } -} - -public int nullStatus(FlowInfo flowInfo) { - return FlowInfo.UNKNOWN; -} - -public Constant optimizedBooleanConstant() { - switch (this.resolvedType.id) { - case T_boolean : - case T_JavaLangBoolean : - return Constant.NotAConstant; - default : - return Constant.NotAConstant; + + public boolean isSuperAccess() { + return receiver.isSuper(); } -} - -/** - * @see org.eclipse.wst.jsdt.internal.compiler.ast.Expression#postConversionType(Scope) - */ -public TypeBinding postConversionType(Scope scope) { - TypeBinding convertedType = this.resolvedType; -// if (this.genericCast != null) -// convertedType = this.genericCast; - int runtimeType = (this.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4; - switch (runtimeType) { - case T_boolean : - convertedType = TypeBinding.BOOLEAN; - break; - case T_short : - convertedType = TypeBinding.SHORT; - break; - case T_char : - convertedType = TypeBinding.CHAR; - break; - case T_int : - convertedType = TypeBinding.INT; - break; - case T_float : - convertedType = TypeBinding.FLOAT; - break; - case T_long : - convertedType = TypeBinding.LONG; - break; - case T_double : - convertedType = TypeBinding.DOUBLE; - break; - default : + + public boolean isTypeAccess() { + return receiver != null && receiver.isTypeReference(); } - if ((this.implicitConversion & BOXING) != 0) { - convertedType = scope.environment().computeBoxingType(convertedType); + + public int nullStatus(FlowInfo flowInfo) { + return FlowInfo.UNKNOWN; } - return convertedType; -} -public StringBuffer printExpression(int indent, StringBuffer output) { - return receiver.printExpression(0, output).append('.').append(token); -} + public Constant optimizedBooleanConstant() { + return Constant.NotAConstant; + } + public StringBuffer printExpression(int indent, StringBuffer output) { + return receiver.printExpression(0, output).append('.').append(token); + } -public TypeBinding resolveType(BlockScope scope) { - return resolveType(scope, false, null); -} -public TypeBinding resolveType(BlockScope scope, boolean define, TypeBinding useType) { - // Answer the signature type of the field. - // constants are propaged when the field is final - // and initialized with a (compile time) constant + public TypeBinding resolveType(BlockScope scope) { + return resolveType(scope, false, null); + } - //always ignore receiver cast, since may affect constant pool reference -// boolean receiverCast = false; -// if (this.receiver instanceof CastExpression) { -// this.receiver.bits |= DisableUnnecessaryCastCheck; // will check later on -// receiverCast = true; -// } + public TypeBinding resolveType(BlockScope scope, boolean define, TypeBinding useType) { + /* + * Handle if this is a reference to the prototype of a type + * + * By default, the prototype is of type Object, but if there is an + * InferredType for the receiver, it should yeild the receiver type. + */ + if (this.isPrototype()) { + // check if receiver type is defined + if ((this.receiverType = receiver.resolveType(scope)) == null) { + constant = Constant.NotAConstant; + return null; + } + // construct the name of the type based on the receiver + char[] possibleTypeName = Util.getTypeName(receiver); + TypeBinding typeBinding = scope.getJavaLangObject(); + if (possibleTypeName != null) { + Binding possibleTypeBinding = scope.getBinding(possibleTypeName, Binding.TYPE & RestrictiveFlagMASK, this, true /* resolve */); - /* - * Handle if this is a reference to the prototype of a type - * - * By default, the prototype is of type Object, but if there is an InferredType - * for the receiver, it should yeild the receiver type. - */ -if( this.isPrototype() ){ - // check if receiver type is defined - if ((this.receiverType = receiver.resolveType(scope)) == null) { - constant = Constant.NotAConstant; - return null; - } - - - //construc the name of the type based on the receiver - char [] possibleTypeName = Util.getTypeName( receiver ); - TypeBinding typeBinding = scope.getJavaLangObject(); - if( possibleTypeName != null ){ - Binding possibleTypeBinding = scope.getBinding( possibleTypeName, Binding.TYPE & RestrictiveFlagMASK, this, true /*resolve*/); - - if( possibleTypeBinding.isValidBinding() ){ - //get the super class -// TypeBinding superTypeBinding = ((ReferenceBinding)possibleTypeBinding).superclass(); -// if( superTypeBinding != null ) -// typeBinding = superTypeBinding; - typeBinding = (TypeBinding)possibleTypeBinding; + if (possibleTypeBinding.isValidBinding()) { + typeBinding = (TypeBinding) possibleTypeBinding; + } + char[] fieldname = new char[]{'p', 'r', 'o', 't', 'o', 't', 'y', 'p', 'e'}; + this.binding = scope.getJavaLangObject().getField(fieldname, true); + constant = Constant.NotAConstant; + return this.resolvedType = typeBinding; } - char[] fieldname=new char[]{'p','r','o','t','o','t','y','p','e'}; - this.binding=scope.getJavaLangObject().getField(fieldname, true); - constant = Constant.NotAConstant; - return this.resolvedType = typeBinding; + } - } + char[] possibleTypeName = Util.getTypeName(this); + Binding possibleTypeBinding = null; + if (possibleTypeName != null) { + possibleTypeBinding = scope.getBinding(possibleTypeName, Binding.TYPE & RestrictiveFlagMASK, this, true /* resolve */); + } - char [] possibleTypeName = Util.getTypeName( this ); - Binding possibleTypeBinding =null; - if (possibleTypeName!=null) - possibleTypeBinding = scope.getBinding( possibleTypeName, Binding.TYPE & RestrictiveFlagMASK, this, true /*resolve*/); - if(possibleTypeBinding != null && possibleTypeBinding.isValidBinding() && (TypeBinding)possibleTypeBinding != scope.getJavaLangObject()) { - this.typeBinding=(TypeBinding)possibleTypeBinding; - constant = Constant.NotAConstant; - this.bits|=Binding.TYPE; - return this.typeBinding; - } - boolean receiverDefined=true; - // if this could be a qualified type name, first check if receiver is defined, and if not look up as type name - if (possibleTypeName!=null && receiver instanceof SingleNameReference) - { - Binding receiverBinding = ((SingleNameReference)receiver).findBinding(scope); - if (receiverBinding==null || !receiverBinding.isValidBinding()) - receiverDefined=false; - this.receiverType=null; - } - if (receiverDefined) - this.receiverType = receiver.resolveType(scope); - if (this.receiverType == null || this.receiverType==scope.getJavaLangObject()) { - if (possibleTypeBinding!=null && possibleTypeBinding.isValidBinding()) - { - this.typeBinding=(TypeBinding)possibleTypeBinding; - this.bits|=Binding.TYPE; + if (possibleTypeBinding != null && possibleTypeBinding.isValidBinding() && (TypeBinding) possibleTypeBinding != scope.getJavaLangObject()) { + this.typeBinding = (TypeBinding) possibleTypeBinding; + constant = Constant.NotAConstant; + this.bits |= Binding.TYPE; return this.typeBinding; } - else - { - this.binding=new ProblemFieldBinding(null,this.token,ProblemReasons.NotFound); + + /* if this could be a qualified type name, first check if receiver is + * defined, and if not look up as type name */ + this.receiverType = this.receiver.resolveType(scope); + + if (this.receiverType == null || this.receiverType == scope.getJavaLangObject()) { + if (possibleTypeBinding != null && possibleTypeBinding.isValidBinding()) { + this.typeBinding = (TypeBinding) possibleTypeBinding; + this.bits |= Binding.TYPE; + return this.typeBinding; + } + else { + this.binding = new ProblemFieldBinding(null, this.token, ProblemReasons.NotFound); + constant = Constant.NotAConstant; + this.resolvedType = TypeBinding.ANY; + } + return null; + } + + /* Need to look in the fields and method for a match... In JS there is + * no distinction between member functions or field. We are trying to + * mimic that property below (Java does have a distinction) */ + if (this.receiverType.id == TypeIds.T_any) { constant = Constant.NotAConstant; - this.resolvedType=TypeBinding.ANY; + this.binding = new ProblemFieldBinding(null, token, ProblemReasons.NotFound); + return this.resolvedType = TypeBinding.ANY; } - return null; - } -// if (receiverCast) { -// // due to change of declaring class with receiver type, only identity cast should be notified -// if (((CastExpression)this.receiver).expression.resolvedType == this.receiverType) { -// scope.problemReporter().unnecessaryCast((CastExpression)this.receiver); -// } -// } - // the case receiverType.isArrayType and token = 'length' is handled by the scope API - - /* - * Need to look in the fields and method for a match... In JS there is no distinction between member functions - * or field. We are trying to mimic that property below (Java does have a distinction) - */ - if (this.receiverType.id==TypeIds.T_any) - { - constant = Constant.NotAConstant; - this.binding=new ProblemFieldBinding( null, token, ProblemReasons.NotFound) ; - return this.resolvedType=TypeBinding.ANY; - } - - Binding memberBinding = scope.getFieldOrMethod(this.receiverType, token, this); - boolean receiverIsType = (receiver instanceof NameReference || receiver instanceof FieldReference || receiver instanceof ThisReference) - && ( receiver.bits & Binding.TYPE) != 0; - if (!memberBinding.isValidBinding() && (this.receiverType!=null && this.receiverType.isFunctionType())) - { - Binding alternateBinding = receiver.alternateBinding(); - if (alternateBinding instanceof TypeBinding) - { - this.receiverType=(TypeBinding)alternateBinding; + + Binding memberBinding = scope.getFieldOrMethod(this.receiverType, token, this); + boolean receiverIsType = (receiver instanceof NameReference || receiver instanceof FieldReference || receiver instanceof ThisReference) && (receiver.bits & Binding.TYPE) != 0; + if (!memberBinding.isValidBinding() && (this.receiverType != null && this.receiverType.isFunctionType())) { + Binding alternateBinding = receiver.alternateBinding(); + if (alternateBinding instanceof TypeBinding) { + this.receiverType = (TypeBinding) alternateBinding; memberBinding = scope.getFieldOrMethod(this.receiverType, token, this); - receiverIsType=true; - } - } - - - //FieldBinding fieldBinding = this.codegenBinding = this.binding = scope.getField(this.receiverType, token, this); - - constant = Constant.NotAConstant; - if( memberBinding instanceof FieldBinding ){ - FieldBinding fieldBinding =/* this.codegenBinding =*/ this.binding = (FieldBinding)memberBinding; - if (!fieldBinding.isValidBinding()) { - this.binding=fieldBinding; - this.resolvedType=TypeBinding.ANY; - if (!define) - { - constant = Constant.NotAConstant; - scope.problemReporter().invalidField(this, this.receiverType); - return null; + receiverIsType = true; } - else // should add binding here - { + } + constant = Constant.NotAConstant; + if (memberBinding instanceof FieldBinding) { + FieldBinding fieldBinding = /* this.codegenBinding = */this.binding = (FieldBinding) memberBinding; + if (!fieldBinding.isValidBinding()) { + this.binding = fieldBinding; + this.resolvedType = TypeBinding.ANY; + if (!define) { + constant = Constant.NotAConstant; + scope.problemReporter().invalidField(this, this.receiverType); + return null; + } + else { + // should add binding here + } } - // return this.resolvedType=TypeBinding.UNKNOWN; - } - if (JavaScriptCore.IS_ECMASCRIPT4) - { - TypeBinding receiverErasure = this.receiverType; - if (receiverErasure instanceof ReferenceBinding) { - if (receiverErasure.findSuperTypeWithSameErasure(fieldBinding.declaringClass) == null) { - this.receiverType = fieldBinding.declaringClass; // handle indirect inheritance thru variable secondary bound + if (JavaScriptCore.IS_ECMASCRIPT4) { + TypeBinding receiverErasure = this.receiverType; + if (receiverErasure instanceof ReferenceBinding) { + if (receiverErasure.findSuperTypeWithSameErasure(fieldBinding.declaringClass) == null) { + // handle indirect inheritance thru variable secondary bound + this.receiverType = fieldBinding.declaringClass; + } } } - } - if (isFieldUseDeprecated(fieldBinding, scope, (this.bits & IsStrictlyAssigned) !=0)) { - scope.problemReporter().deprecatedField(fieldBinding, this); - } - boolean isImplicitThisRcv = receiver.isImplicitThis(); - constant = Constant.NotAConstant; - if (fieldBinding.isStatic()) { - // static field accessed through receiver? legal but unoptimal (optional warning) - if (!(isImplicitThisRcv - || receiverIsType - )) { - scope.problemReporter().nonStaticAccessToStaticField(this, fieldBinding); + if (isFieldUseDeprecated(fieldBinding, scope, (this.bits & IsStrictlyAssigned) != 0)) { + scope.problemReporter().deprecatedField(fieldBinding, this); } - if (!isImplicitThisRcv - && fieldBinding.declaringClass != receiverType - && fieldBinding.declaringClass.canBeSeenBy(scope)) { - scope.problemReporter().indirectAccessToStaticField(this, fieldBinding); + boolean isImplicitThisRcv = receiver.isImplicitThis(); + constant = Constant.NotAConstant; + if (fieldBinding.isStatic()) { + // static field accessed through receiver? legal but unoptimal (optional warning) + if (!(isImplicitThisRcv || receiverIsType)) { + scope.problemReporter().nonStaticAccessToStaticField(this, fieldBinding); + } + if (!isImplicitThisRcv && fieldBinding.declaringClass != receiverType && fieldBinding.declaringClass.canBeSeenBy(scope)) { + scope.problemReporter().indirectAccessToStaticField(this, fieldBinding); + } + } + else { + if (receiverIsType) { + scope.problemReporter().staticFieldAccessToNonStaticVariable(this, fieldBinding); + } + } + + //if there is a given useType and the field is not valid, create a valid binding + if(useType != null && !fieldBinding.isValidBinding()) { + fieldBinding = new FieldBinding(fieldBinding, fieldBinding.declaringClass); + if(fieldBinding.declaringClass instanceof SourceTypeBinding) { + ((SourceTypeBinding)fieldBinding.declaringClass).addField(fieldBinding); + } + this.binding = fieldBinding; + } + + //set use type + if(useType != null) { + fieldBinding.type = useType; + + //add as a function binding as well if there is not already a function binding by the same name + if(useType.isFunctionType() && fieldBinding.declaringClass instanceof SourceTypeBinding) { + SourceTypeBinding declaringBinding = (SourceTypeBinding)fieldBinding.declaringClass; + InferredMethod dupMeth = declaringBinding.getInferredType().findMethod(this.getToken(), null); + if(dupMeth == null) { + MethodBinding[] funcBindings = declaringBinding.getMethods(this.getToken()); + if(funcBindings == null || funcBindings.length == 0) { + MethodBinding methBinding = new MethodBinding( + ((FunctionTypeBinding)useType).functionBinding, fieldBinding.declaringClass); + methBinding.selector = fieldBinding.name; + + if(methBinding.declaringClass instanceof SourceTypeBinding) { + ((SourceTypeBinding)methBinding.declaringClass).addMethod(methBinding); + } + } + } + } } - } else { - if(receiverIsType) - scope.problemReporter().staticFieldAccessToNonStaticVariable(this, fieldBinding); + + // perform capture conversion if read access + return this.resolvedType = fieldBinding.type; } - // perform capture conversion if read access - return this.resolvedType = fieldBinding.type; - } - else if( memberBinding instanceof MethodBinding ){ - MethodBinding methodBinding=(MethodBinding) memberBinding; + else if (memberBinding instanceof MethodBinding) { + MethodBinding methodBinding = (MethodBinding) memberBinding; + + if (!methodBinding.isStatic() || memberBinding instanceof LocalFunctionBinding) { + if (receiverIsType && methodBinding.isValidBinding() && !methodBinding.isConstructor()) { + if (this.receiverType == null || !this.receiverType.isAnonymousType()) + scope.problemReporter().mustUseAStaticMethod(this, methodBinding); + } + } + else { + if (!receiverIsType && methodBinding.isValidBinding()) + scope.problemReporter().nonStaticAccessToStaticMethod(this, methodBinding); - if (!methodBinding.isStatic()) { - if (receiverIsType && methodBinding.isValidBinding() && !methodBinding.isConstructor()) { - if(this.receiverType == null || !this.receiverType.isAnonymousType()) - scope.problemReporter().mustUseAStaticMethod(this, methodBinding); } - } - else - { - if (!receiverIsType && methodBinding.isValidBinding()) - scope.problemReporter().nonStaticAccessToStaticMethod(this, - methodBinding); + this.resolvedType = methodBinding.functionTypeBinding; + this.binding = new FieldBinding(((MethodBinding) memberBinding).selector, this.receiverType, ((MethodBinding) memberBinding).modifiers, methodBinding.declaringClass); + if (memberBinding.isValidBinding()) { + return this.resolvedType; + } + return null; } - - this.resolvedType= scope.getJavaLangFunction(); - this.binding = new FieldBinding(((MethodBinding) memberBinding).selector, this.receiverType, ((MethodBinding) memberBinding).modifiers, methodBinding.declaringClass); - //this.binding=new ProblemFieldBinding(null,this.token,ProblemReasons.NotFound); - if( memberBinding.isValidBinding() ) - return this.resolvedType; + return null; } - return null; -} - -public void setActualReceiverType(ReferenceBinding receiverType) { - // ignored -} + public void setActualReceiverType(ReferenceBinding receiverType) { + // ignored + } -public void setDepth(int depth) { - bits &= ~DepthMASK; // flush previous depth if any - if (depth > 0) { - bits |= (depth & 0xFF) << DepthSHIFT; // encoded on 8 bits + public void setDepth(int depth) { + bits &= ~DepthMASK; // flush previous depth if any + if (depth > 0) { + bits |= (depth & 0xFF) << DepthSHIFT; // encoded on 8 bits + } } -} -public void setFieldIndex(int index) { - // ignored -} + public void setFieldIndex(int index) { + // ignored + } -public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - receiver.traverse(visitor, scope); + public void traverse(ASTVisitor visitor, BlockScope scope) { + if (visitor.visit(this, scope)) { + receiver.traverse(visitor, scope); + } + visitor.endVisit(this, scope); } - visitor.endVisit(this, scope); -} -public boolean isPrototype() -{ - return (CharOperation.equals(TypeConstants.PROTOTYPE,this.token)); -} - - -public TypeBinding resolveForAllocation(BlockScope scope, ASTNode location) -{ - char [][]qualifiedName=asQualifiedName(); - TypeBinding typeBinding=null; - if (qualifiedName!=null) - { - typeBinding=scope.getType(CharOperation.concatWith(qualifiedName, '.')); + + public boolean isPrototype() { + return (CharOperation.equals(TypeConstants.PROTOTYPE, this.token)); } - if (typeBinding==null || !typeBinding.isValidBinding()) - { - this.receiverType = receiver.resolveType(scope); - if (this.receiverType == null) { - this.binding=new ProblemFieldBinding(null,this.token,ProblemReasons.NotFound); - constant = Constant.NotAConstant; - this.resolvedType=TypeBinding.ANY; - return null; + + + public TypeBinding resolveForAllocation(BlockScope scope, ASTNode location) { + char[][] qualifiedName = asQualifiedName(); + TypeBinding typeBinding = null; + if (qualifiedName != null) { + typeBinding = scope.getType(CharOperation.concatWith(qualifiedName, '.')); } - Binding memberBinding = scope.getFieldOrMethod(this.receiverType, token, this); - if( memberBinding instanceof MethodBinding && memberBinding.isValidBinding()){ - this.resolvedType= ((MethodBinding)memberBinding).allocationType; - this.binding=new ProblemFieldBinding(null,this.token,ProblemReasons.NotFound); - if( memberBinding.isValidBinding() ) - return this.resolvedType; + if (typeBinding == null || !typeBinding.isValidBinding()) { + this.receiverType = receiver.resolveType(scope); + if (this.receiverType == null) { + this.binding = new ProblemFieldBinding(null, this.token, ProblemReasons.NotFound); + constant = Constant.NotAConstant; + this.resolvedType = TypeBinding.ANY; + return null; + } + Binding memberBinding = scope.getFieldOrMethod(this.receiverType, token, this); + if (memberBinding instanceof MethodBinding && memberBinding.isValidBinding()) { + this.resolvedType = ((MethodBinding) memberBinding).allocationType; + this.binding = new ProblemFieldBinding(null, this.token, ProblemReasons.NotFound); + if (memberBinding.isValidBinding()) + return this.resolvedType; + } + + } + if (typeBinding == null) { + if (qualifiedName == null) + qualifiedName = new char[][]{token}; + typeBinding = new ProblemReferenceBinding(qualifiedName, null, ProblemReasons.NotFound); } - + return typeBinding; } - if (typeBinding==null) - { - if (qualifiedName==null) - qualifiedName=new char[][]{token}; - typeBinding=new ProblemReferenceBinding(qualifiedName,null,ProblemReasons.NotFound); + + public int getASTType() { + return IASTNode.FIELD_REFERENCE; + } - return typeBinding; -} -public int getASTType() { - return IASTNode.FIELD_REFERENCE; - -} - -public char [][] asQualifiedName() -{ - ArrayList list=new ArrayList(); - list.add(token); - FieldReference fieldReference=this; - while (fieldReference!=null) - { - if ( fieldReference.receiver instanceof SingleNameReference) - { - list.add(0,((SingleNameReference)fieldReference.receiver).token); - fieldReference=null; - } - else if (fieldReference.receiver instanceof FieldReference) - { - fieldReference=(FieldReference)fieldReference.receiver; - list.add(0,fieldReference.token); + + public char[][] asQualifiedName() { + ArrayList list = new ArrayList(); + list.add(token); + FieldReference fieldReference = this; + while (fieldReference != null) { + if (fieldReference.receiver instanceof SingleNameReference) { + list.add(0, ((SingleNameReference) fieldReference.receiver).token); + fieldReference = null; + } + else if (fieldReference.receiver instanceof FieldReference) { + fieldReference = (FieldReference) fieldReference.receiver; + list.add(0, fieldReference.token); + } + else if (fieldReference.receiver instanceof ThisReference) { + //use the inferred type name of "this" as the next segment + InferredType type = ((ThisReference)fieldReference.receiver).getInferredType(); + if(type != null) { + list.add(0, type.getName()); + } else { + //if do not have a type for "this" then can't build the fully qualified name + return null; + } + + fieldReference = null; } - else + else { return null; + } + } + return (char[][]) list.toArray(new char[list.size()][]); } - return (char [][])list.toArray(new char[list.size()][]); -} - -public IExpression getReceiver() { - return receiver; -} -public char[] getToken() { - return token; -} + public IExpression getReceiver() { + return receiver; + } -public boolean isTypeReference() { - return (this.bits & Binding.TYPE) ==Binding.TYPE; -} + public char[] getToken() { + return token; + } -} + public boolean isTypeReference() { + return (this.bits & Binding.TYPE) == Binding.TYPE; + } +}
\ No newline at end of file |