From 50ba3b0ef7627e64ea317a7a9fc36758df27b782 Mon Sep 17 00:00:00 2001 From: GrahamTheCoder Date: Sat, 24 Feb 2018 15:56:56 +0000 Subject: [PATCH 1/9] Enable tests that already pass --- Tests/CSharp/StatementTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/CSharp/StatementTests.cs b/Tests/CSharp/StatementTests.cs index 54cadb1ae..018aff7cc 100644 --- a/Tests/CSharp/StatementTests.cs +++ b/Tests/CSharp/StatementTests.cs @@ -554,7 +554,7 @@ private void TestMethod() }"); } - [Fact(Skip = "Not implemented!")] + [Fact()] public void DeclarationStatements() { TestConversionVisualBasicToCSharp( @@ -841,7 +841,7 @@ private void TestMethod() }"); } - [Fact(Skip = "Not implemented!")] + [Fact()] public void LabeledAndForStatement() { TestConversionVisualBasicToCSharp(@"Class GotoTest1 From 49488a5360a6f00777a7bba9946e3c0ec675fb72 Mon Sep 17 00:00:00 2001 From: GrahamTheCoder Date: Sat, 24 Feb 2018 15:59:47 +0000 Subject: [PATCH 2/9] Enable tests that just need formatting changes to pass --- Tests/CSharp/ExpressionTests.cs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/Tests/CSharp/ExpressionTests.cs b/Tests/CSharp/ExpressionTests.cs index c00a27212..190acdf85 100644 --- a/Tests/CSharp/ExpressionTests.cs +++ b/Tests/CSharp/ExpressionTests.cs @@ -273,7 +273,7 @@ private void TestMethod(string str) }"); } - [Fact(Skip = "Not implemented!")] + [Fact()] public void ObjectInitializerExpression() { TestConversionVisualBasicToCSharp(@"Class StudentName @@ -284,8 +284,7 @@ Class TestClass Private Sub TestMethod(ByVal str As String) Dim student2 As StudentName = New StudentName With {.FirstName = ""Craig"", .LastName = ""Playstead""} End Sub -End Class", @" -class StudentName +End Class", @"class StudentName { public string LastName, FirstName; } @@ -294,31 +293,23 @@ class TestClass { private void TestMethod(string str) { - StudentName student2 = new StudentName - { - FirstName = ""Craig"", - LastName = ""Playstead"", - }; + StudentName student2 = new StudentName() { FirstName = ""Craig"", LastName = ""Playstead"" }; } }"); } - [Fact(Skip = "Not implemented!")] + [Fact()] public void ObjectInitializerExpression2() { TestConversionVisualBasicToCSharp(@"Class TestClass Private Sub TestMethod(ByVal str As String) Dim student2 = New With {Key .FirstName = ""Craig"", Key .LastName = ""Playstead""} End Sub -End Class", @" -class TestClass +End Class", @"class TestClass { private void TestMethod(string str) { - var student2 = new { - FirstName = ""Craig"", - LastName = ""Playstead"", - }; + var student2 = new { FirstName = ""Craig"", LastName = ""Playstead"" }; } }"); } From d171e52841d4e5f2b5bdd85f3f382711e423a0ba Mon Sep 17 00:00:00 2001 From: GrahamTheCoder Date: Sat, 24 Feb 2018 17:50:07 +0000 Subject: [PATCH 3/9] Most basic query expression support --- .../CSharp/NodesVisitor.cs | 36 +++++++++++++++++++ Tests/CSharp/ExpressionTests.cs | 15 ++++---- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs b/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs index 443efdd3b..9272744e9 100644 --- a/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs +++ b/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs @@ -1007,6 +1007,42 @@ public override CSharpSyntaxNode VisitCollectionInitializer(VBSyntax.CollectionI : initializer; } + public override CSharpSyntaxNode VisitQueryExpression(VBSyntax.QueryExpressionSyntax node) + { + var vbFromClause = node.Clauses.OfType().Single(); + var fromClauseSyntax = ConvertFromClauseSyntax(vbFromClause); + var vbSelectClause = node.Clauses.OfType().Single(); + var selectClauseSyntax = ConvertSelectClauseSyntax(vbSelectClause); + var vbBodyClauses = node.Clauses.Except(new VBSyntax.QueryClauseSyntax[] {vbFromClause, vbSelectClause }); + var queryClauseSyntaxs = SyntaxFactory.List(vbBodyClauses.Select(ConvertQueryBodyClause)); + var queryBodySyntax = SyntaxFactory.QueryBody(queryClauseSyntaxs, selectClauseSyntax, null); + return SyntaxFactory.QueryExpression(fromClauseSyntax, queryBodySyntax); + } + + private FromClauseSyntax ConvertFromClauseSyntax(VBSyntax.FromClauseSyntax vbFromClause) + { + var collectionRangeVariableSyntax = vbFromClause.Variables.Single(); + var fromClauseSyntax = SyntaxFactory.FromClause( + ConvertIdentifier(collectionRangeVariableSyntax.Identifier.Identifier, semanticModel), + (ExpressionSyntax) collectionRangeVariableSyntax.Expression.Accept(TriviaConvertingVisitor)); + return fromClauseSyntax; + } + + private SelectClauseSyntax ConvertSelectClauseSyntax(VBSyntax.SelectClauseSyntax vbFromClause) + { + var collectionRangeVariableSyntax = vbFromClause.Variables.Single(); + return SyntaxFactory.SelectClause( + (ExpressionSyntax)collectionRangeVariableSyntax.Expression.Accept(TriviaConvertingVisitor) + ); + } + + private QueryClauseSyntax ConvertQueryBodyClause(VBSyntax.QueryClauseSyntax node) + { + return node.TypeSwitch( + (VBSyntax.WhereClauseSyntax ws) => SyntaxFactory.WhereClause((ExpressionSyntax) ws.Condition.Accept(TriviaConvertingVisitor)), + _ => throw new NotImplementedException($"Conversion for query clause with kind '{node.Kind()}' not implemented")); + } + public override CSharpSyntaxNode VisitNamedFieldInitializer(VBSyntax.NamedFieldInitializerSyntax node) { if (node?.Parent?.Parent is VBSyntax.AnonymousObjectCreationExpressionSyntax) { diff --git a/Tests/CSharp/ExpressionTests.cs b/Tests/CSharp/ExpressionTests.cs index 190acdf85..1095fde41 100644 --- a/Tests/CSharp/ExpressionTests.cs +++ b/Tests/CSharp/ExpressionTests.cs @@ -463,7 +463,7 @@ private async void TestMethod() }"); } - [Fact(Skip = "Not implemented!")] + [Fact] public void Linq1() { TestConversionVisualBasicToCSharp(@"Private Shared Sub SimpleQuery() @@ -474,16 +474,15 @@ For Each n In res Console.WriteLine(n) Next End Sub", - @"static void SimpleQuery() + @"private static void SimpleQuery() { - int[] numbers = { 7, 9, 5, 3, 6 }; - + int[] numbers = new[] { 7, 9, 5, 3, 6 };"/*TODO Remove need for new[]*/ + @" var res = from n in numbers - where n > 5 - select n; - + where n > 5 + select n; + foreach (var n in res) - Console.WriteLine(n); + System.Console.WriteLine(n); }"); } From d7b039ac9f2eb0ac16e7db8769efce061ecc1262 Mon Sep 17 00:00:00 2001 From: GrahamTheCoder Date: Sat, 24 Feb 2018 19:09:08 +0000 Subject: [PATCH 4/9] Simple group join works Haven't handled the case of aggregates other than Group (such as Count()) which are allowed in VB - need to figure out the closest equivalent syntax in C# --- .../CSharp/NodesVisitor.cs | 63 ++++++++++++- .../CSharp/VisualBasicConverter.cs | 4 + Tests/CSharp/ExpressionTests.cs | 91 +++++++------------ 3 files changed, 99 insertions(+), 59 deletions(-) diff --git a/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs b/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs index 9272744e9..e6b52cc23 100644 --- a/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs +++ b/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs @@ -1038,11 +1038,70 @@ private SelectClauseSyntax ConvertSelectClauseSyntax(VBSyntax.SelectClauseSyntax private QueryClauseSyntax ConvertQueryBodyClause(VBSyntax.QueryClauseSyntax node) { - return node.TypeSwitch( - (VBSyntax.WhereClauseSyntax ws) => SyntaxFactory.WhereClause((ExpressionSyntax) ws.Condition.Accept(TriviaConvertingVisitor)), + return node.TypeSwitch( + //(VBSyntax.AggregateClauseSyntax ags) => null, + //(VBSyntax.DistinctClauseSyntax ds) => null, + //(VBSyntax.GroupByClauseSyntax gs) => null, + ConvertJoinClause, + ConvertLetClause, + ConvertOrderByClause, + //(VBSyntax.PartitionClauseSyntax ps) => null, // TODO Convert to Skip and Take methods (they don't exist in C#s query syntax) + //(VBSyntax.PartitionWhileClauseSyntax pws) => null, // TODO Convert to SkipWhile and TakeWhile methods (they don't exist in C#s query syntax) + ConvertWhereClause, _ => throw new NotImplementedException($"Conversion for query clause with kind '{node.Kind()}' not implemented")); } + private QueryClauseSyntax ConvertWhereClause(VBSyntax.WhereClauseSyntax ws) + { + return SyntaxFactory.WhereClause((ExpressionSyntax) ws.Condition.Accept(TriviaConvertingVisitor)); + } + + private QueryClauseSyntax ConvertLetClause(VBSyntax.LetClauseSyntax ls) + { + var singleVariable = ls.Variables.Single(); + return SyntaxFactory.LetClause(ConvertIdentifier(singleVariable.NameEquals.Identifier.Identifier, semanticModel), (ExpressionSyntax) singleVariable.Expression.Accept(TriviaConvertingVisitor)); + } + + private QueryClauseSyntax ConvertOrderByClause(VBSyntax.OrderByClauseSyntax os) + { + return SyntaxFactory.OrderByClause(SyntaxFactory.SeparatedList(os.Orderings.Select(o => (OrderingSyntax) o.Accept(TriviaConvertingVisitor)))); + } + + public override CSharpSyntaxNode VisitOrdering(VBSyntax.OrderingSyntax node) + { + return SyntaxFactory.Ordering(SyntaxKind.OrderByClause, + (ExpressionSyntax)node.Expression.Accept(TriviaConvertingVisitor), + ConvertToken(node.AscendingOrDescendingKeyword)); + } + + private QueryClauseSyntax ConvertJoinClause(VBSyntax.JoinClauseSyntax js) + { + var variable = js.JoinedVariables.Single(); + var joinLhs = SingleExpression(js.JoinConditions.Select(c => c.Left.Accept(TriviaConvertingVisitor)) + .Cast().ToList()); + var joinRhs = SingleExpression(js.JoinConditions.Select(c => c.Right.Accept(TriviaConvertingVisitor)) + .Cast().ToList()); + var convertIdentifier = ConvertIdentifier(variable.Identifier.Identifier, semanticModel); + var expressionSyntax = (ExpressionSyntax) variable.Expression.Accept(TriviaConvertingVisitor); + + JoinIntoClauseSyntax joinIntoClauseSyntax = null; + if (js is VBSyntax.GroupJoinClauseSyntax gjs) { + joinIntoClauseSyntax = gjs.AggregationVariables + .Where(a => a.Aggregation is VBSyntax.GroupAggregationSyntax) + .Select(a => SyntaxFactory.JoinIntoClause(ConvertIdentifier(a.NameEquals.Identifier.Identifier, semanticModel))) + .SingleOrDefault(); + } + return SyntaxFactory.JoinClause(null, convertIdentifier, expressionSyntax, joinLhs, joinRhs, joinIntoClauseSyntax); + } + + private ExpressionSyntax SingleExpression(IReadOnlyCollection expressions) + { + if (expressions.Count == 1) return expressions.Single(); + return SyntaxFactory.AnonymousObjectCreationExpression(SyntaxFactory.SeparatedList(expressions.Select((e, i) => + SyntaxFactory.AnonymousObjectMemberDeclarator(SyntaxFactory.NameEquals($"key{i}"), e) + ))); + } + public override CSharpSyntaxNode VisitNamedFieldInitializer(VBSyntax.NamedFieldInitializerSyntax node) { if (node?.Parent?.Parent is VBSyntax.AnonymousObjectCreationExpressionSyntax) { diff --git a/ICSharpCode.CodeConverter/CSharp/VisualBasicConverter.cs b/ICSharpCode.CodeConverter/CSharp/VisualBasicConverter.cs index 615cdf4b5..06b964a5b 100644 --- a/ICSharpCode.CodeConverter/CSharp/VisualBasicConverter.cs +++ b/ICSharpCode.CodeConverter/CSharp/VisualBasicConverter.cs @@ -504,6 +504,10 @@ static SyntaxKind ConvertToken(VBasic.SyntaxKind t, TokenContext context = Token return SyntaxKind.AssemblyKeyword; case VBasic.SyntaxKind.AsyncKeyword: return SyntaxKind.AsyncKeyword; + case VBasic.SyntaxKind.AscendingKeyword: + return SyntaxKind.AscendingKeyword; + case VBasic.SyntaxKind.DescendingKeyword: + return SyntaxKind.DescendingKeyword; } throw new NotSupportedException(t + " not supported!"); } diff --git a/Tests/CSharp/ExpressionTests.cs b/Tests/CSharp/ExpressionTests.cs index 1095fde41..a6192c372 100644 --- a/Tests/CSharp/ExpressionTests.cs +++ b/Tests/CSharp/ExpressionTests.cs @@ -501,22 +501,18 @@ For Each n In g.Numbers Next Next End Sub", - @"public static void Linq40() - { - int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; - - var numberGroups = - from n in numbers - group n by n % 5 into g - select new { Remainder = g.Key, Numbers = g }; - - foreach (var g in numberGroups) - { - Console.WriteLine($""Numbers with a remainder of {g.Remainder} when divided by 5:""); + @"public static void Linq40() + { + int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; + var numberGroups = from n in numbers + group n by n % 5 into g + select new { Remainder = g.Key, Numbers = g }; + + foreach (var g in numberGroups) + { + System.Console.WriteLine($""Numbers with a remainder of {g.Remainder} when divided by 5:""); foreach (var n in g.Numbers) - { - Console.WriteLine(n); - } + System.Console.WriteLine(n); } }"); } @@ -546,31 +542,21 @@ End Sub } class Test { - public void Linq102() - { - string[] categories = new string[]{ - ""Beverages"", - ""Condiments"", - ""Vegetables"", - ""Dairy Products"", - ""Seafood"" }; - - Product[] products = GetProductList(); - - var q = - from c in categories + public void Linq102() + { + string[] categories = new string[] { ""Beverages"", ""Condiments"", ""Vegetables"", ""Dairy Products"", ""Seafood"" }; + Product[] products = GetProductList(); + var q = from c in categories join p in products on c equals p.Category - select new { Category = c, p.ProductName }; - - foreach (var v in q) - { - Console.WriteLine($""{v.ProductName}: {v.Category}""); - } + select new { Category = c, p.ProductName }; + + foreach (var v in q) + Console.WriteLine($""{v.ProductName}: {v.Category}""); } }"); } - [Fact(Skip = "Not implemented!")] + [Fact] public void Linq4() { TestConversionVisualBasicToCSharp(@"Public Sub Linq103() @@ -585,29 +571,20 @@ For Each p In v.Products Console.WriteLine("" "" & p.ProductName) Next Next -End Sub", @"public void Linq103() -{ - string[] categories = new string[]{ - ""Beverages"", - ""Condiments"", - ""Vegetables"", - ""Dairy Products"", - ""Seafood"" }; - - var products = GetProductList(); - - var q = - from c in categories +End Sub", @"public void Linq103() +{ + string[] categories = new string[] { ""Beverages"", ""Condiments"", ""Vegetables"", ""Dairy Products"", ""Seafood"" }; + var products = GetProductList(); + var q = from c in categories join p in products on c equals p.Category into ps - select new { Category = c, Products = ps }; - - foreach (var v in q) - { - Console.WriteLine(v.Category + "":""); - foreach (var p in v.Products) - { - Console.WriteLine("" "" + p.ProductName); - } + select new { Category = c, Products = ps }; + + foreach (var v in q) + { + System.Console.WriteLine(v.Category + "":""); + + foreach (var p in v.Products) + System.Console.WriteLine("" "" + p.ProductName); } }"); } From 0dffc68ef39d417c923b6290f17b1079a3e46226 Mon Sep 17 00:00:00 2001 From: GrahamTheCoder Date: Sat, 24 Feb 2018 19:29:42 +0000 Subject: [PATCH 5/9] Helper method for brevity --- .../CSharp/NodesVisitor.cs | 57 ++++++++++--------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs b/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs index e6b52cc23..09bfd6e43 100644 --- a/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs +++ b/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs @@ -126,7 +126,7 @@ public override CSharpSyntaxNode VisitCompilationUnit(VBSyntax.CompilationUnitSy public override CSharpSyntaxNode VisitSimpleImportsClause(VBSyntax.SimpleImportsClauseSyntax node) { var nameEqualsSyntax = node.Alias == null ? null - : SyntaxFactory.NameEquals(SyntaxFactory.IdentifierName(ConvertIdentifier(node.Alias.Identifier, semanticModel))); + : SyntaxFactory.NameEquals(SyntaxFactory.IdentifierName(ConvertIdentifier(node.Alias.Identifier))); var usingDirective = SyntaxFactory.UsingDirective(nameEqualsSyntax, (NameSyntax)node.Name.Accept(TriviaConvertingVisitor)); return usingDirective; } @@ -169,7 +169,7 @@ public override CSharpSyntaxNode VisitClassBlock(VBSyntax.ClassBlockSyntax node) var classStatement = node.ClassStatement; var attributes = ConvertAttributes(classStatement.AttributeLists); SplitTypeParameters(classStatement.TypeParameterList, out var parameters, out var constraints); - var convertedIdentifier = ConvertIdentifier(classStatement.Identifier, semanticModel); + var convertedIdentifier = ConvertIdentifier(classStatement.Identifier); return SyntaxFactory.ClassDeclaration( attributes, @@ -205,7 +205,7 @@ public override CSharpSyntaxNode VisitModuleBlock(VBSyntax.ModuleBlockSyntax nod return SyntaxFactory.ClassDeclaration( attributes, ConvertModifiers(stmt.Modifiers, TokenContext.InterfaceOrModule).Add(SyntaxFactory.Token(SyntaxKind.StaticKeyword)), - ConvertIdentifier(stmt.Identifier, semanticModel), + ConvertIdentifier(stmt.Identifier), parameters, ConvertInheritsAndImplements(node.Inherits, node.Implements), constraints, @@ -226,7 +226,7 @@ public override CSharpSyntaxNode VisitStructureBlock(VBSyntax.StructureBlockSynt return SyntaxFactory.StructDeclaration( attributes, ConvertModifiers(stmt.Modifiers, TokenContext.Global), - ConvertIdentifier(stmt.Identifier, semanticModel), + ConvertIdentifier(stmt.Identifier), parameters, ConvertInheritsAndImplements(node.Inherits, node.Implements), constraints, @@ -247,7 +247,7 @@ public override CSharpSyntaxNode VisitInterfaceBlock(VBSyntax.InterfaceBlockSynt return SyntaxFactory.InterfaceDeclaration( attributes, ConvertModifiers(stmt.Modifiers, TokenContext.InterfaceOrModule), - ConvertIdentifier(stmt.Identifier, semanticModel), + ConvertIdentifier(stmt.Identifier), parameters, ConvertInheritsAndImplements(node.Inherits, node.Implements), constraints, @@ -277,7 +277,7 @@ public override CSharpSyntaxNode VisitEnumBlock(VBSyntax.EnumBlockSyntax node) return SyntaxFactory.EnumDeclaration( SyntaxFactory.List(attributes), ConvertModifiers(stmt.Modifiers, TokenContext.Global), - ConvertIdentifier(stmt.Identifier, semanticModel), + ConvertIdentifier(stmt.Identifier), baseList, members ); @@ -288,7 +288,7 @@ public override CSharpSyntaxNode VisitEnumMemberDeclaration(VBSyntax.EnumMemberD var attributes = ConvertAttributes(node.AttributeLists); return SyntaxFactory.EnumMemberDeclaration( attributes, - ConvertIdentifier(node.Identifier, semanticModel), + ConvertIdentifier(node.Identifier), (EqualsValueClauseSyntax)node.Initializer?.Accept(TriviaConvertingVisitor) ); } @@ -321,7 +321,7 @@ public override CSharpSyntaxNode VisitDelegateStatement(VBSyntax.DelegateStateme SyntaxFactory.List(attributes), ConvertModifiers(node.Modifiers, TokenContext.Global), returnType, - ConvertIdentifier(node.Identifier, semanticModel), + ConvertIdentifier(node.Identifier), typeParameters, (ParameterListSyntax)node.ParameterList?.Accept(TriviaConvertingVisitor), constraints @@ -413,7 +413,7 @@ public override CSharpSyntaxNode VisitPropertyStatement(VBSyntax.PropertyStateme modifiers, rawType, null, - ConvertIdentifier(node.Identifier, semanticModel), accessors, + ConvertIdentifier(node.Identifier), accessors, null, initializer, SyntaxFactory.Token(initializer == null ? SyntaxKind.None : SyntaxKind.SemicolonToken)); @@ -473,7 +473,7 @@ public override CSharpSyntaxNode VisitMethodStatement(VBSyntax.MethodStatementSy if ("Finalize".Equals(node.Identifier.ValueText, StringComparison.OrdinalIgnoreCase) && node.Modifiers.Any(m => VBasic.VisualBasicExtensions.Kind(m) == VBasic.SyntaxKind.OverridesKeyword)) { var decl = SyntaxFactory.DestructorDeclaration( - ConvertIdentifier(node.GetAncestor().BlockStatement.Identifier, semanticModel) + ConvertIdentifier(node.GetAncestor().BlockStatement.Identifier) ).WithAttributeLists(SyntaxFactory.List(attributes)); if (hasBody) return decl; return decl.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)); @@ -490,7 +490,7 @@ public override CSharpSyntaxNode VisitMethodStatement(VBSyntax.MethodStatementSy modifiers, (TypeSyntax)node.AsClause?.Type.Accept(TriviaConvertingVisitor) ?? SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword)), null, - ConvertIdentifier(node.Identifier, semanticModel), + ConvertIdentifier(node.Identifier), typeParameters, (ParameterListSyntax)node.ParameterList.Accept(TriviaConvertingVisitor), constraints, @@ -532,7 +532,7 @@ public override CSharpSyntaxNode VisitEventBlock(VBSyntax.EventBlockSyntax node) modifiers, rawType, null, - ConvertIdentifier(block.Identifier, semanticModel), + ConvertIdentifier(block.Identifier), SyntaxFactory.AccessorList(SyntaxFactory.List(node.Accessors.Select(a => (AccessorDeclarationSyntax)a.Accept(TriviaConvertingVisitor)))) ); } @@ -541,7 +541,7 @@ public override CSharpSyntaxNode VisitEventStatement(VBSyntax.EventStatementSynt { var attributes = node.AttributeLists.SelectMany(ConvertAttribute); var modifiers = ConvertModifiers(node.Modifiers, TokenContext.Member); - var id = ConvertIdentifier(node.Identifier, semanticModel); + var id = ConvertIdentifier(node.Identifier); if (node.AsClause == null) { var delegateName = SyntaxFactory.Identifier(id.ValueText + "EventHandler"); @@ -628,7 +628,7 @@ public override CSharpSyntaxNode VisitConstructorBlock(VBSyntax.ConstructorBlock return SyntaxFactory.ConstructorDeclaration( SyntaxFactory.List(attributes), modifiers, - ConvertIdentifier(node.GetAncestor().BlockStatement.Identifier, semanticModel), + ConvertIdentifier(node.GetAncestor().BlockStatement.Identifier), (ParameterListSyntax)block.ParameterList.Accept(TriviaConvertingVisitor), ctorCall, SyntaxFactory.Block(statements.SelectMany(s => s.Accept(CreateMethodBodyVisitor()))) @@ -652,7 +652,7 @@ public override CSharpSyntaxNode VisitParameterList(VBSyntax.ParameterListSyntax public override CSharpSyntaxNode VisitParameter(VBSyntax.ParameterSyntax node) { - var id = ConvertIdentifier(node.Identifier.Identifier, semanticModel); + var id = ConvertIdentifier(node.Identifier.Identifier); var returnType = (TypeSyntax)node.AsClause?.Type.Accept(TriviaConvertingVisitor); if (node.Parent?.Parent?.IsKind(VBasic.SyntaxKind.FunctionStatement, VBasic.SyntaxKind.SubStatement) == true) { @@ -711,7 +711,7 @@ public override CSharpSyntaxNode VisitCatchBlock(VBSyntax.CatchBlockSyntax node) var typeInfo = semanticModel.GetTypeInfo(stmt.IdentifierName).Type; catcher = SyntaxFactory.CatchDeclaration( SyntaxFactory.ParseTypeName(typeInfo.ToMinimalDisplayString(semanticModel, node.SpanStart)), - ConvertIdentifier(stmt.IdentifierName.Identifier, semanticModel) + ConvertIdentifier(stmt.IdentifierName.Identifier) ); } @@ -1023,7 +1023,7 @@ private FromClauseSyntax ConvertFromClauseSyntax(VBSyntax.FromClauseSyntax vbFro { var collectionRangeVariableSyntax = vbFromClause.Variables.Single(); var fromClauseSyntax = SyntaxFactory.FromClause( - ConvertIdentifier(collectionRangeVariableSyntax.Identifier.Identifier, semanticModel), + ConvertIdentifier(collectionRangeVariableSyntax.Identifier.Identifier), (ExpressionSyntax) collectionRangeVariableSyntax.Expression.Accept(TriviaConvertingVisitor)); return fromClauseSyntax; } @@ -1051,6 +1051,11 @@ private QueryClauseSyntax ConvertQueryBodyClause(VBSyntax.QueryClauseSyntax node _ => throw new NotImplementedException($"Conversion for query clause with kind '{node.Kind()}' not implemented")); } + private SyntaxToken ConvertIdentifier(SyntaxToken identifierIdentifier, bool isAttribute = false) + { + return VisualBasicConverter.ConvertIdentifier(identifierIdentifier, semanticModel, isAttribute); + } + private QueryClauseSyntax ConvertWhereClause(VBSyntax.WhereClauseSyntax ws) { return SyntaxFactory.WhereClause((ExpressionSyntax) ws.Condition.Accept(TriviaConvertingVisitor)); @@ -1059,7 +1064,7 @@ private QueryClauseSyntax ConvertWhereClause(VBSyntax.WhereClauseSyntax ws) private QueryClauseSyntax ConvertLetClause(VBSyntax.LetClauseSyntax ls) { var singleVariable = ls.Variables.Single(); - return SyntaxFactory.LetClause(ConvertIdentifier(singleVariable.NameEquals.Identifier.Identifier, semanticModel), (ExpressionSyntax) singleVariable.Expression.Accept(TriviaConvertingVisitor)); + return SyntaxFactory.LetClause(ConvertIdentifier(singleVariable.NameEquals.Identifier.Identifier), (ExpressionSyntax) singleVariable.Expression.Accept(TriviaConvertingVisitor)); } private QueryClauseSyntax ConvertOrderByClause(VBSyntax.OrderByClauseSyntax os) @@ -1081,14 +1086,14 @@ private QueryClauseSyntax ConvertJoinClause(VBSyntax.JoinClauseSyntax js) .Cast().ToList()); var joinRhs = SingleExpression(js.JoinConditions.Select(c => c.Right.Accept(TriviaConvertingVisitor)) .Cast().ToList()); - var convertIdentifier = ConvertIdentifier(variable.Identifier.Identifier, semanticModel); + var convertIdentifier = ConvertIdentifier(variable.Identifier.Identifier); var expressionSyntax = (ExpressionSyntax) variable.Expression.Accept(TriviaConvertingVisitor); JoinIntoClauseSyntax joinIntoClauseSyntax = null; if (js is VBSyntax.GroupJoinClauseSyntax gjs) { joinIntoClauseSyntax = gjs.AggregationVariables .Where(a => a.Aggregation is VBSyntax.GroupAggregationSyntax) - .Select(a => SyntaxFactory.JoinIntoClause(ConvertIdentifier(a.NameEquals.Identifier.Identifier, semanticModel))) + .Select(a => SyntaxFactory.JoinIntoClause(ConvertIdentifier(a.NameEquals.Identifier.Identifier))) .SingleOrDefault(); } return SyntaxFactory.JoinClause(null, convertIdentifier, expressionSyntax, joinLhs, joinRhs, joinIntoClauseSyntax); @@ -1106,7 +1111,7 @@ public override CSharpSyntaxNode VisitNamedFieldInitializer(VBSyntax.NamedFieldI { if (node?.Parent?.Parent is VBSyntax.AnonymousObjectCreationExpressionSyntax) { return SyntaxFactory.AnonymousObjectMemberDeclarator( - SyntaxFactory.NameEquals(SyntaxFactory.IdentifierName(ConvertIdentifier(node.Name.Identifier, semanticModel))), + SyntaxFactory.NameEquals(SyntaxFactory.IdentifierName(ConvertIdentifier(node.Name.Identifier))), (ExpressionSyntax)node.Expression.Accept(TriviaConvertingVisitor)); } @@ -1308,18 +1313,18 @@ public override CSharpSyntaxNode VisitTypeParameter(VBSyntax.TypeParameterSyntax if (!SyntaxTokenExtensions.IsKind(node.VarianceKeyword, VBasic.SyntaxKind.None)) { variance = SyntaxFactory.Token(SyntaxTokenExtensions.IsKind(node.VarianceKeyword, VBasic.SyntaxKind.InKeyword) ? SyntaxKind.InKeyword : SyntaxKind.OutKeyword); } - return SyntaxFactory.TypeParameter(SyntaxFactory.List(), variance, ConvertIdentifier(node.Identifier, semanticModel)); + return SyntaxFactory.TypeParameter(SyntaxFactory.List(), variance, ConvertIdentifier(node.Identifier)); } public override CSharpSyntaxNode VisitTypeParameterSingleConstraintClause(VBSyntax.TypeParameterSingleConstraintClauseSyntax node) { - var id = SyntaxFactory.IdentifierName(ConvertIdentifier(((VBSyntax.TypeParameterSyntax)node.Parent).Identifier, semanticModel)); + var id = SyntaxFactory.IdentifierName(ConvertIdentifier(((VBSyntax.TypeParameterSyntax)node.Parent).Identifier)); return SyntaxFactory.TypeParameterConstraintClause(id, SyntaxFactory.SingletonSeparatedList((TypeParameterConstraintSyntax)node.Constraint.Accept(TriviaConvertingVisitor))); } public override CSharpSyntaxNode VisitTypeParameterMultipleConstraintClause(VBSyntax.TypeParameterMultipleConstraintClauseSyntax node) { - var id = SyntaxFactory.IdentifierName(ConvertIdentifier(((VBSyntax.TypeParameterSyntax)node.Parent).Identifier, semanticModel)); + var id = SyntaxFactory.IdentifierName(ConvertIdentifier(((VBSyntax.TypeParameterSyntax)node.Parent).Identifier)); return SyntaxFactory.TypeParameterConstraintClause(id, SyntaxFactory.SeparatedList(node.Constraints.Select(c => (TypeParameterConstraintSyntax)c.Accept(TriviaConvertingVisitor)))); } @@ -1341,7 +1346,7 @@ public override CSharpSyntaxNode VisitTypeConstraint(VBSyntax.TypeConstraintSynt public override CSharpSyntaxNode VisitIdentifierName(VBSyntax.IdentifierNameSyntax node) { - var identifier = SyntaxFactory.IdentifierName(ConvertIdentifier(node.Identifier, semanticModel, node.GetAncestor() != null)); + var identifier = SyntaxFactory.IdentifierName(ConvertIdentifier(node.Identifier, node.GetAncestor() != null)); return !node.Parent.IsKind(VBasic.SyntaxKind.SimpleMemberAccessExpression, VBasic.SyntaxKind.QualifiedName, VBasic.SyntaxKind.NameColonEquals, VBasic.SyntaxKind.ImportsStatement, VBasic.SyntaxKind.NamespaceStatement, VBasic.SyntaxKind.NamedFieldInitializer) ? QualifyNode(node, identifier) : identifier; @@ -1417,7 +1422,7 @@ public override CSharpSyntaxNode VisitQualifiedName(VBSyntax.QualifiedNameSyntax public override CSharpSyntaxNode VisitGenericName(VBSyntax.GenericNameSyntax node) { - return SyntaxFactory.GenericName(ConvertIdentifier(node.Identifier, semanticModel), (TypeArgumentListSyntax)node.TypeArgumentList?.Accept(TriviaConvertingVisitor)); + return SyntaxFactory.GenericName(ConvertIdentifier(node.Identifier), (TypeArgumentListSyntax)node.TypeArgumentList?.Accept(TriviaConvertingVisitor)); } public override CSharpSyntaxNode VisitTypeArgumentList(VBSyntax.TypeArgumentListSyntax node) From 64dfdcd86ba57915db446ff5e86bfda36d964be5 Mon Sep 17 00:00:00 2001 From: GrahamTheCoder Date: Sat, 24 Feb 2018 20:21:28 +0000 Subject: [PATCH 6/9] Cater for simple group clause Name of group variable isn't declared in the C#, could add an extra "let" if this becomes a problem --- .../CSharp/NodesVisitor.cs | 38 +++++++++++++++++-- Tests/CSharp/ExpressionTests.cs | 35 +++++++++-------- Tests/ConverterTestBase.cs | 27 +++++++++---- 3 files changed, 72 insertions(+), 28 deletions(-) diff --git a/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs b/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs index 09bfd6e43..c11905374 100644 --- a/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs +++ b/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs @@ -962,6 +962,11 @@ public override CSharpSyntaxNode VisitAnonymousObjectCreationExpression(VBSyntax return SyntaxFactory.AnonymousObjectCreationExpression(memberDeclaratorSyntaxs); } + public override CSharpSyntaxNode VisitInferredFieldInitializer(VBSyntax.InferredFieldInitializerSyntax node) + { + return SyntaxFactory.AnonymousObjectMemberDeclarator((ExpressionSyntax) node.Expression.Accept(TriviaConvertingVisitor)); + } + public override CSharpSyntaxNode VisitObjectCreationExpression(VBSyntax.ObjectCreationExpressionSyntax node) { return SyntaxFactory.ObjectCreationExpression( @@ -1011,11 +1016,24 @@ public override CSharpSyntaxNode VisitQueryExpression(VBSyntax.QueryExpressionSy { var vbFromClause = node.Clauses.OfType().Single(); var fromClauseSyntax = ConvertFromClauseSyntax(vbFromClause); + var vbGroupClause = node.Clauses.OfType().SingleOrDefault(); var vbSelectClause = node.Clauses.OfType().Single(); var selectClauseSyntax = ConvertSelectClauseSyntax(vbSelectClause); - var vbBodyClauses = node.Clauses.Except(new VBSyntax.QueryClauseSyntax[] {vbFromClause, vbSelectClause }); - var queryClauseSyntaxs = SyntaxFactory.List(vbBodyClauses.Select(ConvertQueryBodyClause)); - var queryBodySyntax = SyntaxFactory.QueryBody(queryClauseSyntaxs, selectClauseSyntax, null); + var alreadyConverted = new VBSyntax.QueryClauseSyntax[] { vbFromClause, vbGroupClause, vbSelectClause }; + var vbBodyClauses = node.Clauses; + SelectOrGroupClauseSyntax selectOrGroup = null; + QueryContinuationSyntax queryContinuation = null; + var queryClauseSyntaxs = SyntaxFactory.List(vbBodyClauses.TakeWhile(x => x != vbGroupClause).Except(alreadyConverted).Select(ConvertQueryBodyClause)); + var continuedClauses = SyntaxFactory.List(vbBodyClauses.SkipWhile(x => x != vbGroupClause).Skip(1).Except(alreadyConverted).Select(ConvertQueryBodyClause)); + if (vbGroupClause != null) { + selectOrGroup = ConvertGroupByClause(vbGroupClause); + queryContinuation = SyntaxFactory.QueryContinuation(GetGroupIdentifier(vbGroupClause), + SyntaxFactory.QueryBody(continuedClauses, selectClauseSyntax, null)); + } else { + selectOrGroup = selectClauseSyntax; + } + + var queryBodySyntax = SyntaxFactory.QueryBody(queryClauseSyntaxs, selectOrGroup, queryContinuation); return SyntaxFactory.QueryExpression(fromClauseSyntax, queryBodySyntax); } @@ -1041,7 +1059,6 @@ private QueryClauseSyntax ConvertQueryBodyClause(VBSyntax.QueryClauseSyntax node return node.TypeSwitch( //(VBSyntax.AggregateClauseSyntax ags) => null, //(VBSyntax.DistinctClauseSyntax ds) => null, - //(VBSyntax.GroupByClauseSyntax gs) => null, ConvertJoinClause, ConvertLetClause, ConvertOrderByClause, @@ -1051,6 +1068,19 @@ private QueryClauseSyntax ConvertQueryBodyClause(VBSyntax.QueryClauseSyntax node _ => throw new NotImplementedException($"Conversion for query clause with kind '{node.Kind()}' not implemented")); } + private GroupClauseSyntax ConvertGroupByClause(VBSyntax.GroupByClauseSyntax gs) + { + if (gs == null) return null; + var item = (IdentifierNameSyntax) gs.Items.Single().Expression.Accept(TriviaConvertingVisitor); + var keyExpression = (ExpressionSyntax) gs.Keys.Single().Expression.Accept(TriviaConvertingVisitor); + return SyntaxFactory.GroupClause(item, keyExpression); + } + + private SyntaxToken GetGroupIdentifier(VBSyntax.GroupByClauseSyntax gs) + { + return ConvertIdentifier(gs.AggregationVariables.Select(x => x.Aggregation).OfType().First().FunctionName); + } + private SyntaxToken ConvertIdentifier(SyntaxToken identifierIdentifier, bool isAttribute = false) { return VisualBasicConverter.ConvertIdentifier(identifierIdentifier, semanticModel, isAttribute); diff --git a/Tests/CSharp/ExpressionTests.cs b/Tests/CSharp/ExpressionTests.cs index a6192c372..3dbc1957c 100644 --- a/Tests/CSharp/ExpressionTests.cs +++ b/Tests/CSharp/ExpressionTests.cs @@ -486,7 +486,7 @@ where n > 5 }"); } - [Fact(Skip = "Not implemented!")] + [Fact] public void Linq2() { TestConversionVisualBasicToCSharp(@"Public Shared Sub Linq40() @@ -502,25 +502,26 @@ For Each n In g.Numbers Next End Sub", @"public static void Linq40() +{ + int[] numbers = new[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };"/*TODO Remove need for new[]*/ + @" + var numberGroups = from n in numbers + group n by n % 5 into g + select new { Remainder = g.Key, Numbers = g }; + + foreach (var g in numberGroups) { - int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; - var numberGroups = from n in numbers - group n by n % 5 into g - select new { Remainder = g.Key, Numbers = g }; + System.Console.WriteLine($""Numbers with a remainder of {g.Remainder} when divided by 5:""); - foreach (var g in numberGroups) - { - System.Console.WriteLine($""Numbers with a remainder of {g.Remainder} when divided by 5:""); - foreach (var n in g.Numbers) - System.Console.WriteLine(n); - } - }"); + foreach (var n in g.Numbers) + System.Console.WriteLine(n); + } +}"); } - [Fact(Skip = "Not implemented!")] + [Fact()] public void Linq3() { - TestConversionVisualBasicToCSharp(@"Class Product + TestConversionVisualBasicToCSharpWithoutComments(@"Class Product Public Category As String Public ProductName As String End Class @@ -536,12 +537,14 @@ For Each v In q Next End Sub End Class", - @"class Product { + @"class Product +{ public string Category; public string ProductName; } -class Test { +class Test +{ public void Linq102() { string[] categories = new string[] { ""Beverages"", ""Condiments"", ""Vegetables"", ""Dairy Products"", ""Seafood"" }; diff --git a/Tests/ConverterTestBase.cs b/Tests/ConverterTestBase.cs index 1ad301c99..629d2ded6 100644 --- a/Tests/ConverterTestBase.cs +++ b/Tests/ConverterTestBase.cs @@ -32,27 +32,38 @@ public void TestConversionCSharpToVisualBasic(string csharpCode, string expected public void TestConversionVisualBasicToCSharp(string visualBasicCode, string expectedCsharpCode, bool standaloneStatements = false) { - if (standaloneStatements) { + expectedCsharpCode = AddUsings(expectedCsharpCode, standaloneStatements); + TestConversionVisualBasicToCSharpWithoutComments(visualBasicCode, expectedCsharpCode, false); + if (testCommentsByDefault) TestConversionVisualBasicToCSharpWithoutComments(AddLineNumberComments(visualBasicCode, "' ", false), AddLineNumberComments(expectedCsharpCode, "// ", true), false); + } + + private static string AddUsings(string expectedCsharpCode, bool standaloneStatements) + { + if (standaloneStatements) + { var indentedStatements = expectedCsharpCode.Replace("\n", "\n "); expectedCsharpCode = -$@"{{ + $@"{{ {indentedStatements} }}"; - } else if (!expectedCsharpCode.StartsWith("using System")) { - expectedCsharpCode = -@"using System; + } + else if (!expectedCsharpCode.StartsWith("using System")) + { + expectedCsharpCode = + @"using System; using System.Collections.Generic; using System.Linq; using Microsoft.VisualBasic; " + expectedCsharpCode; } - TestConversionVisualBasicToCSharpWithoutComments(visualBasicCode, expectedCsharpCode); - if (testCommentsByDefault) TestConversionVisualBasicToCSharpWithoutComments(AddLineNumberComments(visualBasicCode, "' ", false), AddLineNumberComments(expectedCsharpCode, "// ", true)); + + return expectedCsharpCode; } - public void TestConversionVisualBasicToCSharpWithoutComments(string visualBasicCode, string expectedCsharpCode, CSharpParseOptions csharpOptions = null, VisualBasicParseOptions vbOptions = null) + public void TestConversionVisualBasicToCSharpWithoutComments(string visualBasicCode, string expectedCsharpCode, bool addUsings = true, CSharpParseOptions csharpOptions = null, VisualBasicParseOptions vbOptions = null) { + if (addUsings) expectedCsharpCode = AddUsings(expectedCsharpCode, false); var outputNode = VisualBasicConverter.ConvertText(visualBasicCode, DiagnosticTestBase.DefaultMetadataReferences); var txt = Utils.HomogenizeEol(outputNode.ConvertedCode ?? outputNode.GetExceptionsAsString()).TrimEnd(); expectedCsharpCode = Utils.HomogenizeEol(expectedCsharpCode).TrimEnd(); From 30fda400c64d266e0d5df3f764ab07c0c8e84937 Mon Sep 17 00:00:00 2001 From: GrahamTheCoder Date: Sat, 24 Feb 2018 20:52:38 +0000 Subject: [PATCH 7/9] Handle basic goto case --- .../CSharp/MethodBodyVisitor.cs | 12 ++++++++++++ Tests/CSharp/StatementTests.cs | 15 ++++++--------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/ICSharpCode.CodeConverter/CSharp/MethodBodyVisitor.cs b/ICSharpCode.CodeConverter/CSharp/MethodBodyVisitor.cs index bdb99ed1a..9a0ce98fe 100644 --- a/ICSharpCode.CodeConverter/CSharp/MethodBodyVisitor.cs +++ b/ICSharpCode.CodeConverter/CSharp/MethodBodyVisitor.cs @@ -272,6 +272,18 @@ public override SyntaxList VisitForEachBlock(VBSyntax.ForEachBl )); } + + public override SyntaxList VisitLabelStatement(VBSyntax.LabelStatementSyntax node) + { + return SingleStatement(SyntaxFactory.LabeledStatement(node.LabelToken.Text, SyntaxFactory.EmptyStatement())); + } + + public override SyntaxList VisitGoToStatement(VBSyntax.GoToStatementSyntax node) + { + return SingleStatement(SyntaxFactory.GotoStatement(SyntaxKind.GotoStatement, + SyntaxFactory.IdentifierName(node.Label.LabelToken.Text))); + } + public override SyntaxList VisitSelectBlock(VBSyntax.SelectBlockSyntax node) { var expr = (ExpressionSyntax)node.SelectStatement.Expression.Accept(nodesVisitor); diff --git a/Tests/CSharp/StatementTests.cs b/Tests/CSharp/StatementTests.cs index 018aff7cc..cbd2ca45d 100644 --- a/Tests/CSharp/StatementTests.cs +++ b/Tests/CSharp/StatementTests.cs @@ -554,10 +554,10 @@ private void TestMethod() }"); } - [Fact()] + [Fact] public void DeclarationStatements() { - TestConversionVisualBasicToCSharp( + TestConversionVisualBasicToCSharpWithoutComments( @"Class Test Private Sub TestMethod() the_beginning: @@ -566,15 +566,12 @@ Private Sub TestMethod() Dim text = ""This is my text!"" GoTo the_beginning End Sub -End Class", @"using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.VisualBasic; - -class Test { +End Class", @"class Test +{ private void TestMethod() { -the_beginning: + the_beginning: + ; int value = 1; const double myPIe = System.Math.PI; var text = ""This is my text!""; From 9eb8a544ae716d34b8a4a9633c5506b57e8d0636 Mon Sep 17 00:00:00 2001 From: GrahamTheCoder Date: Sat, 24 Feb 2018 21:10:41 +0000 Subject: [PATCH 8/9] Simple implementation of goto and another array bounds mechanism --- .../CSharp/NodesVisitor.cs | 9 ++- Tests/CSharp/StatementTests.cs | 64 +++++++++---------- 2 files changed, 33 insertions(+), 40 deletions(-) diff --git a/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs b/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs index c11905374..642618fee 100644 --- a/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs +++ b/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs @@ -979,12 +979,11 @@ public override CSharpSyntaxNode VisitObjectCreationExpression(VBSyntax.ObjectCr public override CSharpSyntaxNode VisitArrayCreationExpression(VBSyntax.ArrayCreationExpressionSyntax node) { - IEnumerable arguments; - if (node.ArrayBounds != null) { - arguments = ConvertArrayBounds(node.ArrayBounds); - } else - arguments = Enumerable.Empty(); var bounds = ConvertArrayRankSpecifierSyntaxes(node.RankSpecifiers); + if (node.ArrayBounds != null) { + var arrayRankSpecifierSyntax = SyntaxFactory.ArrayRankSpecifier(SyntaxFactory.SeparatedList(ConvertArrayBounds(node.ArrayBounds))); + bounds = bounds.Insert(0, arrayRankSpecifierSyntax); + } return SyntaxFactory.ArrayCreationExpression( SyntaxFactory.ArrayType((TypeSyntax)node.Type.Accept(TriviaConvertingVisitor), bounds), (InitializerExpressionSyntax)node.Initializer?.Accept(TriviaConvertingVisitor) diff --git a/Tests/CSharp/StatementTests.cs b/Tests/CSharp/StatementTests.cs index cbd2ca45d..813916e11 100644 --- a/Tests/CSharp/StatementTests.cs +++ b/Tests/CSharp/StatementTests.cs @@ -365,7 +365,7 @@ private void TestMethod() }"); } - [Fact(Skip = "Not implemented!")] + [Fact] public void ArrayInitializationStatementWithLength() { TestConversionVisualBasicToCSharp(@"Class TestClass @@ -449,7 +449,7 @@ private void TestMethod() }"); } - [Fact(Skip = "Not implemented!")] + [Fact] public void MultidimensionalArrayInitializationStatementWithLengths() { TestConversionVisualBasicToCSharp(@"Class TestClass @@ -512,7 +512,7 @@ private void TestMethod() }"); } - [Fact(Skip = "Not implemented!")] + [Fact] public void JaggedArrayInitializationStatementWithType() { TestConversionVisualBasicToCSharp(@"Class TestClass @@ -533,7 +533,7 @@ private void TestMethod() }"); } - [Fact(Skip = "Not implemented!")] + [Fact] public void JaggedArrayInitializationStatementWithLength() { TestConversionVisualBasicToCSharp(@"Class TestClass @@ -838,10 +838,10 @@ private void TestMethod() }"); } - [Fact()] + [Fact] public void LabeledAndForStatement() { - TestConversionVisualBasicToCSharp(@"Class GotoTest1 + TestConversionVisualBasicToCSharpWithoutComments(@"Class GotoTest1 Private Shared Sub Main() Dim x As Integer = 200, y As Integer = 4 Dim count As Integer = 0 @@ -883,46 +883,40 @@ End Sub class GotoTest1 { - static void Main() + private static void Main() { - int x = 200, y = 4; + int x = 200; + int y = 4; int count = 0; - string[,] array = new string[x, y]; + string[,] array = new string[x - 1 + 1, y - 1 + 1]; - for (int i = 0; i < x; i++) + for (int i = 0; i <= x - 1; i++) - for (int j = 0; j < y; j++) - array[i, j] = (++count).ToString(); + for (int j = 0; j <= y - 1; j++) + array[i, j] = (System.Threading.Interlocked.Increment(ref count)).ToString(); Console.Write(""Enter the number to search for: ""); - string myNumber = Console.ReadLine(); - for (int i = 0; i < x; i++) - { - for (int j = 0; j < y; j++) - { - if (array[i, j].Equals(myNumber)) - { - goto Found; - } - } - } - - Console.WriteLine(""The number {0} was not found."", myNumber); - goto Finish; + for (int i = 0; i <= x - 1; i++) - Found: - Console.WriteLine(""The number {0} is found."", myNumber); + for (int j = 0; j <= y - 1; j++) - Finish: - Console.WriteLine(""End of search.""); + if (array[i, j].Equals(myNumber)) + goto Found; - - Console.WriteLine(""Press any key to exit.""); - Console.ReadKey(); - } - }"); + Console.WriteLine(""The number {0} was not found."", myNumber); + goto Finish; + Found: + ; + Console.WriteLine(""The number {0} is found."", myNumber); + Finish: + ; + Console.WriteLine(""End of search.""); + Console.WriteLine(""Press any key to exit.""); + Console.ReadKey(); + } +}"); } [Fact] From 9a1f8e244d80072791437cb147a1d4de3f17e820 Mon Sep 17 00:00:00 2001 From: GrahamTheCoder Date: Sat, 24 Feb 2018 22:00:48 +0000 Subject: [PATCH 9/9] Extension method conversion --- .../CSharp/NodesVisitor.cs | 28 ++++++++++++++----- Tests/CSharp/MemberTests.cs | 21 +++++--------- Tests/ConverterTestBase.cs | 1 + 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs b/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs index 642618fee..7b41800a2 100644 --- a/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs +++ b/ICSharpCode.CodeConverter/CSharp/NodesVisitor.cs @@ -91,7 +91,7 @@ private SyntaxList ConvertAttributes(SyntaxList ConvertAttribute(VBSyntax.AttributeListSyntax attributeList) { - return attributeList.Attributes.Select(a => (AttributeListSyntax)a.Accept(TriviaConvertingVisitor)); + return attributeList.Attributes.Where(a => !IsExtensionAttribute(a)).Select(a => (AttributeListSyntax)a.Accept(TriviaConvertingVisitor)); } public override CSharpSyntaxNode VisitAttribute(VBSyntax.AttributeSyntax node) @@ -464,17 +464,17 @@ private BlockSyntax VisitStatements(SyntaxList stateme { return SyntaxFactory.Block(statements.SelectMany(s => s.Accept(CreateMethodBodyVisitor(isIterator)))); } - + public override CSharpSyntaxNode VisitMethodStatement(VBSyntax.MethodStatementSyntax node) { - var attributes = node.AttributeLists.SelectMany(ConvertAttribute); + var attributes = ConvertAttributes(node.AttributeLists); bool hasBody = node.Parent is VBSyntax.MethodBlockBaseSyntax; if ("Finalize".Equals(node.Identifier.ValueText, StringComparison.OrdinalIgnoreCase) && node.Modifiers.Any(m => VBasic.VisualBasicExtensions.Kind(m) == VBasic.SyntaxKind.OverridesKeyword)) { var decl = SyntaxFactory.DestructorDeclaration( ConvertIdentifier(node.GetAncestor().BlockStatement.Identifier) - ).WithAttributeLists(SyntaxFactory.List(attributes)); + ).WithAttributeLists(attributes); if (hasBody) return decl; return decl.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)); } else { @@ -486,7 +486,7 @@ public override CSharpSyntaxNode VisitMethodStatement(VBSyntax.MethodStatementSy SplitTypeParameters(node.TypeParameterList, out typeParameters, out constraints); var decl = SyntaxFactory.MethodDeclaration( - SyntaxFactory.List(attributes), + attributes, modifiers, (TypeSyntax)node.AsClause?.Type.Accept(TriviaConvertingVisitor) ?? SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword)), null, @@ -501,6 +501,15 @@ public override CSharpSyntaxNode VisitMethodStatement(VBSyntax.MethodStatementSy return decl.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)); } } + private bool HasExtensionAttribute(VBSyntax.AttributeListSyntax a) + { + return a.Attributes.Any(IsExtensionAttribute); + } + + private bool IsExtensionAttribute(VBSyntax.AttributeSyntax a) + { + return semanticModel.GetTypeInfo(a).ConvertedType?.GetFullMetadataName()?.Equals("System.Runtime.CompilerServices.ExtensionAttribute") == true; + } private TokenContext GetMethodOrPropertyContext(VBSyntax.StatementSyntax node) { @@ -644,10 +653,11 @@ public override CSharpSyntaxNode VisitTypeParameterList(VBSyntax.TypeParameterLi public override CSharpSyntaxNode VisitParameterList(VBSyntax.ParameterListSyntax node) { + var parameterSyntaxs = node.Parameters.Select(p => (ParameterSyntax)p.Accept(TriviaConvertingVisitor)); if (node.Parent is VBSyntax.PropertyStatementSyntax) { - return SyntaxFactory.BracketedParameterList(SyntaxFactory.SeparatedList(node.Parameters.Select(p => (ParameterSyntax)p.Accept(TriviaConvertingVisitor)))); + return SyntaxFactory.BracketedParameterList(SyntaxFactory.SeparatedList(parameterSyntaxs)); } - return SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(node.Parameters.Select(p => (ParameterSyntax)p.Accept(TriviaConvertingVisitor)))); + return SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameterSyntaxs)); } public override CSharpSyntaxNode VisitParameter(VBSyntax.ParameterSyntax node) @@ -683,6 +693,10 @@ public override CSharpSyntaxNode VisitParameter(VBSyntax.ParameterSyntax node) attributes.RemoveAt(outAttributeIndex); modifiers = modifiers.Replace(SyntaxFactory.Token(SyntaxKind.RefKeyword), SyntaxFactory.Token(SyntaxKind.OutKeyword)); } + + if (node.Parent.Parent is VBSyntax.MethodStatementSyntax mss && mss.AttributeLists.Any(HasExtensionAttribute)) { + modifiers = modifiers.Insert(0, SyntaxFactory.Token(SyntaxKind.ThisKeyword)); + } return SyntaxFactory.Parameter( SyntaxFactory.List(attributes), modifiers, diff --git a/Tests/CSharp/MemberTests.cs b/Tests/CSharp/MemberTests.cs index fc8ebb445..845250384 100644 --- a/Tests/CSharp/MemberTests.cs +++ b/Tests/CSharp/MemberTests.cs @@ -150,30 +150,23 @@ public sealed void TestMethod(out T argument, ref T2 argument2, T3 ar }"); } - [Fact(Skip = "Not implemented!")] + [Fact] public void TestExtensionMethod() { TestConversionVisualBasicToCSharp( -@"Imports System.Runtime.CompilerServices - -Module TestClass - +@"Module TestClass + Sub TestMethod(ByVal str As String) End Sub -End Module", @"using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.VisualBasic; - -static class TestClass +End Module", @"static class TestClass { - public static void TestMethod(this String str) + public static void TestMethod(this string str) { } }"); } - [Fact(Skip = "Not implemented!")] + [Fact] public void TestExtensionMethodWithExistingImport() { TestConversionVisualBasicToCSharp( @@ -191,7 +184,7 @@ End Sub static class TestClass { - public static void TestMethod(this String str) + public static void TestMethod(this string str) { } }"); diff --git a/Tests/ConverterTestBase.cs b/Tests/ConverterTestBase.cs index 629d2ded6..d993c2313 100644 --- a/Tests/ConverterTestBase.cs +++ b/Tests/ConverterTestBase.cs @@ -145,6 +145,7 @@ private static bool HasNoTargetLine(string prevLine, string line, string nextLin return IsVbInheritsOrImplements(nextLine) || line.Contains("End If") || line.Contains("Next") || IsFirstOfMultiLineVbIfStatement(line) + || line.Contains("