From d00c755c03af9a3a0529007491ada0eb4dac5149 Mon Sep 17 00:00:00 2001 From: GrahamTheCoder Date: Wed, 14 Dec 2022 10:59:11 +0000 Subject: [PATCH 1/3] Remove converter error from #965 (still creates compile error) - closes #965 --- .../VB/CSToVBProjectContentsConverter.cs | 3 +- CodeConverter/VB/CSharpConverter.cs | 4 +-- CodeConverter/VB/CommonConversions.cs | 4 ++- .../MethodBodyExecutableStatementVisitor.cs | 5 ++- CodeConverter/VB/NodesVisitor.cs | 24 ++++++++++++-- Tests/VB/SpecialConversionTests.cs | 32 +++++++++++++++++++ 6 files changed, 64 insertions(+), 8 deletions(-) diff --git a/CodeConverter/VB/CSToVBProjectContentsConverter.cs b/CodeConverter/VB/CSToVBProjectContentsConverter.cs index b1eb4b298..571443206 100644 --- a/CodeConverter/VB/CSToVBProjectContentsConverter.cs +++ b/CodeConverter/VB/CSToVBProjectContentsConverter.cs @@ -54,7 +54,8 @@ public async Task InitializeSourceAsync(Project project) public async Task SingleFirstPassAsync(Document document) { - return await CSharpConverter.ConvertCompilationTreeAsync(document, _vbViewOfCsSymbols, _vbReferenceProject, OptionalOperations, _cancellationToken); + bool outputWillBeOverflowChecked = false; //Future: If it's a project conversion, set RemoveIntegerChecks (default true) to match CSharp's compilation option of CheckOverflow (default false) + return await CSharpConverter.ConvertCompilationTreeAsync(document, _vbViewOfCsSymbols, _vbReferenceProject, OptionalOperations, outputWillBeOverflowChecked, _cancellationToken); } public async Task<(Project project, List> firstPassDocIds)> diff --git a/CodeConverter/VB/CSharpConverter.cs b/CodeConverter/VB/CSharpConverter.cs index ac9e6c54c..9f21f97a7 100644 --- a/CodeConverter/VB/CSharpConverter.cs +++ b/CodeConverter/VB/CSharpConverter.cs @@ -6,7 +6,7 @@ namespace ICSharpCode.CodeConverter.VB; internal static class CSharpConverter { public static async Task ConvertCompilationTreeAsync(Document document, - VisualBasicCompilation vbViewOfCsSymbols, Project vbReferenceProject, OptionalOperations optionalOperations, CancellationToken cancellationToken) + VisualBasicCompilation vbViewOfCsSymbols, Project vbReferenceProject, OptionalOperations optionalOperations, bool outputWillBeOverflowChecked, CancellationToken cancellationToken) { document = await document.WithExpandedRootAsync(cancellationToken); var compilation = await document.Project.GetCompilationAsync(cancellationToken); @@ -18,7 +18,7 @@ public static async Task ConvertCompilationTreeAsync(Document docume var vbSyntaxGenerator = SyntaxGenerator.GetGenerator(vbReferenceProject); _ = tree.GetLineSpan(root.FullSpan, cancellationToken).EndLinePosition.Line; - var visualBasicSyntaxVisitor = new NodesVisitor((CS.CSharpCompilation)compilation, semanticModel, vbViewOfCsSymbols, vbSyntaxGenerator); + var visualBasicSyntaxVisitor = new NodesVisitor((CS.CSharpCompilation)compilation, semanticModel, vbViewOfCsSymbols, vbSyntaxGenerator, outputWillBeOverflowChecked); var converted = (VBSyntax.CompilationUnitSyntax)root.Accept(visualBasicSyntaxVisitor.TriviaConvertingVisitor); return optionalOperations.MapSourceTriviaToTargetHandled(root, converted, document); diff --git a/CodeConverter/VB/CommonConversions.cs b/CodeConverter/VB/CommonConversions.cs index 2972946b0..ff0ee7eb2 100644 --- a/CodeConverter/VB/CommonConversions.cs +++ b/CodeConverter/VB/CommonConversions.cs @@ -29,13 +29,15 @@ namespace ICSharpCode.CodeConverter.VB; internal class CommonConversions { public SyntaxGenerator VbSyntaxGenerator { get; } + public bool OutputWillBeOverflowChecked { get; } private readonly CommentConvertingVisitorWrapper _nodesVisitor; private readonly SemanticModel _semanticModel; public CommonConversions(SemanticModel semanticModel, SyntaxGenerator vbSyntaxGenerator, - CommentConvertingVisitorWrapper nodesVisitor) + CommentConvertingVisitorWrapper nodesVisitor, bool outputWillBeOverflowChecked) { VbSyntaxGenerator = vbSyntaxGenerator; + OutputWillBeOverflowChecked = outputWillBeOverflowChecked; _semanticModel = semanticModel; _nodesVisitor = nodesVisitor; } diff --git a/CodeConverter/VB/MethodBodyExecutableStatementVisitor.cs b/CodeConverter/VB/MethodBodyExecutableStatementVisitor.cs index ea13eef5b..58c9cabd1 100644 --- a/CodeConverter/VB/MethodBodyExecutableStatementVisitor.cs +++ b/CodeConverter/VB/MethodBodyExecutableStatementVisitor.cs @@ -671,7 +671,10 @@ public override SyntaxList VisitEmptyStatement(CSSyntax.EmptySt public override SyntaxList VisitCheckedStatement(CSSyntax.CheckedStatementSyntax node) { - return WrapInComment(ConvertBlock(node.Block), "Visual Basic does not support checked statements!"); + var inputWasChecked = node.Keyword.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.CheckedKeyword); + var innerBlock = ConvertBlock(node.Block); + if (_commonConversions.OutputWillBeOverflowChecked == inputWasChecked) return innerBlock; + return WrapInComment(innerBlock, "Visual Basic does not support checked statements!"); } private static SyntaxList WrapInComment(SyntaxList nodes, string comment) diff --git a/CodeConverter/VB/NodesVisitor.cs b/CodeConverter/VB/NodesVisitor.cs index 62a6784f9..e7bb36738 100644 --- a/CodeConverter/VB/NodesVisitor.cs +++ b/CodeConverter/VB/NodesVisitor.cs @@ -1,6 +1,8 @@ -using System.Collections.Immutable; +using System; +using System.Collections.Immutable; using ICSharpCode.CodeConverter.Util.FromRoslyn; using ICSharpCode.CodeConverter.VB.Trivia; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.VisualBasic; using Microsoft.CodeAnalysis.VisualBasic.Syntax; @@ -12,6 +14,9 @@ using ExpressionSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax; using IdentifierNameSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.IdentifierNameSyntax; using InterpolatedStringContentSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.InterpolatedStringContentSyntax; +using InterpolationAlignmentClauseSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.InterpolationAlignmentClauseSyntax; +using InterpolationFormatClauseSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.InterpolationFormatClauseSyntax; +using MemberAccessExpressionSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.MemberAccessExpressionSyntax; using NameSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.NameSyntax; using OrderingSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.OrderingSyntax; using ParameterListSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.ParameterListSyntax; @@ -22,6 +27,7 @@ using SyntaxFactory = Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory; using SyntaxFacts = Microsoft.CodeAnalysis.VisualBasic.SyntaxFacts; using SyntaxKind = Microsoft.CodeAnalysis.VisualBasic.SyntaxKind; +using TupleElementSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.TupleElementSyntax; using TypeArgumentListSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.TypeArgumentListSyntax; using TypeParameterConstraintClauseSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.TypeParameterConstraintClauseSyntax; using TypeParameterListSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.TypeParameterListSyntax; @@ -46,6 +52,7 @@ internal class NodesVisitor : CS.CSharpSyntaxVisitor private readonly HashSet _addedNames = new(); private int _placeholder = 1; + private readonly bool _outputWillBeOverflowChecked; public CommentConvertingVisitorWrapper TriviaConvertingVisitor { get; } public LanguageVersion LanguageVersion { get => _vbViewOfCsSymbols.Options.ParseOptions.LanguageVersion; } @@ -55,14 +62,15 @@ private string GeneratePlaceholder(string v) } public NodesVisitor(CS.CSharpCompilation compilation, SemanticModel semanticModel, - VisualBasicCompilation vbViewOfCsSymbols, SyntaxGenerator vbSyntaxGenerator) + VisualBasicCompilation vbViewOfCsSymbols, SyntaxGenerator vbSyntaxGenerator, bool outputWillBeOverflowChecked) { _compilation = compilation; _semanticModel = semanticModel; _vbViewOfCsSymbols = vbViewOfCsSymbols; _vbSyntaxGenerator = vbSyntaxGenerator; + _outputWillBeOverflowChecked = outputWillBeOverflowChecked; TriviaConvertingVisitor = new CommentConvertingVisitorWrapper(this); - _commonConversions = new CommonConversions(semanticModel, vbSyntaxGenerator, TriviaConvertingVisitor); + _commonConversions = new CommonConversions(semanticModel, vbSyntaxGenerator, TriviaConvertingVisitor, _outputWillBeOverflowChecked); _cSharpHelperMethodDefinition = new CSharpHelperMethodDefinition(); } @@ -891,6 +899,16 @@ public override VisualBasicSyntaxNode VisitInterpolatedStringText(CSSyntax.Inter return SyntaxFactory.InterpolatedStringText(SyntaxFactory.InterpolatedStringTextToken(ConvertUserText(node.TextToken), node.TextToken.ValueText)); } + public override VisualBasicSyntaxNode VisitCheckedExpression(CheckedExpressionSyntax node) + { + var inputWasChecked = node.Keyword.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.CheckedKeyword); + var innerExpression = node.Expression.Accept(TriviaConvertingVisitor); + if (_outputWillBeOverflowChecked == inputWasChecked) return innerExpression; + + return innerExpression.WithAdditionalAnnotations(new SyntaxAnnotation(AnnotationConstants.ConversionErrorAnnotationKind, + $"WARNING: Expression at character {node.FullSpan.Start} contained the {node.Keyword} keyword before conversion")); + } + private static string ConvertUserText(SyntaxToken token) { if (CS.CSharpExtensions.IsVerbatimStringLiteral(token)) return token.Text; diff --git a/Tests/VB/SpecialConversionTests.cs b/Tests/VB/SpecialConversionTests.cs index 47fea1272..0ea3c4553 100644 --- a/Tests/VB/SpecialConversionTests.cs +++ b/Tests/VB/SpecialConversionTests.cs @@ -6,6 +6,38 @@ namespace ICSharpCode.CodeConverter.Tests.VB; public class SpecialConversionTests : ConverterTestBase { + [Fact] + public async Task UncheckedConstantAsync() + { + await TestConversionCSharpToVisualBasicAsync( + @"internal partial class TestClass +{ + private const int GENERIC_READ = unchecked((int)0x80000000); +}", @"Friend Partial Class TestClass + Private Const GENERIC_READ As Integer = &H80000000UI +End Class + +1 target compilation errors: +BC30439: Constant expression not representable in type 'Integer'."); + } + + [Fact] + public async Task CheckedAsync() + { + await TestConversionCSharpToVisualBasicAsync( + @"using System; + +internal partial class TestClass +{ + private int GENERIC_READ = checked((int) Math.Pow(46341, 2)); +}", @"Imports System + +Friend Partial Class TestClass + Private GENERIC_READ As Integer = Math.Pow(46341, 2) +End Class +WARNING: Expression at character 85 contained the checked keyword before conversion"); + } + [Fact] public async Task TestSimpleInlineAssignAsync() { await TestConversionCSharpToVisualBasicAsync( From 0430128c5e90b8504ac74e3752344f2cbf080f7f Mon Sep 17 00:00:00 2001 From: GrahamTheCoder Date: Wed, 4 Jan 2023 17:38:51 +0000 Subject: [PATCH 2/3] Add test for #975 - closes #975 --- Tests/VB/ExpressionTests.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Tests/VB/ExpressionTests.cs b/Tests/VB/ExpressionTests.cs index 85d1a1cd6..acf9d7559 100644 --- a/Tests/VB/ExpressionTests.cs +++ b/Tests/VB/ExpressionTests.cs @@ -6,6 +6,25 @@ namespace ICSharpCode.CodeConverter.Tests.VB; public class ExpressionTests : ConverterTestBase { + [Fact] + public async Task ReturnUncheckedAsync() + { + await TestConversionCSharpToVisualBasicAsync(@"internal static class Hash +{ + internal static int Combine(int newKey, int currentKey) + { + return unchecked((currentKey * (int)0xA5555529) + newKey); + } +}", @"Friend Module Hash + Friend Function Combine(ByVal newKey As Integer, ByVal currentKey As Integer) As Integer + Return currentKey * CInt(&HA5555529UI) + newKey + End Function +End Module + +1 target compilation errors: +BC30439: Constant expression not representable in type 'Integer'."); + } + [Fact] public async Task MultilineStringAsync() { From 47b01d0dfa3110f6ae1b27ed96bae34fae1f6fce Mon Sep 17 00:00:00 2001 From: GrahamTheCoder Date: Wed, 4 Jan 2023 17:41:25 +0000 Subject: [PATCH 3/3] Add to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a5d8b05b..60c534306 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ### C# -> VB +* Return contents of checked/unchecked expressions/statements [#965](https://github.com/icsharpcode/CodeConverter/issues/965) [#975](https://github.com/icsharpcode/CodeConverter/issues/975) ## [9.1.1] - 2022-12-19