From 280e8d9923f0db732aade9d30f53af69e5c23358 Mon Sep 17 00:00:00 2001 From: GrahamTheCoder Date: Tue, 5 Feb 2019 21:24:27 +0000 Subject: [PATCH] Do all the same mappings that vb -> c# does - fixes #240 --- CHANGELOG.md | 1 + ICSharpCode.CodeConverter/VB/NodesVisitor.cs | 39 ++++- Tests/VB/MemberTests.cs | 146 +++++++++++++++++++ 3 files changed, 183 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14c108767..8ede7192a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to the code converter will be documented here. ### C# -> VB * Tuples now converted +* All known operator overloads now converted # 6.3.0 05/02/2019 * VS 2019 support diff --git a/ICSharpCode.CodeConverter/VB/NodesVisitor.cs b/ICSharpCode.CodeConverter/VB/NodesVisitor.cs index 3e12a9d50..47b6b1694 100644 --- a/ICSharpCode.CodeConverter/VB/NodesVisitor.cs +++ b/ICSharpCode.CodeConverter/VB/NodesVisitor.cs @@ -602,24 +602,57 @@ public override VisualBasicSyntaxNode VisitOperatorDeclaration(CSS.OperatorDecla ConvertAndSplitAttributes(node.AttributeLists, out var attributes, out var returnAttributes); var body = _commonConversions.ConvertBody(node.Body, node.ExpressionBody); var parameterList = (ParameterListSyntax)node.ParameterList?.Accept(TriviaConvertingVisitor); + var firstParam = node.ParameterList?.Parameters.FirstOrDefault() + ?? throw new NotSupportedException("Operator overloads with no parameters aren't supported"); + var firstParameterIsString = _semanticModel.GetTypeInfo(firstParam.Type).ConvertedType.SpecialType == SpecialType.System_String; var stmt = SyntaxFactory.OperatorStatement( attributes, CommonConversions.ConvertModifiers(node.Modifiers, GetMemberContext(node)), - SyntaxFactory.Token(ConvertOperatorDeclarationToken(CS.CSharpExtensions.Kind(node.OperatorToken))), + SyntaxFactory.Token(ConvertOperatorDeclarationToken(CS.CSharpExtensions.Kind(node.OperatorToken), firstParameterIsString)), parameterList, SyntaxFactory.SimpleAsClause(returnAttributes, (TypeSyntax)node.ReturnType.Accept(TriviaConvertingVisitor)) ); return SyntaxFactory.OperatorBlock(stmt, body); } - SyntaxKind ConvertOperatorDeclarationToken(CS.SyntaxKind syntaxKind) + + + SyntaxKind ConvertOperatorDeclarationToken(CS.SyntaxKind syntaxKind, bool firstParameterIsString) { switch (syntaxKind) { + case CS.SyntaxKind.PlusToken: + return firstParameterIsString ? SyntaxKind.AmpersandToken : SyntaxKind.PlusToken; + case CS.SyntaxKind.MinusToken: + return SyntaxKind.MinusToken; + case CS.SyntaxKind.ExclamationToken: + return SyntaxKind.NotKeyword; + case CS.SyntaxKind.AsteriskToken: + return SyntaxKind.AsteriskToken; + case CS.SyntaxKind.SlashToken: + return SyntaxKind.SlashToken; + case CS.SyntaxKind.PercentToken: + return SyntaxKind.ModKeyword; + case CS.SyntaxKind.LessThanLessThanToken: + return SyntaxKind.LessThanLessThanToken; + case CS.SyntaxKind.GreaterThanGreaterThanToken: + return SyntaxKind.GreaterThanGreaterThanToken; case CS.SyntaxKind.EqualsEqualsToken: return SyntaxKind.EqualsToken; case CS.SyntaxKind.ExclamationEqualsToken: return SyntaxKind.LessThanGreaterThanToken; + case CS.SyntaxKind.GreaterThanToken: + return SyntaxKind.GreaterThanToken; + case CS.SyntaxKind.LessThanToken: + return SyntaxKind.LessThanToken; + case CS.SyntaxKind.GreaterThanEqualsToken: + return SyntaxKind.GreaterThanEqualsToken; + case CS.SyntaxKind.LessThanEqualsToken: + return SyntaxKind.LessThanEqualsToken; + case CS.SyntaxKind.AmpersandToken: + return SyntaxKind.AndKeyword; + case CS.SyntaxKind.BarToken: + return SyntaxKind.OrKeyword; } - throw new NotSupportedException(); + throw new NotSupportedException($"{nameof(syntaxKind)} of {syntaxKind} cannot be converted"); } public override VisualBasicSyntaxNode VisitConversionOperatorDeclaration(CSS.ConversionOperatorDeclarationSyntax node) diff --git a/Tests/VB/MemberTests.cs b/Tests/VB/MemberTests.cs index 8e2c56ad9..876637e58 100644 --- a/Tests/VB/MemberTests.cs +++ b/Tests/VB/MemberTests.cs @@ -138,6 +138,152 @@ End Sub End Class"); } + + [Fact] + public void OperatorOverloads() + { + // Note a couple map to the same thing in C# so occasionally the result won't compile. The user can manually decide what to do in such scenarios. + TestConversionCSharpToVisualBasic(@"public class AcmeClass +{ + public static AcmeClass operator +(int i, AcmeClass ac) + { + return ac; + } + public static AcmeClass operator +(string s, AcmeClass ac) + { + return ac; + } + public static AcmeClass operator -(int i, AcmeClass ac) + { + return ac; + } + public static AcmeClass operator !(AcmeClass ac) + { + return ac; + } + public static AcmeClass operator *(int i, AcmeClass ac) + { + return ac; + } + public static AcmeClass operator /(int i, AcmeClass ac) + { + return ac; + } + public static AcmeClass operator %(string s, AcmeClass ac) + { + return ac; + } + public static AcmeClass operator <<(AcmeClass ac, int i) + { + return ac; + } + public static AcmeClass operator >>(AcmeClass ac, int i) + { + return ac; + } + public static AcmeClass operator ==(string s, AcmeClass ac) + { + return ac; + } + public static AcmeClass operator !=(string s, AcmeClass ac) + { + return ac; + } + public static AcmeClass operator <(string s, AcmeClass ac) + { + return ac; + } + public static AcmeClass operator >(string s, AcmeClass ac) + { + return ac; + } + public static AcmeClass operator <=(string s, AcmeClass ac) + { + return ac; + } + public static AcmeClass operator >=(string s, AcmeClass ac) + { + return ac; + } + public static AcmeClass operator &(string s, AcmeClass ac) + { + return ac; + } + public static AcmeClass operator |(string s, AcmeClass ac) + { + return ac; + } +}", @"Public Class AcmeClass + Public Shared Operator +(ByVal i As Integer, ByVal ac As AcmeClass) As AcmeClass + Return ac + End Operator + + Public Shared Operator &(ByVal s As String, ByVal ac As AcmeClass) As AcmeClass + Return ac + End Operator + + Public Shared Operator -(ByVal i As Integer, ByVal ac As AcmeClass) As AcmeClass + Return ac + End Operator + + Public Shared Operator Not(ByVal ac As AcmeClass) As AcmeClass + Return ac + End Operator + + Public Shared Operator *(ByVal i As Integer, ByVal ac As AcmeClass) As AcmeClass + Return ac + End Operator + + Public Shared Operator /(ByVal i As Integer, ByVal ac As AcmeClass) As AcmeClass + Return ac + End Operator + + Public Shared Operator Mod(ByVal s As String, ByVal ac As AcmeClass) As AcmeClass + Return ac + End Operator + + Public Shared Operator <<(ByVal ac As AcmeClass, ByVal i As Integer) As AcmeClass + Return ac + End Operator + + Public Shared Operator >>(ByVal ac As AcmeClass, ByVal i As Integer) As AcmeClass + Return ac + End Operator + + Public Shared Operator =(ByVal s As String, ByVal ac As AcmeClass) As AcmeClass + Return ac + End Operator + + Public Shared Operator <>(ByVal s As String, ByVal ac As AcmeClass) As AcmeClass + Return ac + End Operator + + Public Shared Operator <(ByVal s As String, ByVal ac As AcmeClass) As AcmeClass + Return ac + End Operator + + Public Shared Operator >(ByVal s As String, ByVal ac As AcmeClass) As AcmeClass + Return ac + End Operator + + Public Shared Operator <=(ByVal s As String, ByVal ac As AcmeClass) As AcmeClass + Return ac + End Operator + + Public Shared Operator >=(ByVal s As String, ByVal ac As AcmeClass) As AcmeClass + Return ac + End Operator + + Public Shared Operator And(ByVal s As String, ByVal ac As AcmeClass) As AcmeClass + Return ac + End Operator + + Public Shared Operator Or(ByVal s As String, ByVal ac As AcmeClass) As AcmeClass + Return ac + End Operator +End Class"); + } + [Fact] public void TestSealedMethod() {