VB -> C#: Convert erase, and a crude conversion for Redim

This commit is contained in:
GrahamTheCoder 2018-03-17 20:47:39 +00:00
Родитель 49261e640b
Коммит 17da71e4f1
3 изменённых файлов: 130 добавлений и 7 удалений

Просмотреть файл

@ -6,6 +6,7 @@ using ICSharpCode.CodeConverter.Util;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using SyntaxFactory = Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
using VBasic = Microsoft.CodeAnalysis.VisualBasic;
using VBSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax;
@ -101,6 +102,91 @@ namespace ICSharpCode.CodeConverter.CSharp
return SingleStatement(SyntaxFactory.AssignmentExpression(kind, (ExpressionSyntax)node.Left.Accept(nodesVisitor), (ExpressionSyntax)node.Right.Accept(nodesVisitor)));
}
public override SyntaxList<StatementSyntax> VisitEraseStatement(VBSyntax.EraseStatementSyntax node)
{
var eraseStatements = node.Expressions.Select<VBSyntax.ExpressionSyntax, StatementSyntax>(arrayExpression => {
var lhs = arrayExpression.Accept(nodesVisitor);
var rhs = SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression);
var assignmentExpressionSyntax =
SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, (ExpressionSyntax)lhs,
rhs);
return SyntaxFactory.ExpressionStatement(assignmentExpressionSyntax);
});
return SyntaxFactory.List(eraseStatements);
}
public override SyntaxList<StatementSyntax> VisitReDimStatement(VBSyntax.ReDimStatementSyntax node)
{
return SyntaxFactory.List(node.Clauses.SelectMany(arrayExpression => arrayExpression.Accept(CommentConvertingVisitor)));
}
public override SyntaxList<StatementSyntax> VisitRedimClause(VBSyntax.RedimClauseSyntax node)
{
bool preserve = node.Parent is VBSyntax.ReDimStatementSyntax rdss && rdss.PreserveKeyword.IsKind(VBasic.SyntaxKind.PreserveKeyword);
var csTargetArrayExpression = (ExpressionSyntax) node.Expression.Accept(nodesVisitor);
var convertedBounds = ConvertArrayBounds(node.ArrayBounds, semanticModel, nodesVisitor).ToList();
var newArrayAssignment = CreateNewArrayAssignment(node.Expression, csTargetArrayExpression, convertedBounds, node.SpanStart);
if (!preserve) return SingleStatement(newArrayAssignment);
var oldTargetName = GetUniqueVariableNameInScope(node, "old" + csTargetArrayExpression.ToString().ToPascalCase());
var oldArrayAssignment = CreateVariableDeclarationAndAssignment(oldTargetName, csTargetArrayExpression);
var oldTargetExpression = SyntaxFactory.IdentifierName(oldTargetName);
var arrayCopyIfNotNull = CreateConditionalRankOneArrayCopy(oldTargetExpression, csTargetArrayExpression, convertedBounds);
return SyntaxFactory.List(new StatementSyntax[] {oldArrayAssignment, newArrayAssignment, arrayCopyIfNotNull});
}
/// <summary>
/// Cut down version of Microsoft.VisualBasic.CompilerServices.Utils.CopyArray
/// </summary>
private static IfStatementSyntax CreateConditionalRankOneArrayCopy(IdentifierNameSyntax oldTargetExpression,
ExpressionSyntax csTargetArrayExpression,
List<ExpressionSyntax> convertedBounds)
{
var expressionSyntax = convertedBounds.Count != 1 ? throw new NotSupportedException("ReDim not supported with Preserve for multi-dimensional arrays")
: convertedBounds.Single();
var oldTargetLength = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
oldTargetExpression, SyntaxFactory.IdentifierName("Length"));
var minLength = SyntaxFactory.InvocationExpression(SyntaxFactory.ParseExpression("Math.Min"),
CreateArgList(expressionSyntax, oldTargetLength));
var oldTargetNotEqualToNull = SyntaxFactory.BinaryExpression(SyntaxKind.NotEqualsExpression, oldTargetExpression,
SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression));
var copyArgList = CreateArgList(oldTargetExpression, csTargetArrayExpression, minLength);
var arrayCopy = SyntaxFactory.InvocationExpression(SyntaxFactory.ParseExpression("Array.Copy"), copyArgList);
return SyntaxFactory.IfStatement(oldTargetNotEqualToNull, SyntaxFactory.ExpressionStatement(arrayCopy));
}
private ExpressionStatementSyntax CreateNewArrayAssignment(VBSyntax.ExpressionSyntax vbArrayExpression,
ExpressionSyntax csArrayExpression, List<ExpressionSyntax> convertedBounds,
int nodeSpanStart)
{
var arrayRankSpecifierSyntax = SyntaxFactory.ArrayRankSpecifier(SyntaxFactory.SeparatedList(convertedBounds));
var convertedType = (IArrayTypeSymbol) semanticModel.GetTypeInfo(vbArrayExpression).ConvertedType;
var typeSyntax = GetTypeSyntaxFromTypeSymbol(convertedType.ElementType, nodeSpanStart);
var arrayCreation =
SyntaxFactory.ArrayCreationExpression(SyntaxFactory.ArrayType(typeSyntax,
SyntaxFactory.SingletonList(arrayRankSpecifierSyntax)));
var assignmentExpressionSyntax =
SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, csArrayExpression, arrayCreation);
var newArrayAssignment = SyntaxFactory.ExpressionStatement(assignmentExpressionSyntax);
return newArrayAssignment;
}
private static ArgumentListSyntax CreateArgList(params ExpressionSyntax[] copyArgs)
{
return SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(copyArgs.Select(SyntaxFactory.Argument)));
}
private TypeSyntax GetTypeSyntaxFromTypeSymbol(ITypeSymbol convertedType, int nodeSpanStart)
{
var predefinedKeywordKind = convertedType.SpecialType.GetPredefinedKeywordKind();
if (predefinedKeywordKind != SyntaxKind.None) return SyntaxFactory.PredefinedType(SyntaxFactory.Token(predefinedKeywordKind));
return SyntaxFactory.ParseTypeName(convertedType.ToMinimalDisplayString(semanticModel, nodeSpanStart));
}
public override SyntaxList<StatementSyntax> VisitThrowStatement(VBSyntax.ThrowStatementSyntax node)
{
return SingleStatement(SyntaxFactory.ThrowStatement((ExpressionSyntax)node.Expression?.Accept(nodesVisitor)));
@ -327,12 +413,7 @@ namespace ICSharpCode.CodeConverter.CSharp
var withExpression = (ExpressionSyntax)node.WithStatement.Expression.Accept(nodesVisitor);
withBlockTempVariableNames.Push(GetUniqueVariableNameInScope(node, "withBlock"));
try {
var variableDeclaratorSyntax = SyntaxFactory.VariableDeclarator(
SyntaxFactory.Identifier(withBlockTempVariableNames.Peek()), null,
SyntaxFactory.EqualsValueClause(withExpression));
var declaration = SyntaxFactory.LocalDeclarationStatement(SyntaxFactory.VariableDeclaration(
SyntaxFactory.IdentifierName("var"),
SyntaxFactory.SingletonSeparatedList(variableDeclaratorSyntax)));
var declaration = CreateVariableDeclarationAndAssignment(withBlockTempVariableNames.Peek(), withExpression);
var statements = node.Statements.SelectMany(s => s.Accept(CommentConvertingVisitor));
return SingleStatement(SyntaxFactory.Block(new[] { declaration }.Concat(statements).ToArray()));
@ -341,6 +422,16 @@ namespace ICSharpCode.CodeConverter.CSharp
}
}
private LocalDeclarationStatementSyntax CreateVariableDeclarationAndAssignment(string variableName, ExpressionSyntax initValue)
{
var variableDeclaratorSyntax = SyntaxFactory.VariableDeclarator(
SyntaxFactory.Identifier(variableName), null,
SyntaxFactory.EqualsValueClause(initValue));
return SyntaxFactory.LocalDeclarationStatement(SyntaxFactory.VariableDeclaration(
SyntaxFactory.IdentifierName("var"),
SyntaxFactory.SingletonSeparatedList(variableDeclaratorSyntax)));
}
private string GetUniqueVariableNameInScope(SyntaxNode node, string variableNameBase)
{
var reservedNames = withBlockTempVariableNames.Concat(node.DescendantNodesAndSelf()

Просмотреть файл

@ -1971,7 +1971,7 @@ namespace ICSharpCode.CodeConverter.Util
/// </summary>
/// <param name="specialType">The specialtype of this type.</param>
/// <returns>The keyword kind for a given special type, or SyntaxKind.None if the type name is not a predefined type.</returns>
public static SyntaxKind GetPredefinedKeywordKind(SpecialType specialType)
public static SyntaxKind GetPredefinedKeywordKind(this SpecialType specialType)
{
switch (specialType) {
case SpecialType.System_Boolean:

Просмотреть файл

@ -194,6 +194,38 @@ class TestClass
}");
}
[Fact]
public void ArrayEraseAndRedimStatement()
{
// One statement turns into two, so can't auto-test comments
TestConversionVisualBasicToCSharpWithoutComments(@"Public Class TestClass
Shared Function TestMethod(numArray As Integer(), numArray2 As Integer()) As Integer()
ReDim numArray(3)
Erase numArray
numArray2(1) = 1
ReDim Preserve numArray(5), numArray2(5)
Return numArray2
End Function
End Class", @"public class TestClass
{
public static int[] TestMethod(int[] numArray, int[] numArray2)
{
numArray = new int[4];
numArray = null;
numArray2[1] = 1;
var oldNumArray = numArray;
numArray = new int[6];
if (oldNumArray != null)
Array.Copy(oldNumArray, numArray, Math.Min(6, oldNumArray.Length));
var oldNumArray2 = numArray2;
numArray2 = new int[6];
if (oldNumArray2 != null)
Array.Copy(oldNumArray2, numArray2, Math.Min(6, oldNumArray2.Length));
return numArray2;
}
}");
}
[Fact]
public void EndStatement()
{