Skip to content

Commit 2b49fbf

Browse files
8.1.7 addendum - Convert string operators in common cases - fixes #608
1 parent 8ba435c commit 2b49fbf

File tree

4 files changed

+42
-12
lines changed

4 files changed

+42
-12
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
2727
* No longer adds incorrect "base" qualification for virtual method calls [#600](https://github.com/icsharpcode/CodeConverter/issues/600)
2828
* Don't generate unnecessary properties for WithEvents fields [#572](https://github.com/icsharpcode/CodeConverter/issues/572)
2929
* Add type conversion where needed for externally declared loop control variable [#609](https://github.com/icsharpcode/CodeConverter/issues/609)
30+
* Convert string operators in common cases [#608](https://github.com/icsharpcode/CodeConverter/issues/608)
3031

3132
### C# -> VB
3233

CodeConverter/CSharp/BuiltInVisualBasicOperatorSubstitutions.cs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,15 @@ private async Task<ExpressionSyntax> ConvertToDecimalComparisonOperatorAsync(VBS
171171
return null;
172172
}
173173

174-
private async Task<ExpressionSyntax> ConvertToStringComparisonOperatorAsync(VBSyntax.BinaryExpressionSyntax node)
174+
private async Task<ExpressionSyntax> ConvertToStringComparisonOperatorAsync(VBSyntax.BinaryExpressionSyntax node, SyntaxKind expressionKind)
175175
{
176-
return null;
176+
var (lhs, rhs) = await AcceptSidesAsync(node);
177+
lhs = VisualBasicEqualityComparison.VbCoerceToString(lhs, _semanticModel.GetTypeInfo(node.Left));
178+
rhs = VisualBasicEqualityComparison.VbCoerceToString(rhs, _semanticModel.GetTypeInfo(node.Right));
179+
var member = new KnownMethod(_compilerServices, _operators, "CompareString");
180+
var optionaCompareTextBoolLiteralExpression = _visualBasicEqualityComparison.OptionCompareTextCaseInsensitiveBoolExpression;
181+
var comparedLhs = member.Invoke(_visualBasicEqualityComparison.ExtraUsingDirectives, lhs, rhs, optionaCompareTextBoolLiteralExpression);
182+
return SyntaxFactory.BinaryExpression(expressionKind, comparedLhs, LiteralConversions.GetLiteralExpression(0));
177183
}
178184

179185
private async Task<ExpressionSyntax> ConvertToMethodAsync(VBSyntax.BinaryExpressionSyntax node, KnownMethod member)
@@ -196,7 +202,7 @@ public async Task<ExpressionSyntax> ConvertRewrittenBinaryOperatorOrNullAsync(VB
196202
{
197203
var opKind = node.Kind();
198204
var nodeType = _semanticModel.GetTypeInfo(node).Type;
199-
var leftType = _semanticModel.GetTypeInfo(node.Left).Type;
205+
var leftType = _semanticModel.GetTypeInfo(node.Left).ConvertedType;
200206
switch (opKind) {
201207
case BinaryOperatorKind.IsExpression:
202208
case BinaryOperatorKind.IsNotExpression: {
@@ -234,7 +240,7 @@ public async Task<ExpressionSyntax> ConvertRewrittenBinaryOperatorOrNullAsync(VB
234240
if (leftType.IsObjectType()) {
235241
return await ConvertToObjectComparisonOperatorAsync(node, (_compilerServices, _operators, "ConditionalCompareObjectEqual"));
236242
} else if (leftType.IsStringType()) {
237-
return await ConvertToStringComparisonOperatorAsync(node);
243+
return null; //Handled elsewhere
238244
} else if (leftType.IsDecimalType()) {
239245
return await ConvertToDecimalComparisonOperatorAsync(node);
240246
} else if (leftType.IsDateTimeType()) {
@@ -254,7 +260,7 @@ public async Task<ExpressionSyntax> ConvertRewrittenBinaryOperatorOrNullAsync(VB
254260
if (leftType.IsObjectType()) {
255261
return await ConvertToObjectComparisonOperatorAsync(node, (_compilerServices, _operators, "ConditionalCompareObjectNotEqual"));
256262
} else if (leftType.IsStringType()) {
257-
return await ConvertToStringComparisonOperatorAsync(node);
263+
return null; //Handled elsewhere
258264
} else if (leftType.IsDecimalType()) {
259265
return await ConvertToDecimalComparisonOperatorAsync(node);
260266
} else if (leftType.IsDateTimeType()) {
@@ -274,7 +280,7 @@ public async Task<ExpressionSyntax> ConvertRewrittenBinaryOperatorOrNullAsync(VB
274280
if (leftType.IsObjectType()) {
275281
return await ConvertToObjectComparisonOperatorAsync(node, (_compilerServices, _operators, "ConditionalCompareObjectLessEqual"));
276282
} else if (leftType.IsStringType()) {
277-
return await ConvertToStringComparisonOperatorAsync(node);
283+
return await ConvertToStringComparisonOperatorAsync(node, SyntaxKind.LessThanOrEqualExpression);
278284
} else if (leftType.IsDecimalType()) {
279285
return await ConvertToDecimalComparisonOperatorAsync(node);
280286
} else if (leftType.IsDateTimeType()) {
@@ -294,7 +300,7 @@ public async Task<ExpressionSyntax> ConvertRewrittenBinaryOperatorOrNullAsync(VB
294300
if (leftType.IsObjectType()) {
295301
return await ConvertToObjectComparisonOperatorAsync(node, (_compilerServices, _operators, "ConditionalCompareObjectGreaterEqual"));
296302
} else if (leftType.IsStringType()) {
297-
return await ConvertToStringComparisonOperatorAsync(node);
303+
return await ConvertToStringComparisonOperatorAsync(node, SyntaxKind.GreaterThanOrEqualExpression);
298304
} else if (leftType.IsDecimalType()) {
299305
return await ConvertToDecimalComparisonOperatorAsync(node);
300306
} else if (leftType.IsDateTimeType()) {
@@ -314,7 +320,7 @@ public async Task<ExpressionSyntax> ConvertRewrittenBinaryOperatorOrNullAsync(VB
314320
if (leftType.IsObjectType()) {
315321
return await ConvertToObjectComparisonOperatorAsync(node, (_compilerServices, _operators, "ConditionalCompareObjectLess"));
316322
} else if (leftType.IsStringType()) {
317-
return await ConvertToStringComparisonOperatorAsync(node);
323+
return await ConvertToStringComparisonOperatorAsync(node, SyntaxKind.LessThanExpression);
318324
} else if (leftType.IsDecimalType()) {
319325
return await ConvertToDecimalComparisonOperatorAsync(node);
320326
} else if (leftType.IsDateTimeType()) {
@@ -334,7 +340,7 @@ public async Task<ExpressionSyntax> ConvertRewrittenBinaryOperatorOrNullAsync(VB
334340
if (leftType.IsObjectType()) {
335341
return await ConvertToObjectComparisonOperatorAsync(node, (_compilerServices, _operators, "ConditionalCompareObjectGreater"));
336342
} else if (leftType.IsStringType()) {
337-
return await ConvertToStringComparisonOperatorAsync(node);
343+
return await ConvertToStringComparisonOperatorAsync(node, SyntaxKind.GreaterThanExpression);
338344
} else if (leftType.IsDecimalType()) {
339345
return await ConvertToDecimalComparisonOperatorAsync(node);
340346
} else if (leftType.IsDateTimeType()) {

CodeConverter/CSharp/VisualBasicEqualityComparison.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,14 @@ public ExpressionSyntax VbCoerceToNonNullString(VBSyntax.ExpressionSyntax vbNode
108108
return VbCoerceToString(csNode, typeInfo);
109109
}
110110

111-
private static ExpressionSyntax VbCoerceToString(ExpressionSyntax csNode, TypeInfo typeInfo)
111+
public static ExpressionSyntax VbCoerceToString(ExpressionSyntax csNode, TypeInfo typeInfo)
112112
{
113-
return typeInfo.Type.SpecialType == SpecialType.System_String ? csNode : NewStringFromArg(csNode);
113+
return typeInfo.Type.SpecialType switch
114+
{
115+
SpecialType.System_String => csNode,
116+
SpecialType.System_Char => SyntaxFactory.InvocationExpression(ValidSyntaxFactory.MemberAccess(csNode, nameof(ToString))),
117+
_ => NewStringFromArg(csNode)
118+
};
114119
}
115120

116121
private bool CanBeNull(VBSyntax.ExpressionSyntax vbNode)

Tests/CSharp/SpecialConversionTests.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
using System.Threading.Tasks;
1+
using System;
2+
using System.Threading.Tasks;
23
using ICSharpCode.CodeConverter.Tests.TestRunners;
4+
using Microsoft.VisualBasic.CompilerServices;
35
using Xunit;
46

57
namespace ICSharpCode.CodeConverter.Tests.CSharp
@@ -265,6 +267,22 @@ public void M(string[] OldWords, string[] NewWords, string HTMLCode)
265267
for (int i = 0, loopTo = Conversions.ToInteger(i < OldWords.Length - 1); i <= loopTo; i++)
266268
HTMLCode = HTMLCode.Replace(OldWords[i], NewWords[i]);
267269
}
270+
}");
271+
}
272+
273+
[Fact]
274+
public async Task StringOperatorsAsync()
275+
{
276+
await TestConversionVisualBasicToCSharpAsync(@" Sub DummyMethod(target As String)
277+
If target < ""Z""c OrElse New Char(){} <= target OrElse target = """" OrElse target <> """" OrElse target >= New Char(){} OrElse target > """" Then
278+
Console.WriteLine(""It must be one of those"")
279+
End If
280+
End Sub", @"public void DummyMethod(string target)
281+
{
282+
if (Operators.CompareString(target, 'Z'.ToString(), false) < 0 || Operators.CompareString(new string(new char[] { }), target, false) <= 0 || string.IsNullOrEmpty(target) || !string.IsNullOrEmpty(target) || Operators.CompareString(target, new string(new char[] { }), false) >= 0 || Operators.CompareString(target, """", false) > 0)
283+
{
284+
Console.WriteLine(""It must be one of those"");
285+
}
268286
}");
269287
}
270288
}

0 commit comments

Comments
 (0)