Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue/1084 #1094

Merged
merged 9 commits into from
Apr 21, 2024
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

### Vsix

* Compatible with Visual Studio 2022 17.1 onwards

### VB -> C#


### C# -> VB

* Converts file scoped namespaces

## [9.2.5] - 2024-01-31

Expand Down
6 changes: 3 additions & 3 deletions CodeConverter/CSharp/ClashingMemberRenamer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ internal static class ClashingMemberRenamer
/// Renames symbols in a VB project so that they don't clash with rules for C# member names, attempting to rename the least public ones first.
/// See https://github.com/icsharpcode/CodeConverter/issues/420
/// </summary>
public static async Task<Project> RenameClashingSymbolsAsync(Project project)
public static async Task<Project> RenameClashingSymbolsAsync(Project project, CancellationToken cancellationToken)
{
var compilation = await project.GetCompilationAsync();
var compilation = await project.GetCompilationAsync(cancellationToken);
var memberRenames = SymbolRenamer.GetNamespacesAndTypesInAssembly(project, compilation)
.SelectMany(x => GetSymbolsWithNewNames(x, compilation));
return await SymbolRenamer.PerformRenamesAsync(project, memberRenames.ToList());
return await SymbolRenamer.PerformRenamesAsync(project, memberRenames.ToList(), cancellationToken);
}

private static IEnumerable<(ISymbol Original, string NewName)> GetSymbolsWithNewNames(INamespaceOrTypeSymbol containerSymbol, Compilation compilation)
Expand Down
2 changes: 1 addition & 1 deletion CodeConverter/CSharp/HandledEventsAnalysis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ private PropertyDeclarationSyntax GetDeclarationsForHandlingBaseMembers((EventCo
var prop = (PropertyDeclarationSyntax) _commonConversions.CsSyntaxGenerator.Declaration(basePropertyEventSubscription.PropertyDetails.Property);
var modifiers = prop.Modifiers.RemoveWhere(m => m.IsKind(SyntaxKind.VirtualKeyword)).Add(SyntaxFactory.Token(SyntaxKind.OverrideKeyword));
//TODO Stash away methodwithandles in constructor that don't match any symbol from that type, to match here against base symbols
return GetDeclarationsForFieldBackedProperty(basePropertyEventSubscription.HandledMethods, SyntaxFactory.List<SyntaxNode>(), modifiers,
return GetDeclarationsForFieldBackedProperty(basePropertyEventSubscription.HandledMethods, SyntaxFactory.List<AttributeListSyntax>(), modifiers,
prop.Type, prop.Identifier, SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.BaseExpression(), ValidSyntaxFactory.IdentifierName(prop.Identifier)));
}

Expand Down
2 changes: 1 addition & 1 deletion CodeConverter/CSharp/LambdaConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ private async Task<CSharpSyntaxNode> ConvertToFunctionDeclarationOrNullAsync(VBS
// Could do: See if we can improve upon returning "object" for pretty much everything (which is what the symbols say)
// I believe that in general, special VB functions such as MultiplyObject are designed to work the same as integer when given two integers for example.
// If all callers currently pass an integer, perhaps it'd be more idiomatic in C# to specify "int", than to have Operators
var paramsWithTypes = anonFuncOp.Symbol.Parameters.Select(p => CommonConversions.CsSyntaxGenerator.ParameterDeclaration(p));
var paramsWithTypes = anonFuncOp.Symbol.Parameters.Select(p => (ParameterSyntax) CommonConversions.CsSyntaxGenerator.ParameterDeclaration(p));

var paramListWithTypes = param.WithParameters(SyntaxFactory.SeparatedList(paramsWithTypes));
if (potentialAncestorDeclarationOperation is IFieldInitializerOperation fieldInit) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ public override async Task<SyntaxList<StatementSyntax>> VisitForBlock(VBSyntax.F
}


var preLoopStatements = new List<SyntaxNode>();
var preLoopStatements = new List<StatementSyntax>();
var csToValue = await stmt.ToValue.AcceptAsync<ExpressionSyntax>(_expressionVisitor);
csToValue = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(stmt.ToValue, csToValue?.SkipIntoParens(), forceTargetType: controlVarType);

Expand Down
6 changes: 3 additions & 3 deletions CodeConverter/CSharp/TypeConversionAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -242,17 +242,17 @@ private CSSyntax.NameSyntax GetCommonDelegateTypeOrNull(VBSyntax.ExpressionSynta
private CSSyntax.NameSyntax CreateCommonDelegateTypeSyntax(IMethodSymbol vbLambda)
{
var parameters = vbLambda.Parameters
.Select(p => _csSyntaxGenerator.TypeExpression(p.Type));
.Select(p => (TypeSyntax) _csSyntaxGenerator.TypeExpression(p.Type));

if (vbLambda.ReturnType.IsSystemVoid()) {
return CreateType("Action", parameters);
}

var typeExpression = _csSyntaxGenerator.TypeExpression(vbLambda.ReturnType);
var typeExpression = (TypeSyntax) _csSyntaxGenerator.TypeExpression(vbLambda.ReturnType);
return CreateType("Func", parameters.Concat(typeExpression));
}

private static CSSyntax.NameSyntax CreateType(string baseTypeName, IEnumerable<SyntaxNode> parameters)
private static CSSyntax.NameSyntax CreateType(string baseTypeName, IEnumerable<TypeSyntax> parameters)
{
var parameterList = SyntaxFactory.TypeArgumentList(SyntaxFactory.SeparatedList(parameters));
if (!parameterList.Arguments.Any()) return ValidSyntaxFactory.IdentifierName(baseTypeName);
Expand Down
2 changes: 1 addition & 1 deletion CodeConverter/CSharp/VBToCSProjectContentsConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public VBToCSProjectContentsConverter(ConversionOptions conversionOptions,

public async Task InitializeSourceAsync(Project project)
{
project = await ClashingMemberRenamer.RenameClashingSymbolsAsync(project);
project = await ClashingMemberRenamer.RenameClashingSymbolsAsync(project, _cancellationToken);
var cSharpCompilationOptions = CSharpCompiler.CreateCompilationOptions();
_convertedCsProject = project.ToProjectFromAnyOptions(cSharpCompilationOptions, CSharpCompiler.ParseOptions);
_csharpReferenceProject = project.CreateReferenceOnlyProjectFromAnyOptions(cSharpCompilationOptions, CSharpCompiler.ParseOptions);
Expand Down
5 changes: 3 additions & 2 deletions CodeConverter/CodeConverter.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.11.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.Workspaces" Version="3.11.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Features" Version="4.1.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.1.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.Workspaces" Version="4.1.0" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0">
<PrivateAssets>all</PrivateAssets>
Expand Down
2 changes: 1 addition & 1 deletion CodeConverter/Common/SymbolRenamer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public static string GetName(ISymbol m) {
return m.Name;
}

public static async Task<Project> PerformRenamesAsync(Project project, IEnumerable<(ISymbol Original, string NewName)> symbolsWithNewNames)
public static async Task<Project> PerformRenamesAsync(Project project, IEnumerable<(ISymbol Original, string NewName)> symbolsWithNewNames, CancellationToken cancellationToken)
{
var solution = project.Solution;
foreach (var (originalSymbol, newName) in symbolsWithNewNames.OrderByDescending(s => s.Original.DeclaringSyntaxReferences.Select(x => x.Span.End).Max())) {
Expand Down
2 changes: 1 addition & 1 deletion CodeConverter/VB/CSToVBProjectContentsConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public CSToVBProjectContentsConverter(ConversionOptions conversionOptions, IProg
public async Task InitializeSourceAsync(Project project)
{
// TODO: Don't throw away solution-wide effects - write them to referencing files, and use in conversion of any other projects being converted at the same time.
project = await ClashingMemberRenamer.RenameClashingSymbolsAsync(project);
project = await ClashingMemberRenamer.RenameClashingSymbolsAsync(project, _cancellationToken);
_convertedVbProject = project.ToProjectFromAnyOptions(_vbCompilationOptions, _vbParseOptions);
_vbReferenceProject = project.CreateReferenceOnlyProjectFromAnyOptions(_vbCompilationOptions, _vbParseOptions);
_vbViewOfCsSymbols = (VisualBasicCompilation)await _vbReferenceProject.GetCompilationAsync(_cancellationToken);
Expand Down
6 changes: 3 additions & 3 deletions CodeConverter/VB/ClashingMemberRenamer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ internal static class ClashingMemberRenamer
/// Cases in different named scopes should be dealt with by <seealso cref="DocumentExtensions.ExpandAsync"/>.
/// For names scoped within a type member, see <seealso cref="SemanticModelSymbolSetExtensions.GetCsLocalSymbolsPerScope"/>.
/// </remarks>
public static async Task<Project> RenameClashingSymbolsAsync(Project project)
public static async Task<Project> RenameClashingSymbolsAsync(Project project, CancellationToken cancellationToken)
{
var compilation = await project.GetCompilationAsync();
var compilation = await project.GetCompilationAsync(cancellationToken);
var memberRenames = SymbolRenamer.GetNamespacesAndTypesInAssembly(project, compilation)
.SelectMany(x => GetSymbolsWithNewNames(x, compilation));
return await SymbolRenamer.PerformRenamesAsync(project, memberRenames.ToList());
return await SymbolRenamer.PerformRenamesAsync(project, memberRenames.ToList(), cancellationToken);
}

private static IEnumerable<(ISymbol Original, string NewName)> GetSymbolsWithNewNames(INamespaceOrTypeSymbol containerSymbol, Compilation compilation)
Expand Down
8 changes: 6 additions & 2 deletions CodeConverter/VB/NodesVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,11 @@ public override VisualBasicSyntaxNode VisitAttributeArgument(CSSyntax.AttributeA
}
#endregion

public override VisualBasicSyntaxNode VisitNamespaceDeclaration(CSSyntax.NamespaceDeclarationSyntax node)
public override VisualBasicSyntaxNode VisitFileScopedNamespaceDeclaration(FileScopedNamespaceDeclarationSyntax node) => ConvertNamespaceDeclaration(node);

public override VisualBasicSyntaxNode VisitNamespaceDeclaration(CSSyntax.NamespaceDeclarationSyntax node) => ConvertNamespaceDeclaration(node);

private VisualBasicSyntaxNode ConvertNamespaceDeclaration(BaseNamespaceDeclarationSyntax node)
{
foreach (var @using in node.Usings)
_importsToConvert.AddRange(node.Usings);
Expand Down Expand Up @@ -653,7 +657,7 @@ public override VisualBasicSyntaxNode VisitEventDeclaration(CSSyntax.EventDeclar
);
} else {
if ((int)LanguageVersion < 14) {
var conditionalStatement = _vbSyntaxGenerator.IfStatement(
var conditionalStatement = (StatementSyntax) _vbSyntaxGenerator.IfStatement(
_vbSyntaxGenerator.ReferenceNotEqualsExpression(eventFieldIdentifier,
_vbSyntaxGenerator.NullLiteralExpression()),
SyntaxFactory.InvocationExpression(
Expand Down
10 changes: 5 additions & 5 deletions CommandLine/CodeConv.NetFramework/CodeConv.NetFramework.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="5.0.0" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
<PackageReference Include="Microsoft.Build.Locator" Version="1.2.6" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.11.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.Workspaces" Version="3.11.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="3.11.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.1.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.Workspaces" Version="4.1.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.1.0" />
<PackageReference Include="Microsoft.VisualStudio.Threading" Version="16.10.56" />
<PackageReference Include="NuGet.Build.Tasks" Version="5.4.0" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.7.0" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.6" />
<PackageReference Include="System.Memory" Version="4.5.5" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
Expand Down
2 changes: 1 addition & 1 deletion CommandLine/CodeConv/CodeConv.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="5.0.0" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="7.0.0" />
<PackageReference Include="Microsoft.Build.Locator" Version="1.4.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.1.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.Workspaces" Version="4.1.0" />
Expand Down
12 changes: 6 additions & 6 deletions Func/Func.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@
<PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="1.2.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />

<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="6.0.0" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="7.0.0" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.6" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.2.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.2.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="4.2.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.Workspaces" Version="4.2.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.2.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.1.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.1.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="4.1.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.Workspaces" Version="4.1.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.1.0" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Convert code from VB.NET to C# (and vice versa) using Roslyn - all free and open
* [Visual Studio extension](https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.CodeConverter)
* To install close VS and double-click the downloadeded .vsix file
* [Online snippet converter](https://icsharpcode.github.io/CodeConverter/)
* Command line `dotnet tool install ICSharpCode.CodeConverter.codeconv --global` (still requires VS2019+ installed)
* Command line `dotnet tool install ICSharpCode.CodeConverter.codeconv --global` (still requires VS2022 17.1+ installed)
* [Nuget library](https://www.nuget.org/packages/ICSharpCode.CodeConverter/) (this underpins all other free converters you'll find online)

See [wiki](https://github.com/icsharpcode/CodeConverter/wiki) for advice on getting the best results, or the [changelog](https://github.com/icsharpcode/CodeConverter/blob/master/CHANGELOG.md) for recent improvements.
Expand All @@ -15,7 +15,7 @@ See [wiki](https://github.com/icsharpcode/CodeConverter/wiki) for advice on gett

Adds context menu items to convert projects/files between VB.NET and C#. See the [wiki documentation](https://github.com/icsharpcode/CodeConverter/wiki) for advice / help using it.

Download from [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.CodeConverter) (Use VS 2019+)
Download from [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.CodeConverter) (Use VS 2022 17.1+)

* Flexible: Convert a small selection, or a whole solution in one go, in either direction.
* Accurate: Full project context (through Roslyn) is used to get the most accurate conversion.
Expand Down
38 changes: 20 additions & 18 deletions Tests/CSharp/ExpressionTests/XmlExpressionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,22 +116,22 @@ private void TestMethod()
{
var catalog = new XDocument(
new XElement(""Catalog"",
new XElement(""Book"", new XAttribute(""id"", ""bk101""),
new XElement(""Author"", ""Garghentini, Davide""),
new XElement(""Title"", ""XML Developer's Guide""),
new XElement(""Price"", ""44.95""),
new XElement(""Description"", @""
new XElement(""Book"", new XAttribute(""id"", ""bk101""),
new XElement(""Author"", ""Garghentini, Davide""),
new XElement(""Title"", ""XML Developer's Guide""),
new XElement(""Price"", ""44.95""),
new XElement(""Description"", @""
An in-depth look at creating applications
with "", new XElement(""technology"", ""XML""), @"". For
"", new XElement(""audience"", ""beginners""), @"" or
"", new XElement(""audience"", ""advanced""), @"" developers.
"")
),
new XElement(""Book"", new XAttribute(""id"", ""bk331""),
new XElement(""Author"", ""Spencer, Phil""),
new XElement(""Title"", ""Developing Applications with Visual Basic .NET""),
new XElement(""Price"", ""45.95""),
new XElement(""Description"", @""
),
new XElement(""Book"", new XAttribute(""id"", ""bk331""),
new XElement(""Author"", ""Spencer, Phil""),
new XElement(""Title"", ""Developing Applications with Visual Basic .NET""),
new XElement(""Price"", ""45.95""),
new XElement(""Description"", @""
Get the expert insights, practical code samples,
and best practices you need
to advance your expertise with "", new XElement(""technology"", @""Visual
Expand All @@ -140,21 +140,23 @@ and best practices you need
based on professional,
pragmatic guidance by today's top "", new XElement(""audience"", ""developers""), @"".
"")
)
)
)

);
var htmlOutput = new XElement(""html"",

new XElement(""body"", from book in catalog.Elements(""Catalog"").Elements(""Book"")
select new XElement(""div"",
new XElement(""h1"", book.Elements(""Title"").Value),
new XElement(""h3"", ""By "" + book.Elements(""Author"").Value),
new XElement(""h3"", ""Price = "" + book.Elements(""Price"").Value),
new XElement(""h1"", book.Elements(""Title"").Value),
new XElement(""h3"", ""By "" + book.Elements(""Author"").Value),
new XElement(""h3"", ""Price = "" + book.Elements(""Price"").Value),


new XElement(""h2"", ""Description""), TransformDescription((string)book.Elements(""Description"").ElementAtOrDefault(0)), new XElement(""hr"")
)
)
);
)
)
);
}

public string TransformDescription(string s)
Expand Down
8 changes: 4 additions & 4 deletions Tests/Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@
<ProjectReference Include="..\CommandLine\CodeConv.NetFramework\CodeConv.NetFramework.csproj" />
</ItemGroup>
<ItemGroup Label="ReSharper test runner requirements - test against latest Visual Studio version">
<PackageReference Include="Microsoft.CodeAnalysis.Features" Version="4.2.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.2.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.2.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.Workspaces" Version="4.2.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Features" Version="4.1.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.1.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.1.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.Workspaces" Version="4.1.0" />
<PackageReference Include="Microsoft.Build" Version="17.4.0" />
<PackageReference Include="Microsoft.Build.Tasks.Core" Version="17.4.0" />
</ItemGroup>
Expand Down
15 changes: 15 additions & 0 deletions Tests/VB/NamespaceLevelTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,21 @@ End Class
End Namespace");
}

[Fact]
public async Task TestClassWithNamespaceStatementAsync()
{
await TestConversionCSharpToVisualBasicAsync(@"namespace Test.@class;

class TestClass<T>
{
}
", @"Namespace Test.class

Friend Class TestClass(Of T)
End Class
End Namespace");
}

[Fact]
public async Task TestInternalStaticClassAsync()
{
Expand Down
Loading
Loading