///////////////////////////////////////////////////////////////////////////////// private UnaryOperatorSignatureFindResult PopulateSignatureList(EXPR pArgument, UnaOpKind unaryOpKind, UnaOpMask unaryOpMask, ExpressionKind exprKind, EXPRFLAG flags, List<UnaOpFullSig> pSignatures, out EXPR ppResult) { // We should have already checked argument != null and argument.type != null. Debug.Assert(pArgument != null); Debug.Assert(pArgument.type != null); ppResult = null; CType pArgumentType = pArgument.type; CType pRawType = pArgumentType.StripNubs(); PredefinedType ptRaw = pRawType.isPredefined() ? pRawType.getPredefType() : PredefinedType.PT_COUNT; // Find all applicable operator signatures. // First check for special ones (enum, ptr) and check for user defined ops. if (ptRaw > PredefinedType.PT_ULONG) { // Enum types are special in that they carry a set of "predefined" operators (~ and inc/dec). if (pRawType.isEnumType()) { if ((unaryOpMask & (UnaOpMask.Tilde | UnaOpMask.IncDec)) != 0) { // We have an exact match. LiftFlags liftFlags = LiftFlags.None; CType typeSig = pArgumentType; if (typeSig.IsNullableType()) { if (typeSig.AsNullableType().GetUnderlyingType() != pRawType) { typeSig = GetSymbolLoader().GetTypeManager().GetNullable(pRawType); } liftFlags = LiftFlags.Lift1; } if (unaryOpKind == UnaOpKind.Tilde) { pSignatures.Add(new UnaOpFullSig( typeSig.getAggregate().GetUnderlyingType(), BindEnumUnaOp, liftFlags, UnaOpFuncKind.EnumUnaOp)); } else { // For enums, we want to add the signature as the underlying type so that we'll // perform the conversions to and from the enum type. pSignatures.Add(new UnaOpFullSig( typeSig.getAggregate().GetUnderlyingType(), null, liftFlags, UnaOpFuncKind.None)); } return UnaryOperatorSignatureFindResult.Match; } } else if (unaryOpKind == UnaOpKind.IncDec) { // Check for pointers if (pArgumentType.IsPointerType()) { pSignatures.Add(new UnaOpFullSig( pArgumentType, null, LiftFlags.None, UnaOpFuncKind.None)); return UnaryOperatorSignatureFindResult.Match; } // Check for user defined inc/dec #if !CSEE EXPRMULTIGET exprGet = GetExprFactory().CreateMultiGet(0, pArgumentType, null); #else // CSEE EXPR exprGet = pArgument; #endif // CSEE EXPR exprVal = bindUDUnop((ExpressionKind)(exprKind - ExpressionKind.EK_ADD + ExpressionKind.EK_INC), exprGet); if (exprVal != null) { if (exprVal.type != null && !exprVal.type.IsErrorType() && exprVal.type != pArgumentType) { exprVal = mustConvert(exprVal, pArgumentType); } Debug.Assert(pArgument != null); EXPRMULTI exprMulti = GetExprFactory().CreateMulti(EXPRFLAG.EXF_ASSGOP | flags, pArgumentType, pArgument, exprVal); #if ! CSEE exprGet.SetOptionalMulti(exprMulti); #endif // !CSEE // Check whether Lvalue can be assigned. checkLvalue may return true // despite reporting an error. if (!checkLvalue(pArgument, CheckLvalueKind.Increment)) { // This seems like it can never be reached - exprVal is only valid if // we have a UDUnop, and in order for checkLValue to return false, either the // arg has to not be OK, in which case we shouldn't get here, or we have an // AnonMeth, Lambda, or Constant, all of which cannot have UDUnops defined for them. exprMulti.SetError(); } ppResult = exprMulti; return UnaryOperatorSignatureFindResult.Return; } // Try for a predefined increment operator. } else { // Check for user defined. EXPR expr = bindUDUnop(exprKind, pArgument); if (expr != null) { ppResult = expr; return UnaryOperatorSignatureFindResult.Return; } } } return UnaryOperatorSignatureFindResult.Continue; }
///////////////////////////////////////////////////////////////////////////////// // Bind a standard unary operator. Takes care of user defined operators, predefined operators // and lifting over nullable. private static bool CalculateExprAndUnaryOpKinds( OperatorKind op, bool bChecked, out /*out*/ ExpressionKind ek, out /*out*/ UnaOpKind uok, out /*out*/ EXPRFLAG flags) { flags = 0; ek = 0; uok = 0; switch (op) { case OperatorKind.OP_UPLUS: uok = UnaOpKind.Plus; ek = ExpressionKind.EK_UPLUS; break; case OperatorKind.OP_NEG: if (bChecked) { flags |= EXPRFLAG.EXF_CHECKOVERFLOW; } uok = UnaOpKind.Minus; ek = ExpressionKind.EK_NEG; break; case OperatorKind.OP_BITNOT: uok = UnaOpKind.Tilde; ek = ExpressionKind.EK_BITNOT; break; case OperatorKind.OP_LOGNOT: uok = UnaOpKind.Bang; ek = ExpressionKind.EK_LOGNOT; break; case OperatorKind.OP_POSTINC: flags |= EXPRFLAG.EXF_ISPOSTOP; if (bChecked) { flags |= EXPRFLAG.EXF_CHECKOVERFLOW; } uok = UnaOpKind.IncDec; ek = ExpressionKind.EK_ADD; break; case OperatorKind.OP_PREINC: if (bChecked) { flags |= EXPRFLAG.EXF_CHECKOVERFLOW; } uok = UnaOpKind.IncDec; ek = ExpressionKind.EK_ADD; break; case OperatorKind.OP_POSTDEC: flags |= EXPRFLAG.EXF_ISPOSTOP; if (bChecked) { flags |= EXPRFLAG.EXF_CHECKOVERFLOW; } uok = UnaOpKind.IncDec; ek = ExpressionKind.EK_SUB; break; case OperatorKind.OP_PREDEC: if (bChecked) { flags |= EXPRFLAG.EXF_CHECKOVERFLOW; } uok = UnaOpKind.IncDec; ek = ExpressionKind.EK_SUB; break; default: VSFAIL("Bad op"); return false; } return true; }