Skip to content
Permalink
Browse files

Merge pull request #412 from mrmonday/363-ternary-conversions

Convert short literals in ternary expressions [#363]
  • Loading branch information
GrahamTheCoder committed Nov 11, 2019
2 parents 7eb997b + 4a3b08e commit fe86a5ab74bf12cb8e572720e012a5b49c3fc2b2
@@ -14,6 +14,7 @@ All notable changes to the code converter will be documented here.
* Improvements to implicit enum -> int conversion (#361)
* Convert expressions in constants (#329)
* Convert implicit `ElementAtOrDefault` (#362)
* Convert types in ternary expressions (#363)

### C# -> VB
* Convert property accessors with visiblity modifiers (#92)
@@ -43,7 +43,7 @@ internal class DeclarationNodeVisitor : VBasic.VisualBasicSyntaxVisitor<Task<CSh
private uint _failedMemberConversionMarkerCount;
private readonly HashSet<string> _extraUsingDirectives = new HashSet<string>();
private readonly VisualBasicEqualityComparison _visualBasicEqualityComparison;
private static HashSet<string> _accessedThroughMyClass;
private HashSet<string> _accessedThroughMyClass;
public CommentConvertingNodesVisitor TriviaConvertingVisitor { get; }
private readonly CommentConvertingVisitorWrapper<CSharpSyntaxNode> _triviaConvertingExpressionVisitor;
private readonly ExpressionNodeVisitor _expressionNodeVisitor;
@@ -837,7 +837,7 @@ private async Task<BlockSyntax> ConvertStatements(SyntaxList<VBSyntax.StatementS
return SyntaxFactory.Block(await statements.SelectManyAsync(async s => (IEnumerable<StatementSyntax>) await s.Accept(methodBodyVisitor)));
}

private static bool IsAccessedThroughMyClass(SyntaxNode node, SyntaxToken identifier, ISymbol symbolOrNull)
private bool IsAccessedThroughMyClass(SyntaxNode node, SyntaxToken identifier, ISymbol symbolOrNull)
{
bool accessedThroughMyClass = false;
if (symbolOrNull != null && symbolOrNull.IsVirtual && !symbolOrNull.IsAbstract) {
@@ -478,11 +478,16 @@ public override async Task<CSharpSyntaxNode> VisitBinaryConditionalExpression(VB

public override async Task<CSharpSyntaxNode> VisitTernaryConditionalExpression(VBasic.Syntax.TernaryConditionalExpressionSyntax node)
{
var expr = SyntaxFactory.ConditionalExpression(
(ExpressionSyntax) await node.Condition.AcceptAsync(TriviaConvertingVisitor),
(ExpressionSyntax) await node.WhenTrue.AcceptAsync(TriviaConvertingVisitor),
(ExpressionSyntax) await node.WhenFalse.AcceptAsync(TriviaConvertingVisitor)
);
var condition = (ExpressionSyntax)await node.Condition.AcceptAsync(TriviaConvertingVisitor);

var whenTrue = (ExpressionSyntax)await node.WhenTrue.AcceptAsync(TriviaConvertingVisitor);
whenTrue = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(node.WhenTrue, whenTrue);

var whenFalse = (ExpressionSyntax)await node.WhenFalse.AcceptAsync(TriviaConvertingVisitor);
whenFalse = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(node.WhenFalse, whenFalse);

var expr = SyntaxFactory.ConditionalExpression(condition, whenTrue, whenFalse);


if (node.Parent.IsKind(VBasic.SyntaxKind.Interpolation) || VbSyntaxNodeExtensions.PrecedenceCouldChange(node))
return SyntaxFactory.ParenthesizedExpression(expr);
@@ -110,7 +110,7 @@ public TypeConversionKind AnalyzeConversion(Microsoft.CodeAnalysis.VisualBasic.S

var vbCompilation = (VisualBasicCompilation) _semanticModel.Compilation;
var vbConversion = vbCompilation.ClassifyConversion(vbType, vbConvertedType);
var csType = _csCompilation.GetTypeByMetadataName(vbType.GetFullMetadataName());
var csType = GetCSType(vbNode, vbType);
var csConvertedType = _csCompilation.GetTypeByMetadataName(vbConvertedType.GetFullMetadataName());

if (csType != null && csConvertedType != null &&
@@ -121,6 +121,20 @@ public TypeConversionKind AnalyzeConversion(Microsoft.CodeAnalysis.VisualBasic.S
return AnalyzeVbConversion(alwaysExplicit, vbType, vbConvertedType, vbConversion);
}

private INamedTypeSymbol GetCSType(VBSyntax.ExpressionSyntax vbNode, ITypeSymbol vbType)
{
// C# does not have literals for short/ushort, so the actual type here is integer
if (vbNode is VBSyntax.LiteralExpressionSyntax literal &&
literal.IsKind(Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.NumericLiteralExpression) &&
literal.Token.Text.EndsWith("S")) {
return _csCompilation.GetSpecialType(SpecialType.System_Int32);
}

var csType = _csCompilation.GetTypeByMetadataName(vbType.GetFullMetadataName());

return csType;
}

private bool TryAnalyzeCsConversion(Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax vbNode, INamedTypeSymbol csType,
INamedTypeSymbol csConvertedType, Conversion vbConversion, ITypeSymbol vbConvertedType, ITypeSymbol vbType,
VisualBasicCompilation vbCompilation, bool isConst, out TypeConversionKind typeConversionKind)
@@ -159,6 +173,9 @@ public TypeConversionKind AnalyzeConversion(Microsoft.CodeAnalysis.VisualBasic.S
} else if (csConversion.IsExplicit && vbConversion.IsNumeric && vbType.TypeKind != TypeKind.Enum) {
typeConversionKind = 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 (isArithmetic) {
var arithmeticConversion =
vbCompilation.ClassifyConversion(vbConvertedType,
@@ -2236,6 +2236,25 @@ End Sub
}");
}

[Fact]
public async Task TernaryConversionIssue363()
{
await TestConversionVisualBasicToCSharpWithoutComments(@"Module Module1
Sub Main()
Dim x As Short = If(True, CShort(50), 100S)
End Sub
End Module", @"using Microsoft.VisualBasic.CompilerServices;
internal static partial class Module1
{
public static void Main()
{
short x = true ? Conversions.ToShort(50) : Conversions.ToShort(100);
}
}
");
}

[Fact]
public async Task MemberAccessCasing()
{

0 comments on commit fe86a5a

Please sign in to comment.
You can’t perform that action at this time.