//////////////////////////////////////////////////////////////////////////////// internal EXPR BindToProperty(EXPR pObject, PropWithType pwt, BindingFlag bindFlags, EXPR args, AggregateType pOtherType, EXPRMEMGRP pMemGroup) { Debug.Assert(pwt.Sym != null && pwt.Sym.IsPropertySymbol() && pwt.GetType() != null && pwt.Prop().getClass() == pwt.GetType().getAggregate()); Debug.Assert(pwt.Prop().Params.size == 0 || pwt.Prop().isIndexer()); Debug.Assert(pOtherType == null || !pwt.Prop().isIndexer() && pOtherType.getAggregate() == pwt.Prop().RetType.getAggregate()); bool fConstrained; MethWithType mwtGet; MethWithType mwtSet; EXPR pObjectThrough = null; // We keep track of the type of the pObject which we're doing the call through so that we can report // protection access errors later, either below when binding the get, or later when checking that // the setter is actually an lvalue. If we're actually doing a base.prop call then we do not // need to ensure that the left side of the dot is an instance of the derived class, otherwise // we save it away for later. if (0 == (bindFlags & BindingFlag.BIND_BASECALL)) { pObjectThrough = pObject; } bool bIsMatchingStatic; PostBindProperty((bindFlags & BindingFlag.BIND_BASECALL) != 0, pwt, pObject, out mwtGet, out mwtSet); if (mwtGet && (!mwtSet || mwtSet.GetType() == mwtGet.GetType() || GetSymbolLoader().HasBaseConversion(mwtGet.GetType(), mwtSet.GetType()) ) ) { pObject = AdjustMemberObject(mwtGet, pObject, out fConstrained, out bIsMatchingStatic); } else if (mwtSet) { pObject = AdjustMemberObject(mwtSet, pObject, out fConstrained, out bIsMatchingStatic); } else { pObject = AdjustMemberObject(pwt, pObject, out fConstrained, out bIsMatchingStatic); } pMemGroup.SetOptionalObject(pObject); CType pReturnType = GetTypes().SubstType(pwt.Prop().RetType, pwt.GetType()); Debug.Assert(pOtherType == pReturnType || pOtherType == null); if (pObject != null && !pObject.isOK()) { EXPRPROP pResult = GetExprFactory().CreateProperty(pReturnType, pObjectThrough, args, pMemGroup, pwt, null, null); if (!bIsMatchingStatic) { pResult.SetMismatchedStaticBit(); } pResult.SetError(); return pResult; } // if we are doing a get on this thing, and there is no get, and // most importantly, we are not leaving the arguments to be bound by the array index // then error... if ((bindFlags & BindingFlag.BIND_RVALUEREQUIRED) != 0) { if (!mwtGet) { if (pOtherType != null) { return GetExprFactory().MakeClass(pOtherType); } ErrorContext.ErrorRef(ErrorCode.ERR_PropertyLacksGet, pwt); } else if (((bindFlags & BindingFlag.BIND_BASECALL) != 0) && mwtGet.Meth().isAbstract) { // if the get exists, but is abstract, forbid the call as well... if (pOtherType != null) { return GetExprFactory().MakeClass(pOtherType); } ErrorContext.Error(ErrorCode.ERR_AbstractBaseCall, pwt); } else { CType type = null; if (pObjectThrough != null) { type = pObjectThrough.type; } ACCESSERROR error = SemanticChecker.CheckAccess2(mwtGet.Meth(), mwtGet.GetType(), ContextForMemberLookup(), type); if (error != ACCESSERROR.ACCESSERROR_NOERROR) { // if the get exists, but is not accessible, give an error. if (pOtherType != null) { return GetExprFactory().MakeClass(pOtherType); } if (error == ACCESSERROR.ACCESSERROR_NOACCESSTHRU) { ErrorContext.Error(ErrorCode.ERR_BadProtectedAccess, pwt, type, ContextForMemberLookup()); } else { ErrorContext.ErrorRef(ErrorCode.ERR_InaccessibleGetter, pwt); } } } } EXPRPROP result = GetExprFactory().CreateProperty(pReturnType, pObjectThrough, args, pMemGroup, pwt, mwtGet, mwtSet); if (!bIsMatchingStatic) { result.SetMismatchedStaticBit(); } Debug.Assert(EXPRFLAG.EXF_BASECALL == (EXPRFLAG)BindingFlag.BIND_BASECALL); if ((EXPRFLAG.EXF_BASECALL & (EXPRFLAG)bindFlags) != 0) { result.flags |= EXPRFLAG.EXF_BASECALL; } else if (fConstrained && pObject != null) { // Use the constrained prefix. result.flags |= EXPRFLAG.EXF_CONSTRAINED; } if (result.GetOptionalArguments() != null) { verifyMethodArgs(result, pObjectThrough != null ? pObjectThrough.type : null); } if (mwtSet && objectIsLvalue(result.GetMemberGroup().GetOptionalObject())) { result.flags |= EXPRFLAG.EXF_LVALUE; } if (pOtherType != null) { result.flags |= EXPRFLAG.EXF_SAMENAMETYPE; } return result; }
protected void PostBindProperty(bool fBaseCall, PropWithType pwt, EXPR pObject, out MethWithType pmwtGet, out MethWithType pmwtSet) { pmwtGet = new MethWithType(); pmwtSet = new MethWithType(); // Get the accessors. if (pwt.Prop().methGet != null) { pmwtGet.Set(pwt.Prop().methGet, pwt.GetType()); } else { pmwtGet.Clear(); } if (pwt.Prop().methSet != null) { pmwtSet.Set(pwt.Prop().methSet, pwt.GetType()); } else { pmwtSet.Clear(); } // If it is virtual, find a remap of the method to something more specific. This // may alter where the accessors are found. if (fBaseCall && pObject != null) { if (pmwtGet) { RemapToOverride(GetSymbolLoader(), pmwtGet, pObject.type); } if (pmwtSet) { RemapToOverride(GetSymbolLoader(), pmwtSet, pObject.type); } } if (pwt.Prop().RetType != null) { checkUnsafe(pwt.Prop().RetType); } }