private bool TryAnalyzeCsConversion(Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax vbNode, ITypeSymbol csType, ITypeSymbol csConvertedType, Conversion vbConversion, ITypeSymbol vbConvertedType, ITypeSymbol vbType, VisualBasicCompilation vbCompilation, bool isConst, out TypeConversionKind typeConversionKind) { var csConversion = _csCompilation.ClassifyConversion(csType, csConvertedType); bool isConvertToString = (vbConversion.IsString || vbConversion.IsReference && vbConversion.IsNarrowing) && vbConvertedType.SpecialType == SpecialType.System_String; bool isArithmetic = vbNode.IsKind(Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.AddExpression, Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.SubtractExpression, Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.MultiplyExpression, Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.DivideExpression, Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.IntegerDivideExpression); if (!csConversion.Exists || csConversion.IsUnboxing) { if (ConvertStringToCharLiteral(vbNode, vbConvertedType, out _)) { typeConversionKind = TypeConversionKind.Identity; // Already handled elsewhere by other usage of method return(true); } if (vbType.SpecialType == SpecialType.System_String && vbConvertedType.IsArrayOf(SpecialType.System_Char)) { typeConversionKind = TypeConversionKind.StringToCharArray; return(true); } if (isConvertToString || vbConversion.IsNarrowing) { typeConversionKind = isConst ? TypeConversionKind.ConstConversion : TypeConversionKind.Conversion; return(true); } } else if (vbConversion.IsWidening && vbConversion.IsNumeric && csConversion.IsImplicit && csConversion.IsNumeric) { // Safe overapproximation: A cast is really only needed to help resolve the overload for the operator/method used. // e.g. When VB "&" changes to C# "+", there are lots more overloads available that implicit casts could match. // e.g. sbyte * ulong uses the decimal * operator in VB. In C# it's ambiguous - see ExpressionTests.vb "TestMul". typeConversionKind = TypeConversionKind.NonDestructiveCast; return(true); } else if (csConversion.IsExplicit && csConversion.IsEnumeration) { typeConversionKind = TypeConversionKind.NonDestructiveCast; return(true); } else if (isArithmetic) { var arithmeticConversion = vbCompilation.ClassifyConversion(vbConvertedType, vbCompilation.GetTypeByMetadataName("System.Int32")); if (arithmeticConversion.IsWidening && !arithmeticConversion.IsIdentity) { typeConversionKind = isConst ? TypeConversionKind.ConstConversion : TypeConversionKind.Conversion; return(true); } } else if (csConversion.IsExplicit && csConversion.IsNumeric && vbConversion.IsNarrowing && isConst) { typeConversionKind = IsImplicitConstantConversion(vbNode) ? TypeConversionKind.Identity : TypeConversionKind.NonDestructiveCast; return(true); } else if (csConversion.IsExplicit && vbConversion.IsNumeric && vbType.TypeKind != TypeKind.Enum) { typeConversionKind = IsImplicitConstantConversion(vbNode) ? TypeConversionKind.Identity : isConst ? TypeConversionKind.ConstConversion : TypeConversionKind.Conversion; return(true); } else if (csConversion.IsExplicit && vbConversion.IsIdentity && csConversion.IsNumeric && vbType.TypeKind != TypeKind.Enum) { typeConversionKind = isConst ? TypeConversionKind.ConstConversion : TypeConversionKind.Conversion; return(true); } else if (isConvertToString && vbType.SpecialType == SpecialType.System_Object) { typeConversionKind = isConst ? TypeConversionKind.ConstConversion : TypeConversionKind.Conversion; return(true); } else if (csConversion.IsNullable && csConvertedType.SpecialType == SpecialType.System_Boolean) { typeConversionKind = TypeConversionKind.NullableBool; return(true); } else if (csConversion.IsExplicit) { typeConversionKind = TypeConversionKind.DestructiveCast; return(true); } typeConversionKind = csConversion.IsIdentity ? TypeConversionKind.Identity : TypeConversionKind.Unknown; return(false); }