Skip to content

Commit 970410d

Browse files
Merge branch 'master' into issue/1062
2 parents 442559d + ee8e18f commit 970410d

9 files changed

Lines changed: 96 additions & 42 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
1313
* Remove square brackets from identifiers [#1043](https://github.com/icsharpcode/CodeConverter/issues/1043)
1414
* Conversion of parenthesized ref arguments no longer assigns back [#1046](https://github.com/icsharpcode/CodeConverter/issues/1046)
1515
* Conversion of explicit interface implementations now converts optional parameters [#1062](https://github.com/icsharpcode/CodeConverter/issues/1062)
16+
* Constant chars are converted to constant strings where needed
17+
* Select case for a mixture of strings and characters converts correctly [#1062](https://github.com/icsharpcode/CodeConverter/issues/1062)
1618

1719
### C# -> VB
1820

CodeConverter/CSharp/MethodBodyExecutableStatementVisitor.cs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,9 @@ public override async Task<SyntaxList<StatementSyntax>> VisitSelectBlock(VBSynta
770770

771771
// CSharp requires an explicit cast from the base type (e.g. int) in most cases switching on an enum
772772
var isBooleanCase = caseTypeInfo.Type?.SpecialType == SpecialType.System_Boolean;
773-
var csExpressionToUse = IsEnumOrNullableEnum(switchExprTypeInfo.ConvertedType) ^ IsEnumOrNullableEnum(caseTypeInfo.Type) && !isBooleanCase ? correctTypeExpressionSyntax.Expr : originalExpressionSyntax;
773+
bool enumRelated = IsEnumOrNullableEnum(switchExprTypeInfo.ConvertedType) || IsEnumOrNullableEnum(caseTypeInfo.Type);
774+
bool convertingEnum = IsEnumOrNullableEnum(switchExprTypeInfo.ConvertedType) ^ IsEnumOrNullableEnum(caseTypeInfo.Type);
775+
var csExpressionToUse = !isBooleanCase && (convertingEnum || !enumRelated && correctTypeExpressionSyntax.IsConst) ? correctTypeExpressionSyntax.Expr : originalExpressionSyntax;
774776

775777
var caseSwitchLabelSyntax = !wrapForStringComparison && correctTypeExpressionSyntax.IsConst && notAlreadyUsed
776778
? (SwitchLabelSyntax)SyntaxFactory.CaseSwitchLabel(csExpressionToUse)
@@ -783,14 +785,19 @@ public override async Task<SyntaxList<StatementSyntax>> VisitSelectBlock(VBSynta
783785
var varName = CommonConversions.CsEscapedIdentifier(GetUniqueVariableNameInScope(node, "case"));
784786
ExpressionSyntax csLeft = ValidSyntaxFactory.IdentifierName(varName);
785787
var operatorKind = VBasic.VisualBasicExtensions.Kind(relational);
786-
var relationalValue = await relational.Value.AcceptAsync<ExpressionSyntax>(_expressionVisitor);
787-
var binaryExp = SyntaxFactory.BinaryExpression(operatorKind.ConvertToken(), csLeft, relationalValue);
788+
var csRelationalValue = await relational.Value.AcceptAsync<ExpressionSyntax>(_expressionVisitor);
789+
csRelationalValue = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(relational.Value, csRelationalValue);
790+
var binaryExp = SyntaxFactory.BinaryExpression(operatorKind.ConvertToken(), csLeft, csRelationalValue);
788791
labels.Add(VarWhen(varName, binaryExp));
789792
} else if (c is VBSyntax.RangeCaseClauseSyntax range) {
790793
var varName = CommonConversions.CsEscapedIdentifier(GetUniqueVariableNameInScope(node, "case"));
791794
ExpressionSyntax csLeft = ValidSyntaxFactory.IdentifierName(varName);
792-
var lowerBoundCheck = SyntaxFactory.BinaryExpression(SyntaxKind.LessThanOrEqualExpression, await range.LowerBound.AcceptAsync<ExpressionSyntax>(_expressionVisitor), csLeft);
793-
var upperBoundCheck = SyntaxFactory.BinaryExpression(SyntaxKind.LessThanOrEqualExpression, csLeft, await range.UpperBound.AcceptAsync<ExpressionSyntax>(_expressionVisitor));
795+
var lowerBound = await range.LowerBound.AcceptAsync<ExpressionSyntax>(_expressionVisitor);
796+
lowerBound = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(range.LowerBound, lowerBound);
797+
var lowerBoundCheck = SyntaxFactory.BinaryExpression(SyntaxKind.LessThanOrEqualExpression, lowerBound, csLeft);
798+
var upperBound = await range.UpperBound.AcceptAsync<ExpressionSyntax>(_expressionVisitor);
799+
upperBound = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(range.UpperBound, upperBound);
800+
var upperBoundCheck = SyntaxFactory.BinaryExpression(SyntaxKind.LessThanOrEqualExpression, csLeft, upperBound);
794801
var withinBounds = SyntaxFactory.BinaryExpression(SyntaxKind.LogicalAndExpression, lowerBoundCheck, upperBoundCheck);
795802
labels.Add(VarWhen(varName, withinBounds));
796803
} else {

CodeConverter/CSharp/TypeConversionAnalyzer.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,11 @@ private static ExpressionSyntax GetToStringConversionOrNull(ExpressionSyntax csN
469469
return csNode;
470470
}
471471

472+
if (currentType is {SpecialType: SpecialType.System_Char} && csNode is CSSyntax.LiteralExpressionSyntax {Token: {} t} l) {
473+
return SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Token(t.LeadingTrivia, SyntaxKind.StringLiteralToken, "\"" + t.Text.Trim('\'') + "\"", t.ValueText, t.TrailingTrivia))
474+
.WithLeadingTrivia(csNode.GetLeadingTrivia()).WithTrailingTrivia(csNode.GetTrailingTrivia());
475+
}
476+
472477
if (currentType.IsNumericType()) {
473478
var toString = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
474479
csNode.AddParens(), ValidSyntaxFactory.IdentifierName(toStringMethodName));

Tests/CSharp/MissingSemanticModelInfo/ExpressionTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ public void PositionEnumFromString(char c)
310310
Console.WriteLine(1);
311311
break;
312312
}
313+
313314
case ',':
314315
{
315316
Console.WriteLine(2);

Tests/CSharp/SpecialConversionTests.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -317,19 +317,19 @@ public void Test()
317317
string a;
318318
a = Conversions.ToString(Chr(2));
319319
a = Conversions.ToString(Chr(2));
320-
a = Conversions.ToString('\u0002');
321-
a = Conversions.ToString('\u0002');
322-
a = Conversions.ToString('\u0002');
320+
a = ""\u0002"";
321+
a = ""\u0002"";
322+
a = ""\u0002"";
323323
}
324324
325325
public void TestW()
326326
{
327327
string a;
328328
a = Conversions.ToString(ChrW(2));
329329
a = Conversions.ToString(ChrW(2));
330-
a = Conversions.ToString('\u0002');
331-
a = Conversions.ToString('\u0002');
332-
a = Conversions.ToString('\u0002');
330+
a = ""\u0002"";
331+
a = ""\u0002"";
332+
a = ""\u0002"";
333333
}
334334
335335
public char Chr(object o)

Tests/CSharp/TypeCastTests.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1360,6 +1360,42 @@ private string[] QuoteSplit(string text)
13601360
}");
13611361
}
13621362

1363+
1364+
[Fact]
1365+
public async Task TestSelectCaseComparesCharsAndStringsAsync()
1366+
{
1367+
await TestConversionVisualBasicToCSharpAsync(
1368+
@"
1369+
Class CharTestClass
1370+
Private Sub Q()
1371+
Select Case ""a""
1372+
Case ""x""c To ""y""c
1373+
Case ""b""c
1374+
End Select
1375+
End Sub
1376+
End Class", @"
1377+
internal partial class CharTestClass
1378+
{
1379+
private void Q()
1380+
{
1381+
switch (""a"")
1382+
{
1383+
case var @case when ""x"" <= @case && @case <= ""y"":
1384+
{
1385+
break;
1386+
}
1387+
1388+
case ""b"":
1389+
{
1390+
break;
1391+
}
1392+
}
1393+
}
1394+
}
1395+
1 target compilation errors:
1396+
CS0825: The contextual keyword 'var' may only appear within a local variable declaration or in script code");
1397+
}
1398+
13631399
[Fact]
13641400
public async Task TestSingleCharacterStringLiteralBecomesChar_WhenExplictCastAsync()
13651401
{

Web/ClientApp/src/index.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
import 'bootstrap/dist/css/bootstrap.css';
22
import React from 'react';
33
import ReactDOM from 'react-dom';
4+
import { createRoot } from 'react-dom/client';
45
import { BrowserRouter } from 'react-router-dom';
56
import App from './App';
67
import registerServiceWorker from './registerServiceWorker';
78

89
const baseUrl = document.getElementsByTagName('base')[0].getAttribute('href') || undefined;
9-
const rootElement = document.getElementById('root');
1010

11-
ReactDOM.render(
11+
const container = document.getElementById('root');
12+
const root = createRoot(container!);
13+
14+
root.render(
1215
<BrowserRouter basename={baseUrl}>
1316
<App />
14-
</BrowserRouter>,
15-
rootElement);
17+
</BrowserRouter>);
1618

1719
registerServiceWorker();

Web/Properties/launchSettings.json

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
11
{
2-
"iisSettings": {
3-
"windowsAuthentication": false,
4-
"anonymousAuthentication": true,
5-
"iisExpress": {
6-
"applicationUrl": "http://localhost:40163",
7-
"sslPort": 44360
8-
}
2+
"profiles": {
3+
"CodeConverter": {
4+
"commandName": "Project",
5+
"launchBrowser": true,
6+
"launchUrl": "https://localhost:44463/CodeConverter",
7+
"environmentVariables": {
8+
"ASPNETCORE_ENVIRONMENT": "Development",
9+
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
10+
},
11+
"applicationUrl": "https://localhost:7183;http://localhost:5183"
912
},
10-
"profiles": {
11-
"CodeConverter": {
12-
"commandName": "Project",
13-
"launchBrowser": true,
14-
"applicationUrl": "https://localhost:7183;http://localhost:5183",
15-
"environmentVariables": {
16-
"ASPNETCORE_ENVIRONMENT": "Development",
17-
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
18-
}
19-
},
20-
"IIS Express": {
21-
"commandName": "IISExpress",
22-
"launchBrowser": true,
23-
"environmentVariables": {
24-
"ASPNETCORE_ENVIRONMENT": "Development",
25-
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
26-
}
27-
}
13+
"IIS Express": {
14+
"commandName": "IISExpress",
15+
"launchBrowser": true,
16+
"environmentVariables": {
17+
"ASPNETCORE_ENVIRONMENT": "Development",
18+
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
19+
}
2820
}
21+
},
22+
"iisSettings": {
23+
"windowsAuthentication": false,
24+
"anonymousAuthentication": true,
25+
"iisExpress": {
26+
"applicationUrl": "http://localhost:40163",
27+
"sslPort": 44360
28+
}
29+
}
2930
}

Web/Web.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk.Web">
22

33
<PropertyGroup>
4-
<TargetFramework>net6.0</TargetFramework>
4+
<TargetFramework>net8.0</TargetFramework>
55
<RootNamespace>ICSharpCode.CodeConverter.Web</RootNamespace>
66
<AssemblyName>ICSharpCode.CodeConverter.Web</AssemblyName>
77
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
@@ -21,7 +21,7 @@
2121

2222
<ItemGroup>
2323
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="6.0.0" />
24-
<PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="7.0.1" />
24+
<PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="8.0.0" />
2525
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
2626
<PackageReference Include="System.Data.SqlClient" Version="4.8.5" />
2727
</ItemGroup>

0 commit comments

Comments
 (0)