public TypeBinding resolveType(BlockScope scope) { // field and/or local are done before type lookups // the only available value for the restrictiveFlag BEFORE // the TC is Flag_Type Flag_LocalField and Flag_TypeLocalField this.actualReceiverType = scope.enclosingReceiverType(); this.constant = Constant.NotAConstant; if (( /*this.codegenBinding =*/ this.binding = scope.getBinding( this.tokens, this.bits & ASTNode.RestrictiveFlagMASK, this, true /*resolve*/)) .isValidBinding()) { switch (this.bits & ASTNode.RestrictiveFlagMASK) { case Binding.VARIABLE: // ============only variable=========== case Binding.TYPE | Binding.VARIABLE: if (this.binding instanceof LocalVariableBinding) { this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits this.bits |= Binding.LOCAL; return this.resolvedType = getOtherFieldBindings(scope); } if (this.binding instanceof FieldBinding) { FieldBinding fieldBinding = (FieldBinding) this.binding; MethodScope methodScope = scope.methodScope(); // check for forward references if (this.indexOfFirstFieldBinding == 1 && methodScope.enclosingSourceType() == fieldBinding.original().declaringClass && methodScope.lastVisibleFieldID >= 0 && fieldBinding.id >= methodScope.lastVisibleFieldID && (!fieldBinding.isStatic() || methodScope.isStatic)) { scope.problemReporter().forwardReference(this, 0, methodScope.enclosingSourceType()); } this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits this.bits |= Binding.FIELD; // // check for deprecated receiver type // // deprecation check for receiver type if not first token // if (indexOfFirstFieldBinding > 1) { // if (isTypeUseDeprecated(this.actualReceiverType, scope)) // scope.problemReporter().deprecatedType(this.actualReceiverType, this); // } return this.resolvedType = getOtherFieldBindings(scope); } // thus it was a type this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits this.bits |= Binding.TYPE; case Binding.TYPE: // =============only type ============== TypeBinding type = (TypeBinding) this.binding; // if (isTypeUseDeprecated(type, scope)) // scope.problemReporter().deprecatedType(type, this); return this.resolvedType = type; } } // ========error cases=============== return this.resolvedType = this.reportError(scope); }
/** Check and/or redirect the field access to the delegate receiver if any */ public TypeBinding checkFieldAccess(BlockScope scope) { FieldBinding fieldBinding = (FieldBinding) this.binding; MethodScope methodScope = scope.methodScope(); // check for forward references if (this.indexOfFirstFieldBinding == 1 && methodScope.enclosingSourceType() == fieldBinding.original().declaringClass && methodScope.lastVisibleFieldID >= 0 && fieldBinding.id >= methodScope.lastVisibleFieldID && (!fieldBinding.isStatic() || methodScope.isStatic)) { scope.problemReporter().forwardReference(this, 0, methodScope.enclosingSourceType()); } this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits this.bits |= Binding.FIELD; return getOtherFieldBindings(scope); }
public void resolve(BlockScope scope) { MethodScope methodScope = scope.methodScope(); if (methodScope == null) { /* return statement outside of a method */ scope.problemReporter().cannotReturnOutsideFunction(this); return; } MethodBinding methodBinding = null; TypeBinding methodType = (methodScope.referenceContext instanceof AbstractMethodDeclaration) ? ((methodBinding = ((AbstractMethodDeclaration) methodScope.referenceContext).binding) == null ? null : methodBinding.returnType) : TypeBinding.ANY; TypeBinding expressionType; if (this.expression == null) { if (methodType != null && !methodType.isAnyType()) scope.problemReporter().shouldReturn(methodType, this); return; } this.expression.setExpectedType(methodType); // needed in case of generic method invocation if ((expressionType = this.expression.resolveType(scope)) == null) return; if (methodType == null) return; if (methodType != expressionType) // must call before computeConversion() and typeMismatchError() scope.compilationUnitScope().recordTypeConversion(methodType, expressionType); if (this.expression.isConstantValueOfTypeAssignableToType(expressionType, methodType) || expressionType.isCompatibleWith(methodType)) { return; } if (methodBinding != null && !methodBinding.isConstructor()) scope.problemReporter().typeMismatchError(expressionType, methodType, this.expression); }
public TypeBinding getOtherFieldBindings(BlockScope scope) { // At this point restrictiveFlag may ONLY have two potential value : FIELD LOCAL (i.e cast // <<(VariableBinding) binding>> is valid) int length = this.tokens.length; FieldBinding field; if ((this.bits & Binding.FIELD) != 0) { field = (FieldBinding) this.binding; if (!field.isStatic()) { // must check for the static status.... if (this.indexOfFirstFieldBinding > 1 // accessing to a field using a type as "receiver" is allowed only with static // field || scope.methodScope() .isStatic) { // the field is the first token of the qualified reference.... scope.problemReporter().staticFieldAccessToNonStaticVariable(this, field); return null; } } else { // indirect static reference ? if (this.indexOfFirstFieldBinding > 1 && field.declaringClass != this.actualReceiverType && field.declaringClass.canBeSeenBy(scope)) { scope.problemReporter().indirectAccessToStaticField(this, field); } } // only last field is actually a write access if any if (isFieldUseDeprecated( field, scope, (this.bits & ASTNode.IsStrictlyAssigned) != 0 && this.indexOfFirstFieldBinding == length)) scope.problemReporter().deprecatedField(field, this); } else { field = null; } TypeBinding type = ((VariableBinding) this.binding).type; int index = this.indexOfFirstFieldBinding; if (index == length) { // restrictiveFlag == FIELD // perform capture conversion if read access return type; } // allocation of the fieldBindings array and its respective constants int otherBindingsLength = length - index; this.otherCodegenBindings = this.otherBindings = new FieldBinding[otherBindingsLength]; this.otherDepths = new int[otherBindingsLength]; // save first depth, since will be updated by visibility checks of other bindings int firstDepth = (this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT; // iteration on each field while (index < length) { char[] token = this.tokens[index]; if (type == null) return null; // could not resolve type prior to this point this.bits &= ~ASTNode.DepthMASK; // flush previous depth if any FieldBinding previousField = field; field = scope.getField(type, token, this); int place = index - this.indexOfFirstFieldBinding; this.otherBindings[place] = field; this.otherDepths[place] = (this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT; if (field.isValidBinding()) { // set generic cast of for previous field (if any) if (previousField != null) { TypeBinding fieldReceiverType = type; TypeBinding receiverErasure = type; if (receiverErasure instanceof ReferenceBinding) { if (receiverErasure.findSuperTypeWithSameErasure(field.declaringClass) == null) { fieldReceiverType = field.declaringClass; // handle indirect inheritance thru variable secondary bound } } FieldBinding originalBinding = previousField.original(); } // only last field is actually a write access if any if (isFieldUseDeprecated( field, scope, (this.bits & ASTNode.IsStrictlyAssigned) != 0 && index + 1 == length)) { scope.problemReporter().deprecatedField(field, this); } if (field.isStatic()) { // static field accessed through receiver? legal but unoptimal (optional warning) scope.problemReporter().nonStaticAccessToStaticField(this, field); // indirect static reference ? if (field.declaringClass != type) { scope.problemReporter().indirectAccessToStaticField(this, field); } } type = field.type; index++; } else { this.constant = Constant.NotAConstant; // don't fill other constants slots... scope.problemReporter().invalidField(this, field, index, type); setDepth(firstDepth); return null; } } setDepth(firstDepth); type = (this.otherBindings[otherBindingsLength - 1]).type; // perform capture conversion if read access return type; }