public static bool IsUnnecessaryCast(this CastExpressionSyntax cast, SemanticModel semanticModel, CancellationToken cancellationToken) { var speculationAnalyzer = new SpeculationAnalyzer(cast, cast.Expression, semanticModel, cancellationToken, skipVerificationForReplacedNode: true, failOnOverloadResolutionFailuresInOriginalCode: true); // First, check to see if the node ultimately parenting this cast has any // syntax errors. If so, we bail. if (speculationAnalyzer.SemanticRootOfOriginalExpression.ContainsDiagnostics) { return(false); } var castTypeInfo = semanticModel.GetTypeInfo(cast, cancellationToken); var castType = castTypeInfo.Type; // Case: // 1 . Console.WriteLine(await (dynamic)task); Any Dynamic Cast will not be removed. if (castType == null || castType.Kind == SymbolKind.DynamicType || castType.IsErrorType()) { return(false); } var expressionTypeInfo = semanticModel.GetTypeInfo(cast.Expression, cancellationToken); var expressionType = expressionTypeInfo.Type; // We do not remove any cast on // 1. Dynamic Expressions // 2. If there is any other argument which is dynamic // 3. Dynamic Invocation if ((expressionType != null && (expressionType.IsErrorType() || expressionType.Kind == SymbolKind.DynamicType)) || IsDynamicInvocation(cast, semanticModel, cancellationToken)) { return(false); } if (PointerCastDefinitelyCantBeRemoved(cast)) { return(false); } if (CastPassedToParamsArrayDefinitelyCantBeRemoved(cast, castType, semanticModel, cancellationToken)) { return(false); } if (speculationAnalyzer.ReplacementChangesSemantics()) { return(false); } var expressionToCastType = semanticModel.ClassifyConversion(cast.SpanStart, cast.Expression, castType, isExplicitInSource: true); bool parentIsOrAsExpression; var outerType = GetOuterCastType(cast, semanticModel, out parentIsOrAsExpression) ?? castTypeInfo.ConvertedType; // Simple case: If the conversion from the inner expression to the cast type is identity, // the cast can be removed. if (expressionToCastType.IsIdentity) { // Required explicit cast for reference comparison. // Cast removal causes warning CS0252 (Possible unintended reference comparison). // object x = string.Intern("Hi!"); // (object)x == "Hi!" ExpressionSyntax other; if (IsRequiredCastForReferenceEqualityComparison(outerType, cast, semanticModel, out other)) { var otherToOuterType = semanticModel.ClassifyConversion(other, outerType); if (otherToOuterType.IsImplicit && otherToOuterType.IsReference) { return(false); } } return(true); } if (parentIsOrAsExpression) { // Note: speculationAnalyzer.ReplacementChangesSemantics() ensures that the parenting is or as expression are not broken. // Here we just need to ensure that the original cast expression doesn't invoke a user defined operator. return(!expressionToCastType.IsUserDefined); } if (outerType != null) { var castToOuterType = semanticModel.ClassifyConversion(cast.SpanStart, cast, outerType); var expressionToOuterType = GetSpeculatedExpressionToOuterTypeConversion(speculationAnalyzer.ReplacedExpression, speculationAnalyzer, cancellationToken); // CONSIDER: Anonymous function conversions cannot be compared from different semantic models as lambda symbol comparison requires syntax tree equality. Should this be a compiler bug? // For now, just revert back to computing expressionToOuterType using the original semantic model. if (expressionToOuterType.IsAnonymousFunction) { expressionToOuterType = semanticModel.ClassifyConversion(cast.SpanStart, cast.Expression, outerType); } // If there is an user-defined conversion from the expression to the cast type or the cast // to the outer type, we need to make sure that the same user-defined conversion will be // called if the cast is removed. if (castToOuterType.IsUserDefined || expressionToCastType.IsUserDefined) { return(!expressionToOuterType.IsExplicit && (HaveSameUserDefinedConversion(expressionToCastType, expressionToOuterType) || HaveSameUserDefinedConversion(castToOuterType, expressionToOuterType)) && UserDefinedConversionIsAllowed(cast, semanticModel)); } else if (expressionToOuterType.IsUserDefined) { return(false); } if (expressionToCastType.IsExplicit && expressionToOuterType.IsExplicit) { return(false); } // Required explicit cast for reference comparison. // Cast removal causes warning CS0252 (Possible unintended reference comparison). // object x = string.Intern("Hi!"); // x == (object)"Hi!" ExpressionSyntax other; if (expressionToCastType.IsImplicit && expressionToCastType.IsReference && castToOuterType.IsIdentity && IsRequiredCastForReferenceEqualityComparison(outerType, cast, semanticModel, out other)) { return(false); } // If the conversion from the expression to the cast type is implicit numeric or constant // and the conversion from the expression to the outer type is identity, we'll go ahead // and remove the cast. if (expressionToOuterType.IsIdentity && expressionToCastType.IsImplicit && (expressionToCastType.IsNumeric || expressionToCastType.IsConstantExpression)) { return(true); } if (!castToOuterType.IsBoxing && castToOuterType == expressionToOuterType) { if (castToOuterType.IsNullable) { // Even though both the nullable conversions (castToOuterType and expressionToOuterType) are equal, we can guarantee no data loss only if there is an // implicit conversion from expression type to cast type and expression type is non-nullable. For example, consider the cast removal "(float?)" for below: // Console.WriteLine((int)(float?)(int?)2147483647); // Prints -2147483648 // castToOuterType: ExplicitNullable // expressionToOuterType: ExplicitNullable // expressionToCastType: ImplicitNullable // We should not remove the cast to "float?". // However, cast to "int?" is unnecessary and should be removable. return(expressionToCastType.IsImplicit && ((ITypeSymbol)expressionType.OriginalDefinition).SpecialType != SpecialType.System_Nullable_T); } else if (expressionToCastType.IsImplicit && expressionToCastType.IsNumeric && !castToOuterType.IsIdentity) { // Some implicit numeric conversions can cause loss of precision and must not be removed. return(!IsRequiredImplicitNumericConversion(expressionType, castType)); } return(true); } if (castToOuterType.IsIdentity && !expressionToCastType.IsUnboxing && expressionToCastType == expressionToOuterType) { return(true); } // Special case: It's possible to have useless casts inside delegate creation expressions. // For example: new Func<string, bool>((Predicate<object>)(y => true)). if (IsInDelegateCreationExpression(cast, semanticModel)) { if (expressionToCastType.IsAnonymousFunction && expressionToOuterType.IsAnonymousFunction) { return(!speculationAnalyzer.ReplacementChangesSemanticsOfUnchangedLambda(cast.Expression, speculationAnalyzer.ReplacedExpression)); } if (expressionToCastType.IsMethodGroup && expressionToOuterType.IsMethodGroup) { return(true); } } // Case : // 1. IList<object> y = (IList<dynamic>)new List<object>() if (expressionToCastType.IsExplicit && castToOuterType.IsExplicit && expressionToOuterType.IsImplicit) { return(true); } // Case : // 2. object y = (ValueType)1; if (expressionToCastType.IsBoxing && expressionToOuterType.IsBoxing && castToOuterType.IsImplicit) { return(true); } // Case : // 3. object y = (NullableValueType)null; if ((!castToOuterType.IsBoxing || expressionToCastType.IsNullLiteral) && castToOuterType.IsImplicit && expressionToCastType.IsImplicit && expressionToOuterType.IsImplicit) { if (expressionToOuterType.IsAnonymousFunction) { return(expressionToCastType.IsAnonymousFunction && !speculationAnalyzer.ReplacementChangesSemanticsOfUnchangedLambda(cast.Expression, speculationAnalyzer.ReplacedExpression)); } return(true); } // case : // 4. baseType x; // baseType y = (DerivedType)x; if (expressionToOuterType.IsIdentity && castToOuterType.IsImplicit && castToOuterType.IsReference) { return(true); } } return(false); }
private static bool IsUnnecessaryCast( ExpressionSyntax castNode, ExpressionSyntax castedExpressionNode, SemanticModel semanticModel, CancellationToken cancellationToken) { var speculationAnalyzer = new SpeculationAnalyzer(castNode, castedExpressionNode, semanticModel, cancellationToken, skipVerificationForReplacedNode: true, failOnOverloadResolutionFailuresInOriginalCode: true); // First, check to see if the node ultimately parenting this cast has any // syntax errors. If so, we bail. if (speculationAnalyzer.SemanticRootOfOriginalExpression.ContainsDiagnostics) { return(false); } var castTypeInfo = semanticModel.GetTypeInfo(castNode, cancellationToken); var castType = castTypeInfo.Type; // Case: // 1 . Console.WriteLine(await (dynamic)task); Any Dynamic Cast will not be removed. if (castType == null || castType.Kind == SymbolKind.DynamicType || castType.IsErrorType()) { return(false); } var expressionTypeInfo = semanticModel.GetTypeInfo(castedExpressionNode, cancellationToken); var expressionType = expressionTypeInfo.Type; if (EnumCastDefinitelyCantBeRemoved(castNode, expressionType, castType)) { return(false); } // We do not remove any cast on // 1. Dynamic Expressions // 2. If there is any other argument which is dynamic // 3. Dynamic Invocation // 4. Assignment to dynamic if ((expressionType != null && (expressionType.IsErrorType() || expressionType.Kind == SymbolKind.DynamicType)) || IsDynamicInvocation(castNode, semanticModel, cancellationToken) || IsDynamicAssignment(castNode, semanticModel, cancellationToken)) { return(false); } if (PointerCastDefinitelyCantBeRemoved(castNode, castedExpressionNode)) { return(false); } if (CastPassedToParamsArrayDefinitelyCantBeRemoved(castNode, castType, semanticModel, cancellationToken)) { return(false); } // A casts to object can always be removed from an expression inside of an interpolation, since it'll be converted to object // in order to call string.Format(...) anyway. if (castType?.SpecialType == SpecialType.System_Object && castNode.WalkUpParentheses().IsParentKind(SyntaxKind.Interpolation)) { return(true); } if (speculationAnalyzer.ReplacementChangesSemantics()) { return(false); } var expressionToCastType = semanticModel.ClassifyConversion(castNode.SpanStart, castedExpressionNode, castType, isExplicitInSource: true); var outerType = GetOuterCastType(castNode, semanticModel, out var parentIsOrAsExpression) ?? castTypeInfo.ConvertedType; // Simple case: If the conversion from the inner expression to the cast type is identity, // the cast can be removed. if (expressionToCastType.IsIdentity) { // Simple case: Is this an identity cast to another cast? If so, we're safe to remove it. if (castedExpressionNode.WalkDownParentheses().IsKind(SyntaxKind.CastExpression)) { return(true); } // Required explicit cast for reference comparison. // Cast removal causes warning CS0252 (Possible unintended reference comparison). // object x = string.Intern("Hi!"); // (object)x == "Hi!" if (IsRequiredCastForReferenceEqualityComparison(outerType, castNode, semanticModel, out var other)) { var otherToOuterType = semanticModel.ClassifyConversion(other, outerType); if (otherToOuterType.IsImplicit && otherToOuterType.IsReference) { return(false); } } if (SameSizedFloatingPointCastMustBePreserved( semanticModel, castNode, castedExpressionNode, expressionType, castType, cancellationToken)) { return(false); } return(true); } Debug.Assert(!expressionToCastType.IsIdentity); if (expressionToCastType.IsExplicit) { // Explicit reference conversions can cause an exception or data loss, hence can never be removed. if (expressionToCastType.IsReference) { return(false); } // Unboxing conversions can cause a null ref exception, hence can never be removed. if (expressionToCastType.IsUnboxing) { return(false); } // Don't remove any explicit numeric casts. // https://github.com/dotnet/roslyn/issues/2987 tracks improving on this conservative approach. if (expressionToCastType.IsNumeric) { return(false); } } if (expressionToCastType.IsPointer || expressionToCastType.IsIntPtr) { // Don't remove any non-identity pointer or IntPtr conversions. // https://github.com/dotnet/roslyn/issues/2987 tracks improving on this conservative approach. return(expressionType != null && expressionType.Equals(outerType)); } if (expressionToCastType.IsInterpolatedString) { // interpolation casts are necessary to preserve semantics if our destination type is not itself // FormattableString or some interface of FormattableString. return(castType.Equals(castTypeInfo.ConvertedType) || ImmutableArray <ITypeSymbol> .CastUp(castType.AllInterfaces).Contains(castTypeInfo.ConvertedType)); } if (castedExpressionNode.WalkDownParentheses().IsKind(SyntaxKind.DefaultLiteralExpression) && !castType.Equals(outerType) && outerType.IsNullable()) { // We have a cast like `(T?)(X)default`. We can't remove the inner cast as it effects what value // 'default' means in this context. return(false); } if (parentIsOrAsExpression) { // Note: speculationAnalyzer.ReplacementChangesSemantics() ensures that the parenting is or as expression are not broken. // Here we just need to ensure that the original cast expression doesn't invoke a user defined operator. return(!expressionToCastType.IsUserDefined); } if (outerType != null) { var castToOuterType = semanticModel.ClassifyConversion(castNode.SpanStart, castNode, outerType); var expressionToOuterType = GetSpeculatedExpressionToOuterTypeConversion(speculationAnalyzer.ReplacedExpression, speculationAnalyzer, cancellationToken); // if the conversion to the outer type doesn't exist, then we shouldn't offer, except for anonymous functions which can't be reasoned about the same way (see below) if (!expressionToOuterType.Exists && !expressionToOuterType.IsAnonymousFunction) { return(false); } // CONSIDER: Anonymous function conversions cannot be compared from different semantic models as lambda symbol comparison requires syntax tree equality. Should this be a compiler bug? // For now, just revert back to computing expressionToOuterType using the original semantic model. if (expressionToOuterType.IsAnonymousFunction) { expressionToOuterType = semanticModel.ClassifyConversion(castNode.SpanStart, castedExpressionNode, outerType); } // If there is an user-defined conversion from the expression to the cast type or the cast // to the outer type, we need to make sure that the same user-defined conversion will be // called if the cast is removed. if (castToOuterType.IsUserDefined || expressionToCastType.IsUserDefined) { return(!expressionToOuterType.IsExplicit && (HaveSameUserDefinedConversion(expressionToCastType, expressionToOuterType) || HaveSameUserDefinedConversion(castToOuterType, expressionToOuterType)) && UserDefinedConversionIsAllowed(castNode, semanticModel)); } else if (expressionToOuterType.IsUserDefined) { return(false); } if (expressionToCastType.IsExplicit && expressionToOuterType.IsExplicit) { return(false); } // Required explicit cast for reference comparison. // Cast removal causes warning CS0252 (Possible unintended reference comparison). // object x = string.Intern("Hi!"); // x == (object)"Hi!" if (expressionToCastType.IsImplicit && expressionToCastType.IsReference && castToOuterType.IsIdentity && IsRequiredCastForReferenceEqualityComparison(outerType, castNode, semanticModel, out var other)) { return(false); } // If the conversion from the expression to the cast type is implicit numeric or constant // and the conversion from the expression to the outer type is identity, we'll go ahead // and remove the cast. if (expressionToOuterType.IsIdentity && expressionToCastType.IsImplicit && (expressionToCastType.IsNumeric || expressionToCastType.IsConstantExpression)) { // Some implicit numeric conversions can cause loss of precision and must not be removed. return(!IsRequiredImplicitNumericConversion(expressionType, castType)); } if (!castToOuterType.IsBoxing && castToOuterType == expressionToOuterType) { if (castToOuterType.IsNullable) { // Even though both the nullable conversions (castToOuterType and expressionToOuterType) are equal, we can guarantee no data loss only if there is an // implicit conversion from expression type to cast type and expression type is non-nullable. For example, consider the cast removal "(float?)" for below: // Console.WriteLine((int)(float?)(int?)2147483647); // Prints -2147483648 // castToOuterType: ExplicitNullable // expressionToOuterType: ExplicitNullable // expressionToCastType: ImplicitNullable // We should not remove the cast to "float?". // However, cast to "int?" is unnecessary and should be removable. return(expressionToCastType.IsImplicit && !expressionType.IsNullable()); } else if (expressionToCastType.IsImplicit && expressionToCastType.IsNumeric && !castToOuterType.IsIdentity) { // Some implicit numeric conversions can cause loss of precision and must not be removed. return(!IsRequiredImplicitNumericConversion(expressionType, castType)); } return(true); } if (castToOuterType.IsIdentity && !expressionToCastType.IsUnboxing && expressionToCastType == expressionToOuterType) { return(true); } // Special case: It's possible to have useless casts inside delegate creation expressions. // For example: new Func<string, bool>((Predicate<object>)(y => true)). if (IsInDelegateCreationExpression(castNode, semanticModel)) { if (expressionToCastType.IsAnonymousFunction && expressionToOuterType.IsAnonymousFunction) { return(!speculationAnalyzer.ReplacementChangesSemanticsOfUnchangedLambda(castedExpressionNode, speculationAnalyzer.ReplacedExpression)); } if (expressionToCastType.IsMethodGroup && expressionToOuterType.IsMethodGroup) { return(true); } } // Case : // 1. IList<object> y = (IList<dynamic>)new List<object>() if (expressionToCastType.IsExplicit && castToOuterType.IsExplicit && expressionToOuterType.IsImplicit) { // If both expressionToCastType and castToOuterType are numeric, then this is a required cast as one of the conversions leads to loss of precision. // Cast removal can change program behavior. return(!(expressionToCastType.IsNumeric && castToOuterType.IsNumeric)); } // Case : // 2. object y = (ValueType)1; if (expressionToCastType.IsBoxing && expressionToOuterType.IsBoxing && castToOuterType.IsImplicit) { return(true); } // Case : // 3. object y = (NullableValueType)null; if ((!castToOuterType.IsBoxing || expressionToCastType.IsNullLiteral) && castToOuterType.IsImplicit && expressionToCastType.IsImplicit && expressionToOuterType.IsImplicit) { if (expressionToOuterType.IsAnonymousFunction) { return(expressionToCastType.IsAnonymousFunction && !speculationAnalyzer.ReplacementChangesSemanticsOfUnchangedLambda(castedExpressionNode, speculationAnalyzer.ReplacedExpression)); } return(true); } } return(false); }
public static bool IsUnnecessaryCast(this CastExpressionSyntax cast, SemanticModel semanticModel, CancellationToken cancellationToken) { var speculationAnalyzer = new SpeculationAnalyzer(cast, cast.Expression, semanticModel, cancellationToken, skipVerificationForReplacedNode: true, failOnOverloadResolutionFailuresInOriginalCode: true); // First, check to see if the node ultimately parenting this cast has any // syntax errors. If so, we bail. if (speculationAnalyzer.SemanticRootOfOriginalExpression.ContainsDiagnostics) { return false; } var castTypeInfo = semanticModel.GetTypeInfo(cast, cancellationToken); var castType = castTypeInfo.Type; // Case: // 1 . Console.WriteLine(await (dynamic)task); Any Dynamic Cast will not be removed. if (castType == null || castType.Kind == SymbolKind.DynamicType || castType.IsErrorType()) { return false; } var expressionTypeInfo = semanticModel.GetTypeInfo(cast.Expression, cancellationToken); var expressionType = expressionTypeInfo.Type; // We do not remove any cast on // 1. Dynamic Expressions // 2. If there is any other argument which is dynamic // 3. Dynamic Invocation if ((expressionType != null && (expressionType.IsErrorType() || expressionType.Kind == SymbolKind.DynamicType)) || IsDynamicInvocation(cast, semanticModel, cancellationToken)) { return false; } if (PointerCastDefinitelyCantBeRemoved(cast)) { return false; } if (CastPassedToParamsArrayDefinitelyCantBeRemoved(cast, castType, semanticModel, cancellationToken)) { return false; } if (speculationAnalyzer.ReplacementChangesSemantics()) { return false; } var expressionToCastType = semanticModel.ClassifyConversion(cast.SpanStart, cast.Expression, castType, isExplicitInSource: true); bool parentIsOrAsExpression; var outerType = GetOuterCastType(cast, semanticModel, out parentIsOrAsExpression) ?? castTypeInfo.ConvertedType; // Simple case: If the conversion from the inner expression to the cast type is identity, // the cast can be removed. if (expressionToCastType.IsIdentity) { // Required explicit cast for reference comparison. // Cast removal causes warning CS0252 (Possible unintended reference comparison). // object x = string.Intern("Hi!"); // (object)x == "Hi!" ExpressionSyntax other; if (IsRequiredCastForReferenceEqualityComparison(outerType, cast, semanticModel, out other)) { var otherToOuterType = semanticModel.ClassifyConversion(other, outerType); if (otherToOuterType.IsImplicit && otherToOuterType.IsReference) { return false; } } return true; } else if (expressionToCastType.IsExplicit && expressionToCastType.IsReference) { // Explicit reference conversions can cause an exception or data loss, hence can never be removed. return false; } else if (expressionToCastType.IsExplicit && expressionToCastType.IsNumeric && IsInExplicitCheckedOrUncheckedContext(cast)) { // Don't remove any explicit numeric casts in explicit checked/unchecked context. // https://github.com/dotnet/roslyn/issues/2987 tracks improving on this conservative approach. return false; } else if (expressionToCastType.IsPointer) { // Don't remove any non-identity pointer conversions. // https://github.com/dotnet/roslyn/issues/2987 tracks improving on this conservative approach. return expressionType != null && expressionType.Equals(outerType); } if (parentIsOrAsExpression) { // Note: speculationAnalyzer.ReplacementChangesSemantics() ensures that the parenting is or as expression are not broken. // Here we just need to ensure that the original cast expression doesn't invoke a user defined operator. return !expressionToCastType.IsUserDefined; } if (outerType != null) { var castToOuterType = semanticModel.ClassifyConversion(cast.SpanStart, cast, outerType); var expressionToOuterType = GetSpeculatedExpressionToOuterTypeConversion(speculationAnalyzer.ReplacedExpression, speculationAnalyzer, cancellationToken); // CONSIDER: Anonymous function conversions cannot be compared from different semantic models as lambda symbol comparison requires syntax tree equality. Should this be a compiler bug? // For now, just revert back to computing expressionToOuterType using the original semantic model. if (expressionToOuterType.IsAnonymousFunction) { expressionToOuterType = semanticModel.ClassifyConversion(cast.SpanStart, cast.Expression, outerType); } // If there is an user-defined conversion from the expression to the cast type or the cast // to the outer type, we need to make sure that the same user-defined conversion will be // called if the cast is removed. if (castToOuterType.IsUserDefined || expressionToCastType.IsUserDefined) { return !expressionToOuterType.IsExplicit && (HaveSameUserDefinedConversion(expressionToCastType, expressionToOuterType) || HaveSameUserDefinedConversion(castToOuterType, expressionToOuterType)) && UserDefinedConversionIsAllowed(cast, semanticModel); } else if (expressionToOuterType.IsUserDefined) { return false; } if (expressionToCastType.IsExplicit && expressionToOuterType.IsExplicit) { return false; } // Required explicit cast for reference comparison. // Cast removal causes warning CS0252 (Possible unintended reference comparison). // object x = string.Intern("Hi!"); // x == (object)"Hi!" ExpressionSyntax other; if (expressionToCastType.IsImplicit && expressionToCastType.IsReference && castToOuterType.IsIdentity && IsRequiredCastForReferenceEqualityComparison(outerType, cast, semanticModel, out other)) { return false; } // If the conversion from the expression to the cast type is implicit numeric or constant // and the conversion from the expression to the outer type is identity, we'll go ahead // and remove the cast. if (expressionToOuterType.IsIdentity && expressionToCastType.IsImplicit && (expressionToCastType.IsNumeric || expressionToCastType.IsConstantExpression)) { return true; } if (!castToOuterType.IsBoxing && castToOuterType == expressionToOuterType) { if (castToOuterType.IsNullable) { // Even though both the nullable conversions (castToOuterType and expressionToOuterType) are equal, we can guarantee no data loss only if there is an // implicit conversion from expression type to cast type and expression type is non-nullable. For example, consider the cast removal "(float?)" for below: // Console.WriteLine((int)(float?)(int?)2147483647); // Prints -2147483648 // castToOuterType: ExplicitNullable // expressionToOuterType: ExplicitNullable // expressionToCastType: ImplicitNullable // We should not remove the cast to "float?". // However, cast to "int?" is unnecessary and should be removable. return expressionToCastType.IsImplicit && !((ITypeSymbol)expressionType).IsNullable(); } else if (expressionToCastType.IsImplicit && expressionToCastType.IsNumeric && !castToOuterType.IsIdentity) { // Some implicit numeric conversions can cause loss of precision and must not be removed. return !IsRequiredImplicitNumericConversion(expressionType, castType); } return true; } if (castToOuterType.IsIdentity && !expressionToCastType.IsUnboxing && expressionToCastType == expressionToOuterType) { return true; } // Special case: It's possible to have useless casts inside delegate creation expressions. // For example: new Func<string, bool>((Predicate<object>)(y => true)). if (IsInDelegateCreationExpression(cast, semanticModel)) { if (expressionToCastType.IsAnonymousFunction && expressionToOuterType.IsAnonymousFunction) { return !speculationAnalyzer.ReplacementChangesSemanticsOfUnchangedLambda(cast.Expression, speculationAnalyzer.ReplacedExpression); } if (expressionToCastType.IsMethodGroup && expressionToOuterType.IsMethodGroup) { return true; } } // Case : // 1. IList<object> y = (IList<dynamic>)new List<object>() if (expressionToCastType.IsExplicit && castToOuterType.IsExplicit && expressionToOuterType.IsImplicit) { // If both expressionToCastType and castToOuterType are numeric, then this is a required cast as one of the conversions leads to loss of precision. // Cast removal can change program behavior. return !(expressionToCastType.IsNumeric && castToOuterType.IsNumeric); } // Case : // 2. object y = (ValueType)1; if (expressionToCastType.IsBoxing && expressionToOuterType.IsBoxing && castToOuterType.IsImplicit) { return true; } // Case : // 3. object y = (NullableValueType)null; if ((!castToOuterType.IsBoxing || expressionToCastType.IsNullLiteral) && castToOuterType.IsImplicit && expressionToCastType.IsImplicit && expressionToOuterType.IsImplicit) { if (expressionToOuterType.IsAnonymousFunction) { return expressionToCastType.IsAnonymousFunction && !speculationAnalyzer.ReplacementChangesSemanticsOfUnchangedLambda(cast.Expression, speculationAnalyzer.ReplacedExpression); } return true; } } return false; }