Skip to content

Commit

Permalink
Merge branch 'master' into issue/1062
Browse files Browse the repository at this point in the history
  • Loading branch information
GrahamTheCoder authored Dec 21, 2023
2 parents 442559d + ee8e18f commit 970410d
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 42 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
* Remove square brackets from identifiers [#1043](https://github.com/icsharpcode/CodeConverter/issues/1043)
* Conversion of parenthesized ref arguments no longer assigns back [#1046](https://github.com/icsharpcode/CodeConverter/issues/1046)
* Conversion of explicit interface implementations now converts optional parameters [#1062](https://github.com/icsharpcode/CodeConverter/issues/1062)
* Constant chars are converted to constant strings where needed
* Select case for a mixture of strings and characters converts correctly [#1062](https://github.com/icsharpcode/CodeConverter/issues/1062)

### C# -> VB

Expand Down
17 changes: 12 additions & 5 deletions CodeConverter/CSharp/MethodBodyExecutableStatementVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,9 @@ public override async Task<SyntaxList<StatementSyntax>> VisitSelectBlock(VBSynta

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

var caseSwitchLabelSyntax = !wrapForStringComparison && correctTypeExpressionSyntax.IsConst && notAlreadyUsed
? (SwitchLabelSyntax)SyntaxFactory.CaseSwitchLabel(csExpressionToUse)
Expand All @@ -783,14 +785,19 @@ public override async Task<SyntaxList<StatementSyntax>> VisitSelectBlock(VBSynta
var varName = CommonConversions.CsEscapedIdentifier(GetUniqueVariableNameInScope(node, "case"));
ExpressionSyntax csLeft = ValidSyntaxFactory.IdentifierName(varName);
var operatorKind = VBasic.VisualBasicExtensions.Kind(relational);
var relationalValue = await relational.Value.AcceptAsync<ExpressionSyntax>(_expressionVisitor);
var binaryExp = SyntaxFactory.BinaryExpression(operatorKind.ConvertToken(), csLeft, relationalValue);
var csRelationalValue = await relational.Value.AcceptAsync<ExpressionSyntax>(_expressionVisitor);
csRelationalValue = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(relational.Value, csRelationalValue);
var binaryExp = SyntaxFactory.BinaryExpression(operatorKind.ConvertToken(), csLeft, csRelationalValue);
labels.Add(VarWhen(varName, binaryExp));
} else if (c is VBSyntax.RangeCaseClauseSyntax range) {
var varName = CommonConversions.CsEscapedIdentifier(GetUniqueVariableNameInScope(node, "case"));
ExpressionSyntax csLeft = ValidSyntaxFactory.IdentifierName(varName);
var lowerBoundCheck = SyntaxFactory.BinaryExpression(SyntaxKind.LessThanOrEqualExpression, await range.LowerBound.AcceptAsync<ExpressionSyntax>(_expressionVisitor), csLeft);
var upperBoundCheck = SyntaxFactory.BinaryExpression(SyntaxKind.LessThanOrEqualExpression, csLeft, await range.UpperBound.AcceptAsync<ExpressionSyntax>(_expressionVisitor));
var lowerBound = await range.LowerBound.AcceptAsync<ExpressionSyntax>(_expressionVisitor);
lowerBound = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(range.LowerBound, lowerBound);
var lowerBoundCheck = SyntaxFactory.BinaryExpression(SyntaxKind.LessThanOrEqualExpression, lowerBound, csLeft);
var upperBound = await range.UpperBound.AcceptAsync<ExpressionSyntax>(_expressionVisitor);
upperBound = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(range.UpperBound, upperBound);
var upperBoundCheck = SyntaxFactory.BinaryExpression(SyntaxKind.LessThanOrEqualExpression, csLeft, upperBound);
var withinBounds = SyntaxFactory.BinaryExpression(SyntaxKind.LogicalAndExpression, lowerBoundCheck, upperBoundCheck);
labels.Add(VarWhen(varName, withinBounds));
} else {
Expand Down
5 changes: 5 additions & 0 deletions CodeConverter/CSharp/TypeConversionAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,11 @@ private static ExpressionSyntax GetToStringConversionOrNull(ExpressionSyntax csN
return csNode;
}

if (currentType is {SpecialType: SpecialType.System_Char} && csNode is CSSyntax.LiteralExpressionSyntax {Token: {} t} l) {
return SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Token(t.LeadingTrivia, SyntaxKind.StringLiteralToken, "\"" + t.Text.Trim('\'') + "\"", t.ValueText, t.TrailingTrivia))
.WithLeadingTrivia(csNode.GetLeadingTrivia()).WithTrailingTrivia(csNode.GetTrailingTrivia());
}

if (currentType.IsNumericType()) {
var toString = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
csNode.AddParens(), ValidSyntaxFactory.IdentifierName(toStringMethodName));
Expand Down
1 change: 1 addition & 0 deletions Tests/CSharp/MissingSemanticModelInfo/ExpressionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ public void PositionEnumFromString(char c)
Console.WriteLine(1);
break;
}
case ',':
{
Console.WriteLine(2);
Expand Down
12 changes: 6 additions & 6 deletions Tests/CSharp/SpecialConversionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -317,19 +317,19 @@ public void Test()
string a;
a = Conversions.ToString(Chr(2));
a = Conversions.ToString(Chr(2));
a = Conversions.ToString('\u0002');
a = Conversions.ToString('\u0002');
a = Conversions.ToString('\u0002');
a = ""\u0002"";
a = ""\u0002"";
a = ""\u0002"";
}
public void TestW()
{
string a;
a = Conversions.ToString(ChrW(2));
a = Conversions.ToString(ChrW(2));
a = Conversions.ToString('\u0002');
a = Conversions.ToString('\u0002');
a = Conversions.ToString('\u0002');
a = ""\u0002"";
a = ""\u0002"";
a = ""\u0002"";
}
public char Chr(object o)
Expand Down
36 changes: 36 additions & 0 deletions Tests/CSharp/TypeCastTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1360,6 +1360,42 @@ private string[] QuoteSplit(string text)
}");
}


[Fact]
public async Task TestSelectCaseComparesCharsAndStringsAsync()
{
await TestConversionVisualBasicToCSharpAsync(
@"
Class CharTestClass
Private Sub Q()
Select Case ""a""
Case ""x""c To ""y""c
Case ""b""c
End Select
End Sub
End Class", @"
internal partial class CharTestClass
{
private void Q()
{
switch (""a"")
{
case var @case when ""x"" <= @case && @case <= ""y"":
{
break;
}
case ""b"":
{
break;
}
}
}
}
1 target compilation errors:
CS0825: The contextual keyword 'var' may only appear within a local variable declaration or in script code");
}

[Fact]
public async Task TestSingleCharacterStringLiteralBecomesChar_WhenExplictCastAsync()
{
Expand Down
10 changes: 6 additions & 4 deletions Web/ClientApp/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import 'bootstrap/dist/css/bootstrap.css';
import React from 'react';
import ReactDOM from 'react-dom';
import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';

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

ReactDOM.render(
const container = document.getElementById('root');
const root = createRoot(container!);

root.render(
<BrowserRouter basename={baseUrl}>
<App />
</BrowserRouter>,
rootElement);
</BrowserRouter>);

registerServiceWorker();
51 changes: 26 additions & 25 deletions Web/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:40163",
"sslPort": 44360
}
"profiles": {
"CodeConverter": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "https://localhost:44463/CodeConverter",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
},
"applicationUrl": "https://localhost:7183;http://localhost:5183"
},
"profiles": {
"CodeConverter": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "https://localhost:7183;http://localhost:5183",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
}
}
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
}
}
},
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:40163",
"sslPort": 44360
}
}
}
4 changes: 2 additions & 2 deletions Web/Web.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>ICSharpCode.CodeConverter.Web</RootNamespace>
<AssemblyName>ICSharpCode.CodeConverter.Web</AssemblyName>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
Expand All @@ -21,7 +21,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="7.0.1" />
<PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="8.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.5" />
</ItemGroup>
Expand Down

0 comments on commit 970410d

Please sign in to comment.