Skip to content

Commit 5f85ca7

Browse files
Merge pull request #1256 from GrahamTheCoder/claude/fix-issue-892-char-empty-comparison
Claude/fix issue 892 char empty comparison
2 parents f0d557f + 2ade291 commit 5f85ca7

File tree

3 files changed

+81
-11
lines changed

3 files changed

+81
-11
lines changed

CodeConverter/CSharp/BinaryExpressionConverter.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,15 @@ private async Task<CSharpSyntaxNode> ConvertBinaryExpressionAsync(VBasic.Syntax.
8282
case VisualBasicEqualityComparison.RequiredType.StringOnly:
8383
if (lhsTypeInfo.ConvertedType?.SpecialType == SpecialType.System_String &&
8484
rhsTypeInfo.ConvertedType?.SpecialType == SpecialType.System_String &&
85-
_visualBasicEqualityComparison.TryConvertToNullOrEmptyCheck(node, lhs, rhs, out CSharpSyntaxNode visitBinaryExpression)) {
85+
_visualBasicEqualityComparison.TryConvertToNullOrEmptyCheck(node, lhs, rhs, lhsTypeInfo, rhsTypeInfo, out CSharpSyntaxNode visitBinaryExpression)) {
8686
return visitBinaryExpression;
8787
}
88-
(lhs, rhs) = _visualBasicEqualityComparison.AdjustForVbStringComparison(node.Left, lhs, lhsTypeInfo, false, node.Right, rhs, rhsTypeInfo, false);
89-
omitConversion = true; // Already handled within for the appropriate types (rhs can become int in comparison)
88+
if (lhsTypeInfo.Type?.SpecialType == SpecialType.System_Char && rhsTypeInfo.Type?.SpecialType == SpecialType.System_Char) {
89+
// Do nothing, char comparison
90+
} else {
91+
(lhs, rhs) = _visualBasicEqualityComparison.AdjustForVbStringComparison(node.Left, lhs, lhsTypeInfo, false, node.Right, rhs, rhsTypeInfo, false);
92+
omitConversion = true; // Already handled within for the appropriate types (rhs can become int in comparison)
93+
}
9094
break;
9195
case VisualBasicEqualityComparison.RequiredType.Object:
9296
return _visualBasicEqualityComparison.GetFullExpressionForVbObjectComparison(lhs, rhs, VisualBasicEqualityComparison.ComparisonKind.Equals, node.IsKind(VBasic.SyntaxKind.NotEqualsExpression));

CodeConverter/CSharp/VisualBasicEqualityComparison.cs

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ public RequiredType GetObjectEqualityType(params TypeInfo[] typeInfos)
7979

8080
if (typeInfos.All(
8181
t => t.Type == null || t.Type.SpecialType == SpecialType.System_String ||
82+
t.Type.SpecialType == SpecialType.System_Char ||
8283
t.Type.IsArrayOf(SpecialType.System_Char) ) ) {
8384
return RequiredType.StringOnly;
8485
}
@@ -177,20 +178,38 @@ private static ObjectCreationExpressionSyntax NewStringFromArg(ExpressionSyntax
177178
}
178179

179180
public bool TryConvertToNullOrEmptyCheck(VBSyntax.BinaryExpressionSyntax node, ExpressionSyntax lhs,
180-
ExpressionSyntax rhs, out CSharpSyntaxNode? visitBinaryExpression)
181+
ExpressionSyntax rhs, TypeInfo lhsTypeInfo, TypeInfo rhsTypeInfo, out CSharpSyntaxNode? visitBinaryExpression)
181182
{
182-
if (OptionCompareTextCaseInsensitive)
183-
{
184-
visitBinaryExpression = null;
185-
return false;
186-
}
187-
188183
bool lhsEmpty = IsNothingOrEmpty(node.Left);
189184
bool rhsEmpty = IsNothingOrEmpty(node.Right);
190185

191186
if (lhsEmpty || rhsEmpty)
192187
{
193188
var arg = lhsEmpty ? rhs : lhs;
189+
var argType = lhsEmpty ? rhsTypeInfo : lhsTypeInfo;
190+
191+
if (argType.Type?.SpecialType == SpecialType.System_Char) {
192+
// char = "" in VB means char == '\0' (char.MinValue) in C#; not affected by OptionCompareText
193+
var charMinValue = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
194+
SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.CharKeyword)),
195+
ValidSyntaxFactory.IdentifierName("MinValue"));
196+
var equalityKind = node.IsKind(VBasic.SyntaxKind.NotEqualsExpression) ? SyntaxKind.NotEqualsExpression : SyntaxKind.EqualsExpression;
197+
var opToken = SyntaxFactory.Token(node.IsKind(VBasic.SyntaxKind.NotEqualsExpression) ? SyntaxKind.ExclamationEqualsToken : SyntaxKind.EqualsEqualsToken);
198+
visitBinaryExpression = SyntaxFactory.BinaryExpression(equalityKind, arg, opToken, charMinValue);
199+
return true;
200+
}
201+
202+
if (OptionCompareTextCaseInsensitive)
203+
{
204+
visitBinaryExpression = null;
205+
return false;
206+
}
207+
208+
if (argType.Type?.SpecialType != SpecialType.System_String && argType.Type?.SpecialType != SpecialType.System_Object) {
209+
visitBinaryExpression = null;
210+
return false;
211+
}
212+
194213
var nullOrEmpty = SyntaxFactory.InvocationExpression(
195214
SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
196215
SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.StringKeyword)),
@@ -207,7 +226,7 @@ public bool TryConvertToNullOrEmptyCheck(VBSyntax.BinaryExpressionSyntax node, E
207226
return false;
208227
}
209228

210-
private bool IsNothingOrEmpty(VBSyntax.ExpressionSyntax expressionSyntax)
229+
public bool IsNothingOrEmpty(VBSyntax.ExpressionSyntax expressionSyntax)
211230
{
212231
expressionSyntax = expressionSyntax.SkipIntoParens();
213232

Tests/CSharp/ExpressionTests/StringExpressionTests.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,53 @@ public void Foo()
541541
{
542542
string x = Conversions.ToString(DateTime.Parse(""2022-01-01"")) + "" 15:00"";
543543
}
544+
}");
545+
}
546+
547+
[Fact]
548+
public async Task CharEqualityEmptyStringAsync()
549+
{
550+
await TestConversionVisualBasicToCSharpAsync(@"Class TestClass
551+
Private Sub TestMethod()
552+
Dim testChar As Char = Nothing
553+
Dim testResult = testChar = """"
554+
Dim testResult2 = """" = testChar
555+
Dim testResult3 = testChar <> """"
556+
End Sub
557+
End Class", @"
558+
internal partial class TestClass
559+
{
560+
private void TestMethod()
561+
{
562+
char testChar = default;
563+
bool testResult = testChar == char.MinValue;
564+
bool testResult2 = testChar == char.MinValue;
565+
bool testResult3 = testChar != char.MinValue;
566+
}
567+
}");
568+
}
569+
570+
[Fact]
571+
public async Task CharEqualityInConditionAsync()
572+
{
573+
await TestConversionVisualBasicToCSharpAsync(@"Class TestClass
574+
Private Function IsEmpty(c As Char) As Boolean
575+
If c = """" Then
576+
Return True
577+
End If
578+
Return False
579+
End Function
580+
End Class", @"
581+
internal partial class TestClass
582+
{
583+
private bool IsEmpty(char c)
584+
{
585+
if (c == char.MinValue)
586+
{
587+
return true;
588+
}
589+
return false;
590+
}
544591
}");
545592
}
546593
}

0 commit comments

Comments
 (0)