diff --git a/CHANGELOG.md b/CHANGELOG.md index a1ad1859b..c836d1acd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/CodeConverter/CSharp/ClashingMemberRenamer.cs b/CodeConverter/CSharp/ClashingMemberRenamer.cs index 586701416..dbd7544b8 100644 --- a/CodeConverter/CSharp/ClashingMemberRenamer.cs +++ b/CodeConverter/CSharp/ClashingMemberRenamer.cs @@ -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 /// - public static async Task RenameClashingSymbolsAsync(Project project) + public static async Task 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) diff --git a/CodeConverter/CSharp/HandledEventsAnalysis.cs b/CodeConverter/CSharp/HandledEventsAnalysis.cs index 854176c93..8493d74da 100644 --- a/CodeConverter/CSharp/HandledEventsAnalysis.cs +++ b/CodeConverter/CSharp/HandledEventsAnalysis.cs @@ -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(), modifiers, + return GetDeclarationsForFieldBackedProperty(basePropertyEventSubscription.HandledMethods, SyntaxFactory.List(), modifiers, prop.Type, prop.Identifier, SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.BaseExpression(), ValidSyntaxFactory.IdentifierName(prop.Identifier))); } diff --git a/CodeConverter/CSharp/LambdaConverter.cs b/CodeConverter/CSharp/LambdaConverter.cs index 6fee48063..ad81097c1 100644 --- a/CodeConverter/CSharp/LambdaConverter.cs +++ b/CodeConverter/CSharp/LambdaConverter.cs @@ -67,7 +67,7 @@ private async Task 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) { diff --git a/CodeConverter/CSharp/MethodBodyExecutableStatementVisitor.cs b/CodeConverter/CSharp/MethodBodyExecutableStatementVisitor.cs index 79adfdc80..a88510c74 100644 --- a/CodeConverter/CSharp/MethodBodyExecutableStatementVisitor.cs +++ b/CodeConverter/CSharp/MethodBodyExecutableStatementVisitor.cs @@ -611,7 +611,7 @@ public override async Task> VisitForBlock(VBSyntax.F } - var preLoopStatements = new List(); + var preLoopStatements = new List(); var csToValue = await stmt.ToValue.AcceptAsync(_expressionVisitor); csToValue = CommonConversions.TypeConversionAnalyzer.AddExplicitConversion(stmt.ToValue, csToValue?.SkipIntoParens(), forceTargetType: controlVarType); diff --git a/CodeConverter/CSharp/TypeConversionAnalyzer.cs b/CodeConverter/CSharp/TypeConversionAnalyzer.cs index 38c360b09..a354e2748 100644 --- a/CodeConverter/CSharp/TypeConversionAnalyzer.cs +++ b/CodeConverter/CSharp/TypeConversionAnalyzer.cs @@ -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 parameters) + private static CSSyntax.NameSyntax CreateType(string baseTypeName, IEnumerable parameters) { var parameterList = SyntaxFactory.TypeArgumentList(SyntaxFactory.SeparatedList(parameters)); if (!parameterList.Arguments.Any()) return ValidSyntaxFactory.IdentifierName(baseTypeName); diff --git a/CodeConverter/CSharp/VBToCSProjectContentsConverter.cs b/CodeConverter/CSharp/VBToCSProjectContentsConverter.cs index 595f5ecd0..d6fd1126c 100644 --- a/CodeConverter/CSharp/VBToCSProjectContentsConverter.cs +++ b/CodeConverter/CSharp/VBToCSProjectContentsConverter.cs @@ -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); diff --git a/CodeConverter/CodeConverter.csproj b/CodeConverter/CodeConverter.csproj index 8a4f82b13..80642c84b 100644 --- a/CodeConverter/CodeConverter.csproj +++ b/CodeConverter/CodeConverter.csproj @@ -36,8 +36,9 @@ - - + + + all diff --git a/CodeConverter/Common/SymbolRenamer.cs b/CodeConverter/Common/SymbolRenamer.cs index e81531d76..5ee789494 100644 --- a/CodeConverter/Common/SymbolRenamer.cs +++ b/CodeConverter/Common/SymbolRenamer.cs @@ -26,7 +26,7 @@ public static string GetName(ISymbol m) { return m.Name; } - public static async Task PerformRenamesAsync(Project project, IEnumerable<(ISymbol Original, string NewName)> symbolsWithNewNames) + public static async Task 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())) { diff --git a/CodeConverter/VB/CSToVBProjectContentsConverter.cs b/CodeConverter/VB/CSToVBProjectContentsConverter.cs index 571443206..cd8fda793 100644 --- a/CodeConverter/VB/CSToVBProjectContentsConverter.cs +++ b/CodeConverter/VB/CSToVBProjectContentsConverter.cs @@ -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); diff --git a/CodeConverter/VB/ClashingMemberRenamer.cs b/CodeConverter/VB/ClashingMemberRenamer.cs index 00962cc9e..2648a5875 100644 --- a/CodeConverter/VB/ClashingMemberRenamer.cs +++ b/CodeConverter/VB/ClashingMemberRenamer.cs @@ -10,12 +10,12 @@ internal static class ClashingMemberRenamer /// Cases in different named scopes should be dealt with by . /// For names scoped within a type member, see . /// - public static async Task RenameClashingSymbolsAsync(Project project) + public static async Task 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) diff --git a/CodeConverter/VB/NodesVisitor.cs b/CodeConverter/VB/NodesVisitor.cs index 9c78f384b..48911590e 100644 --- a/CodeConverter/VB/NodesVisitor.cs +++ b/CodeConverter/VB/NodesVisitor.cs @@ -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); @@ -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( diff --git a/CommandLine/CodeConv.NetFramework/CodeConv.NetFramework.csproj b/CommandLine/CodeConv.NetFramework/CodeConv.NetFramework.csproj index c5ec4d625..9f1735fa6 100644 --- a/CommandLine/CodeConv.NetFramework/CodeConv.NetFramework.csproj +++ b/CommandLine/CodeConv.NetFramework/CodeConv.NetFramework.csproj @@ -10,14 +10,14 @@ - + - - - + + + - + diff --git a/CommandLine/CodeConv/CodeConv.csproj b/CommandLine/CodeConv/CodeConv.csproj index 05197601e..83443a382 100644 --- a/CommandLine/CodeConv/CodeConv.csproj +++ b/CommandLine/CodeConv/CodeConv.csproj @@ -31,7 +31,7 @@ - + diff --git a/Func/Func.csproj b/Func/Func.csproj index 1dbc5fbcf..1efbf0c58 100644 --- a/Func/Func.csproj +++ b/Func/Func.csproj @@ -29,13 +29,13 @@ - + - - - - - + + + + + diff --git a/README.md b/README.md index f06a1a492..a7a7ae725 100644 --- a/README.md +++ b/README.md @@ -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. @@ -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. diff --git a/Tests/CSharp/ExpressionTests/XmlExpressionTests.cs b/Tests/CSharp/ExpressionTests/XmlExpressionTests.cs index d059ca7cf..aa064b419 100644 --- a/Tests/CSharp/ExpressionTests/XmlExpressionTests.cs +++ b/Tests/CSharp/ExpressionTests/XmlExpressionTests.cs @@ -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 @@ -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) diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 647e04d44..01aef701e 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -36,10 +36,10 @@ - - - - + + + + diff --git a/Tests/VB/NamespaceLevelTests.cs b/Tests/VB/NamespaceLevelTests.cs index 3d1f08241..3b8c09c25 100644 --- a/Tests/VB/NamespaceLevelTests.cs +++ b/Tests/VB/NamespaceLevelTests.cs @@ -66,6 +66,21 @@ End Class End Namespace"); } + [Fact] + public async Task TestClassWithNamespaceStatementAsync() + { + await TestConversionCSharpToVisualBasicAsync(@"namespace Test.@class; + +class TestClass +{ +} +", @"Namespace Test.class + + Friend Class TestClass(Of T) + End Class +End Namespace"); + } + [Fact] public async Task TestInternalStaticClassAsync() { diff --git a/Vsix/Vsix.csproj b/Vsix/Vsix.csproj index 8e74018bf..bad7ddc59 100644 --- a/Vsix/Vsix.csproj +++ b/Vsix/Vsix.csproj @@ -51,7 +51,7 @@ - + compile; build; native; contentfiles; analyzers; buildtransitive diff --git a/Vsix/source.extension.vsixmanifest b/Vsix/source.extension.vsixmanifest index 34331cf18..7fedb2238 100644 --- a/Vsix/source.extension.vsixmanifest +++ b/Vsix/source.extension.vsixmanifest @@ -13,20 +13,13 @@ code converter vb csharp visual basic csharp net translate - - x86 - - + amd64 - + arm64 - - - - diff --git a/Web/Web.csproj b/Web/Web.csproj index dc3a93a91..428c8acfb 100644 --- a/Web/Web.csproj +++ b/Web/Web.csproj @@ -20,7 +20,6 @@ -