private ExpressionSyntax AddExplicitConversion(Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, ITypeSymbol vbConvertedType, TypeConversionKind conversionKind, bool addParenthesisIfNeeded) { switch (conversionKind) { case TypeConversionKind.Unknown: case TypeConversionKind.Identity: return(addParenthesisIfNeeded ? VbSyntaxNodeExtensions.ParenthesizeIfPrecedenceCouldChange(vbNode, csNode) : csNode); case TypeConversionKind.Implicit: return(ValidSyntaxFactory.CastExpression(_semanticModel.GetCsTypeSyntax(vbConvertedType, vbNode), csNode)); case TypeConversionKind.Explicit: return(AddExplicitConvertTo(vbNode, csNode, vbConvertedType)); default: throw new ArgumentOutOfRangeException(); } }
private ExpressionSyntax AddTypeConversion(VBSyntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, TypeConversionKind conversionKind, bool addParenthesisIfNeeded, ITypeSymbol vbType, ITypeSymbol vbConvertedType) { switch (conversionKind) { case TypeConversionKind.EnumConversionThenCast: var underlyingType = ((INamedTypeSymbol)vbConvertedType).EnumUnderlyingType; csNode = AddTypeConversion(vbNode, csNode, TypeConversionKind.Conversion, addParenthesisIfNeeded, vbType, underlyingType); return(AddTypeConversion(vbNode, csNode, TypeConversionKind.NonDestructiveCast, addParenthesisIfNeeded, underlyingType, vbConvertedType)); case TypeConversionKind.EnumCastThenConversion: var enumUnderlyingType = ((INamedTypeSymbol)vbType).EnumUnderlyingType; csNode = AddTypeConversion(vbNode, csNode, TypeConversionKind.NonDestructiveCast, addParenthesisIfNeeded, vbType, enumUnderlyingType); return(AddTypeConversion(vbNode, csNode, TypeConversionKind.Conversion, addParenthesisIfNeeded, enumUnderlyingType, vbConvertedType)); case TypeConversionKind.Unknown: case TypeConversionKind.Identity: return(addParenthesisIfNeeded ? vbNode.ParenthesizeIfPrecedenceCouldChange(csNode) : csNode); case TypeConversionKind.DestructiveCast: case TypeConversionKind.NonDestructiveCast: return(CreateCast(csNode, vbConvertedType)); case TypeConversionKind.Conversion: return(AddExplicitConvertTo(vbNode, csNode, vbType, vbConvertedType));; case TypeConversionKind.NullableBool: return(SyntaxFactory.BinaryExpression(SyntaxKind.EqualsExpression, csNode, LiteralConversions.GetLiteralExpression(true))); case TypeConversionKind.StringToCharArray: var memberAccessExpressionSyntax = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, csNode, SyntaxFactory.IdentifierName(nameof(string.ToCharArray))); return(SyntaxFactory.InvocationExpression(memberAccessExpressionSyntax, SyntaxFactory.ArgumentList())); case TypeConversionKind.DelegateConstructor: return(SyntaxFactory.ObjectCreationExpression(GetCommonDelegateTypeOrNull(vbNode, vbConvertedType)).WithArgumentList(new[] { csNode }.CreateCsArgList())); default: throw new ArgumentOutOfRangeException(); } }
public (ExpressionSyntax Expr, bool IsConst) AddExplicitConversion(VBSyntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, TypeConversionKind conversionKind, bool addParenthesisIfNeeded = false, bool requiresConst = false, ITypeSymbol forceSourceType = null, ITypeSymbol forceTargetType = null) { var(vbType, vbConvertedType) = GetTypeInfo(vbNode, forceSourceType, forceTargetType); bool resultConst = false; if (requiresConst) { var(constExpression, isCorrectType) = _expressionEvaluator.GetConstantOrNull(vbNode, vbConvertedType, conversionKind, csNode); if (isCorrectType) { return(constExpression, true); } if (constExpression != null) { csNode = constExpression ?? csNode; resultConst = true; } } var typeConvertedResult = AddTypeConversion(vbNode, csNode, conversionKind, addParenthesisIfNeeded, vbType, vbConvertedType); return(typeConvertedResult, resultConst); }
public ExpressionSyntax AddExplicitConversion(Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, TypeConversionKind conversionKind, bool addParenthesisIfNeeded = false, ITypeSymbol forceTargetType = null) { var vbConvertedType = forceTargetType ?? ModelExtensions.GetTypeInfo(_semanticModel, vbNode).ConvertedType; switch (conversionKind) { case TypeConversionKind.Unknown: case TypeConversionKind.Identity: return(addParenthesisIfNeeded ? VbSyntaxNodeExtensions.ParenthesizeIfPrecedenceCouldChange(vbNode, csNode) : csNode); case TypeConversionKind.DestructiveCast: case TypeConversionKind.NonDestructiveCast: return(CreateCast(csNode, vbConvertedType)); case TypeConversionKind.Conversion: return(AddExplicitConvertTo(vbNode, csNode, vbConvertedType)); case TypeConversionKind.ConstConversion: return(ConstantFold(vbNode, vbConvertedType)); case TypeConversionKind.NullableBool: return(SyntaxFactory.BinaryExpression(SyntaxKind.EqualsExpression, csNode, LiteralConversions.GetLiteralExpression(true))); case TypeConversionKind.StringToCharArray: var memberAccessExpressionSyntax = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, csNode, SyntaxFactory.IdentifierName(nameof(string.ToCharArray))); return(SyntaxFactory.InvocationExpression(memberAccessExpressionSyntax, SyntaxFactory.ArgumentList())); default: throw new ArgumentOutOfRangeException(); } }
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); }
public ExpressionSyntax AddExplicitConversion(Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, TypeConversionKind conversionKind, bool addParenthesisIfNeeded = false) { var vbConvertedType = ModelExtensions.GetTypeInfo(_semanticModel, vbNode).ConvertedType; switch (conversionKind) { case TypeConversionKind.Unknown: case TypeConversionKind.Identity: return(addParenthesisIfNeeded ? VbSyntaxNodeExtensions.ParenthesizeIfPrecedenceCouldChange(vbNode, csNode) : csNode); case TypeConversionKind.DestructiveCast: case TypeConversionKind.NonDestructiveCast: return(CreateCast(csNode, vbConvertedType)); case TypeConversionKind.Conversion: return(AddExplicitConvertTo(vbNode, csNode, vbConvertedType)); default: throw new ArgumentOutOfRangeException(); } }
private ExpressionSyntax AddTypeConversion(VBSyntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, TypeConversionKind conversionKind, bool addParenthesisIfNeeded, ITypeSymbol vbType, ITypeSymbol vbConvertedType) { switch (conversionKind) { case TypeConversionKind.Unknown: case TypeConversionKind.Identity: return(addParenthesisIfNeeded ? VbSyntaxNodeExtensions.ParenthesizeIfPrecedenceCouldChange(vbNode, csNode) : csNode); case TypeConversionKind.DestructiveCast: case TypeConversionKind.NonDestructiveCast: return(CreateCast(csNode, vbConvertedType)); case TypeConversionKind.Conversion: return(AddExplicitConvertTo(vbNode, csNode, vbType, vbConvertedType));; case TypeConversionKind.NullableBool: return(SyntaxFactory.BinaryExpression(SyntaxKind.EqualsExpression, csNode, LiteralConversions.GetLiteralExpression(true))); case TypeConversionKind.StringToCharArray: var memberAccessExpressionSyntax = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, csNode, SyntaxFactory.IdentifierName(nameof(string.ToCharArray))); return(SyntaxFactory.InvocationExpression(memberAccessExpressionSyntax, SyntaxFactory.ArgumentList())); default: throw new ArgumentOutOfRangeException(); } }
public (ExpressionSyntax Expr, bool IsConst) AddExplicitConversion(Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, TypeConversionKind conversionKind, bool addParenthesisIfNeeded = false, bool requiresConst = false, ITypeSymbol forceSourceType = null, ITypeSymbol forceTargetType = null) { var typeInfo = ModelExtensions.GetTypeInfo(_semanticModel, vbNode); var vbType = forceSourceType ?? typeInfo.Type; var vbConvertedType = forceTargetType ?? typeInfo.ConvertedType; bool resultConst = false; if (requiresConst) { var(constExpression, isCorrectType) = _expressionEvaluator.GetConstantOrNull(vbNode, vbConvertedType, conversionKind, csNode); if (isCorrectType) { return(constExpression, true); } if (constExpression != null) { csNode = constExpression ?? csNode; resultConst = true; } } var typeConvertedResult = AddTypeConversion(vbNode, csNode, conversionKind, addParenthesisIfNeeded, vbType, vbConvertedType); return(typeConvertedResult, resultConst); }
private ExpressionSyntax AddExplicitConversion(Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, TypeConversionKind conversionKind, bool addParenthesisIfNeeded) { var vbConvertedType = _semanticModel.GetTypeInfo(vbNode).ConvertedType; switch (conversionKind) { case TypeConversionKind.Unknown: case TypeConversionKind.Identity: return(addParenthesisIfNeeded ? VbSyntaxNodeExtensions.ParenthesizeIfPrecedenceCouldChange(vbNode, csNode) : csNode); case TypeConversionKind.DestructiveCast: case TypeConversionKind.NonDestructiveCast: var typeName = (TypeSyntax)_csSyntaxGenerator.TypeExpression(vbConvertedType); if (csNode is CastExpressionSyntax cast && cast.Type.IsEquivalentTo(typeName)) { return(csNode); } return(ValidSyntaxFactory.CastExpression(typeName, csNode)); case TypeConversionKind.Conversion: return(AddExplicitConvertTo(vbNode, csNode, vbConvertedType)); default: throw new ArgumentOutOfRangeException(); } }