Skip to content

Commit 34317c1

Browse files
Handle MidAssignmentStatement
Part of #544
1 parent d2d7e2e commit 34317c1

File tree

5 files changed

+72
-10
lines changed

5 files changed

+72
-10
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
1818
* Fix logic issue when converting expression passed in byref within conditional expression - [#310](https://github.com/icsharpcode/CodeConverter/issues/310)
1919
* Added constructors now only added to the relevant type - not other types in the same file
2020
* Converted non-static field initializers moved to constructor - [#281](https://github.com/icsharpcode/CodeConverter/issues/281)
21+
* Convert assignments using "Mid" built-in function
22+
2123

2224
### C# -> VB
2325

CodeConverter/CSharp/ExpressionNodeVisitor.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,9 +1483,10 @@ private enum RefConversion
14831483
private ISymbol GetInvocationSymbol(SyntaxNode invocation)
14841484
{
14851485
var symbol = invocation.TypeSwitch(
1486-
(VBasic.Syntax.InvocationExpressionSyntax e) => _semanticModel.GetSymbolInfo(e).ExtractBestMatch<ISymbol>(),
1487-
(VBasic.Syntax.ObjectCreationExpressionSyntax e) => _semanticModel.GetSymbolInfo(e).ExtractBestMatch<ISymbol>(),
1488-
(VBasic.Syntax.RaiseEventStatementSyntax e) => _semanticModel.GetSymbolInfo(e.Name).ExtractBestMatch<ISymbol>(),
1486+
(VBSyntax.InvocationExpressionSyntax e) => _semanticModel.GetSymbolInfo(e).ExtractBestMatch<ISymbol>(),
1487+
(VBSyntax.ObjectCreationExpressionSyntax e) => _semanticModel.GetSymbolInfo(e).ExtractBestMatch<ISymbol>(),
1488+
(VBSyntax.RaiseEventStatementSyntax e) => _semanticModel.GetSymbolInfo(e.Name).ExtractBestMatch<ISymbol>(),
1489+
(VBSyntax.MidExpressionSyntax e) => _semanticModel.Compilation.GetTypeByMetadataName("Microsoft.VisualBasic.CompilerServices.StringType")?.GetMembers("MidStmtStr").FirstOrDefault(),
14891490
_ => { throw new NotSupportedException(); }
14901491
);
14911492
return symbol;

CodeConverter/CSharp/MethodBodyExecutableStatementVisitor.cs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ public override async Task<SyntaxList<StatementSyntax>> VisitExpressionStatement
143143

144144
public override async Task<SyntaxList<StatementSyntax>> VisitAssignmentStatement(VBSyntax.AssignmentStatementSyntax node)
145145
{
146+
if (node.IsKind(VBasic.SyntaxKind.MidAssignmentStatement) && node.Left is VBSyntax.MidExpressionSyntax mes) {
147+
return await ConvertMidAssignment(node, mes);
148+
}
149+
146150
var lhs = (ExpressionSyntax) await node.Left.AcceptAsync(_expressionVisitor);
147151
var lOperation = _semanticModel.GetOperation(node.Left);
148152

@@ -160,7 +164,7 @@ _methodNode is VBSyntax.MethodBlockSyntax mb &&
160164

161165
if (node.IsKind(VBasic.SyntaxKind.ExponentiateAssignmentStatement)) {
162166
rhs = SyntaxFactory.InvocationExpression(
163-
SyntaxFactory.ParseExpression($"{nameof(Math)}.{nameof(Math.Pow)}"),
167+
ValidSyntaxFactory.MemberAccess(nameof(Math), nameof(Math.Pow)),
164168
ExpressionSyntaxExtensions.CreateArgList(lhs, rhs));
165169
}
166170
var kind = node.Kind().ConvertToken(TokenContext.Local);
@@ -172,6 +176,21 @@ _methodNode is VBSyntax.MethodBlockSyntax mb &&
172176
return postAssignment.Insert(0, SyntaxFactory.ExpressionStatement(assignment));
173177
}
174178

179+
private async Task<SyntaxList<StatementSyntax>> ConvertMidAssignment(VBSyntax.AssignmentStatementSyntax node, VBSyntax.MidExpressionSyntax mes)
180+
{
181+
_extraUsingDirectives.Add("Microsoft.VisualBasic.CompilerServices");
182+
var midFunction = ValidSyntaxFactory.MemberAccess("StringType", "MidStmtStr");
183+
var midArgList = (ArgumentListSyntax)await mes.ArgumentList.AcceptAsync(_expressionVisitor);
184+
var (reusable, statements, _) = await GetExpressionWithoutSideEffectsAsync(node.Right, "midTmp");
185+
if (midArgList.Arguments.Count == 2) {
186+
var length = ValidSyntaxFactory.MemberAccess(reusable, "Length");
187+
midArgList = midArgList.AddArguments(SyntaxFactory.Argument(length));
188+
}
189+
midArgList = midArgList.AddArguments(SyntaxFactory.Argument(reusable));
190+
var invokeMid = SyntaxFactory.InvocationExpression(midFunction, midArgList);
191+
return statements.Add(SyntaxFactory.ExpressionStatement(invokeMid));
192+
}
193+
175194
/// <remarks>
176195
/// <see cref="CommonConversions.ConvertIdentifier"/> ensures we convert the property access to a field access
177196
/// </remarks>
@@ -214,7 +233,7 @@ private async Task<SyntaxList<StatementSyntax>> ConvertRedimClause(VBSyntax.Redi
214233
if (!preserve) return SingleStatement(newArrayAssignment);
215234

216235
var lastIdentifierText = node.Expression.DescendantNodesAndSelf().OfType<VBSyntax.IdentifierNameSyntax>().Last().Identifier.Text;
217-
var (oldTargetExpression, stmts, _) = await GetExpressionWithoutSideEffects(node.Expression, "old" + lastIdentifierText.ToPascalCase(), true);
236+
var (oldTargetExpression, stmts, _) = await GetExpressionWithoutSideEffectsAsync(node.Expression, "old" + lastIdentifierText.ToPascalCase(), true);
218237
var arrayCopyIfNotNull = CreateConditionalArrayCopy(node, (IdentifierNameSyntax) oldTargetExpression, csTargetArrayExpression, convertedBounds);
219238

220239
return stmts.AddRange(new StatementSyntax[] {newArrayAssignment, arrayCopyIfNotNull});
@@ -618,7 +637,7 @@ public override async Task<SyntaxList<StatementSyntax>> VisitGoToStatement(VBSyn
618637
public override async Task<SyntaxList<StatementSyntax>> VisitSelectBlock(VBSyntax.SelectBlockSyntax node)
619638
{
620639
var vbExpr = node.SelectStatement.Expression;
621-
var (csExpr, stmts, csExprWithSourceMapping) = await GetExpressionWithoutSideEffects(vbExpr, "switchExpr");
640+
var (csExpr, stmts, csExprWithSourceMapping) = await GetExpressionWithoutSideEffectsAsync(vbExpr, "switchExpr");
622641
var usedConstantValues = new HashSet<object>();
623642
var sections = new List<SwitchSectionSyntax>();
624643
foreach (var block in node.CaseBlocks) {
@@ -666,9 +685,10 @@ public override async Task<SyntaxList<StatementSyntax>> VisitSelectBlock(VBSynta
666685
return stmts.Add(switchStatementSyntax);
667686
}
668687

669-
private async Task<(ExpressionSyntax Reusable, SyntaxList<StatementSyntax> Statements, ExpressionSyntax SingleUse)> GetExpressionWithoutSideEffects(VBSyntax.ExpressionSyntax vbExpr, string variableNameBase, bool forceVariable = false)
688+
private async Task<(ExpressionSyntax Reusable, SyntaxList<StatementSyntax> Statements, ExpressionSyntax SingleUse)> GetExpressionWithoutSideEffectsAsync(VBSyntax.ExpressionSyntax vbExpr, string variableNameBase, bool forceVariable = false)
670689
{
671690
var expr = (ExpressionSyntax)await vbExpr.AcceptAsync(_expressionVisitor);
691+
expr = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(vbExpr, expr);
672692
SyntaxList<StatementSyntax> stmts = SyntaxFactory.List<StatementSyntax>();
673693
ExpressionSyntax exprWithoutSideEffects;
674694
ExpressionSyntax reusableExprWithoutSideEffects;
@@ -723,7 +743,7 @@ private CasePatternSwitchLabelSyntax WrapInCasePatternSwitchLabelSyntax(VBSyntax
723743

724744
public override async Task<SyntaxList<StatementSyntax>> VisitWithBlock(VBSyntax.WithBlockSyntax node)
725745
{
726-
var (lhsExpression, prefixDeclarations, _) = await GetExpressionWithoutSideEffects(node.WithStatement.Expression, "withBlock");
746+
var (lhsExpression, prefixDeclarations, _) = await GetExpressionWithoutSideEffectsAsync(node.WithStatement.Expression, "withBlock");
727747

728748
_withBlockLhs.Push(lhsExpression);
729749
try {

CodeConverter/CSharp/ValidSyntaxFactory.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@ public static SwitchStatementSyntax SwitchStatement(ExpressionSyntax expr, List<
2828
SyntaxFactory.List(sections), SyntaxFactory.Token(SyntaxKind.CloseBraceToken));
2929
}
3030

31-
public static ExpressionSyntax MemberAccess(params string[] nameParts)
31+
public static ExpressionSyntax MemberAccess(params string[] nameParts) => MemberAccess(null, nameParts);
32+
33+
public static ExpressionSyntax MemberAccess(ExpressionSyntax lhs, params string[] nameParts)
3234
{
33-
ExpressionSyntax lhs = null;
3435
foreach (var namePart in nameParts) {
3536
if (lhs == null) lhs = SyntaxFactory.IdentifierName(namePart);
3637
else {

Tests/CSharp/SpecialConversionTests.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,44 @@ public partial class Issue483
168168
public int Test4 = 0x7D;
169169
public int Test5 = 0x7E;
170170
public int Test6 = 0x7F;
171+
}");
172+
}
173+
174+
[Fact]
175+
public async Task Issue544_AssignUsingMid()
176+
{
177+
await TestConversionVisualBasicToCSharpAsync(
178+
@"Public Class Issue483
179+
Private Function numstr(ByVal aDouble As Double) As String
180+
Dim str_Txt As String = Format(aDouble, ""0.000000"")
181+
Mid(str_Txt, Len(str_Txt) - 6, 1) = "".""
182+
Mid(str_Txt, Len(str_Txt) - 6) = "".""
183+
Mid(str_Txt, Len(str_Txt) - 6) = aDouble
184+
Console.WriteLine(aDouble)
185+
If aDouble > 5.0 Then Mid(str_Txt, Len(str_Txt) - 6) = numstr(aDouble - 1.0)
186+
Return str_Txt
187+
End Function
188+
End Class", @"using System;
189+
using Microsoft.VisualBasic;
190+
using Microsoft.VisualBasic.CompilerServices;
191+
192+
public partial class Issue483
193+
{
194+
private string numstr(double aDouble)
195+
{
196+
string str_Txt = Strings.Format(aDouble, ""0.000000"");
197+
StringType.MidStmtStr(ref str_Txt, Strings.Len(str_Txt) - 6, 1, ""."");
198+
StringType.MidStmtStr(ref str_Txt, Strings.Len(str_Txt) - 6, ""."".Length, ""."");
199+
StringType.MidStmtStr(ref str_Txt, Strings.Len(str_Txt) - 6, aDouble.ToString().Length, aDouble.ToString());
200+
Console.WriteLine(aDouble);
201+
if (aDouble > 5.0)
202+
{
203+
var midTmp = numstr(aDouble - 1.0);
204+
StringType.MidStmtStr(ref str_Txt, Strings.Len(str_Txt) - 6, midTmp.Length, midTmp);
205+
}
206+
207+
return str_Txt;
208+
}
171209
}");
172210
}
173211
}

0 commit comments

Comments
 (0)