Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CodeConverter/CSharp/AccessorDeclarationNodeConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ CSSyntax.MethodDeclarationSyntax WithMergedModifiers(CSSyntax.MethodDeclarationS

async Task<CSSyntax.MethodDeclarationSyntax> CreateMethodDeclarationSyntaxAsync(VBSyntax.ParameterListSyntax containingPropParameterList, string methodId, bool voidReturn)
{
var parameterListSyntax = await containingPropParameterList.AcceptAsync<CSSyntax.ParameterListSyntax>(CommonConversions.TriviaConvertingExpressionVisitor);
var parameterListSyntax = await containingPropParameterList.AcceptParameterListAsync(CommonConversions.TriviaConvertingExpressionVisitor);
var methodModifiers = CS.SyntaxFactory.TokenList(modifiers.Where(m => !m.IsCsVisibility(false, false)));
CSSyntax.MethodDeclarationSyntax methodDeclarationSyntax = CS.SyntaxFactory.MethodDeclaration(attributes, methodModifiers,
voidReturn ? CS.SyntaxFactory.PredefinedType(CS.SyntaxFactory.Token(CS.SyntaxKind.VoidKeyword)) : rawType,
Expand Down Expand Up @@ -274,7 +274,7 @@ public async Task<CSharpSyntaxNode> VisitAccessorBlockAsync(VBSyntax.AccessorBlo

async Task<CSSyntax.MethodDeclarationSyntax> CreateMethodDeclarationSyntax(VBSyntax.ParameterListSyntax containingPropParameterList, bool voidReturn)
{
var parameterListSyntax = await containingPropParameterList.AcceptAsync<CSSyntax.ParameterListSyntax>(CommonConversions.TriviaConvertingExpressionVisitor, sourceMap);
var parameterListSyntax = await containingPropParameterList.AcceptParameterListAsync(CommonConversions.TriviaConvertingExpressionVisitor, sourceMap);

CSSyntax.MethodDeclarationSyntax methodDeclarationSyntax = CS.SyntaxFactory.MethodDeclaration(attributes, modifiers,
voidReturn ? CS.SyntaxFactory.PredefinedType(CS.SyntaxFactory.Token(CS.SyntaxKind.VoidKeyword)) : returnType,
Expand Down
13 changes: 6 additions & 7 deletions CodeConverter/CSharp/DeclarationNodeVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ public override async Task<CSharpSyntaxNode> VisitDelegateStatement(VBSyntax.Del
CS.SyntaxFactory.List(attributes), CommonConversions.ConvertModifiers(node, node.Modifiers),
returnType, CommonConversions.ConvertIdentifier(node.Identifier),
typeParameters,
await node.ParameterList.AcceptAsync<ParameterListSyntax>(_triviaConvertingExpressionVisitor),
await node.ParameterList.AcceptParameterListAsync(_triviaConvertingExpressionVisitor),
constraints
);
}
Expand Down Expand Up @@ -795,7 +795,7 @@ public override async Task<CSharpSyntaxNode> VisitMethodStatement(VBSyntax.Metho
await (node.AsClause?.Type).AcceptAsync<TypeSyntax>(_triviaConvertingExpressionVisitor) ?? CS.SyntaxFactory.PredefinedType(CS.SyntaxFactory.Token(CS.SyntaxKind.VoidKeyword)));

var directlyConvertedCsIdentifier = CommonConversions.CsEscapedIdentifier(node.Identifier.Value as string);
var parameterList = await node.ParameterList.AcceptAsync<ParameterListSyntax>(_triviaConvertingExpressionVisitor) ?? CS.SyntaxFactory.ParameterList();
var parameterList = await node.ParameterList.AcceptParameterListAsync(_triviaConvertingExpressionVisitor);
var additionalDeclarations = new List<MemberDeclarationSyntax>();

var hasExplicitInterfaceImplementation = declaredSymbol.IsNonPublicInterfaceImplementation() || declaredSymbol.IsRenamedInterfaceMember(directlyConvertedCsIdentifier, declaredSymbol.ExplicitInterfaceImplementations);
Expand Down Expand Up @@ -892,7 +892,7 @@ public override async Task<CSharpSyntaxNode> VisitEventStatement(VBSyntax.EventS
CS.SyntaxFactory.PredefinedType(CS.SyntaxFactory.Token(CS.SyntaxKind.VoidKeyword)),
delegateName,
null,
await node.ParameterList.AcceptAsync<ParameterListSyntax>(_triviaConvertingExpressionVisitor) ?? CS.SyntaxFactory.ParameterList(),
await node.ParameterList.AcceptParameterListAsync(_triviaConvertingExpressionVisitor),
CS.SyntaxFactory.List<TypeParameterConstraintClauseSyntax>()
);

Expand Down Expand Up @@ -927,7 +927,7 @@ public override async Task<CSharpSyntaxNode> VisitOperatorStatement(VBSyntax.Ope
var attributes = await node.AttributeLists.SelectManyAsync(CommonConversions.ConvertAttributeAsync);
var attributeList = CS.SyntaxFactory.List(attributes);
var returnType = await (node.AsClause?.Type).AcceptAsync<TypeSyntax>(_triviaConvertingExpressionVisitor) ?? CS.SyntaxFactory.PredefinedType(CS.SyntaxFactory.Token(CS.SyntaxKind.VoidKeyword));
var parameterList = await node.ParameterList.AcceptAsync<ParameterListSyntax>(_triviaConvertingExpressionVisitor);
var parameterList = await node.ParameterList.AcceptParameterListAsync(_triviaConvertingExpressionVisitor);
var methodBodyVisitor = await ConvertMethodBodyStatementsAsync(node, containingBlock.Statements);
var body = CS.SyntaxFactory.Block(methodBodyVisitor);
var modifiers = CommonConversions.ConvertModifiers(node, node.Modifiers, node.GetMemberContext());
Expand Down Expand Up @@ -974,7 +974,7 @@ public override async Task<CSharpSyntaxNode> VisitConstructorBlock(VBSyntax.Cons
CS.SyntaxFactory.List(attributes),
modifiers,
CommonConversions.ConvertIdentifier(node.GetAncestor<VBSyntax.TypeBlockSyntax>().BlockStatement.Identifier).WithoutSourceMapping(), //TODO Use semantic model for this name
await block.ParameterList.AcceptAsync<ParameterListSyntax>(_triviaConvertingExpressionVisitor) ?? CS.SyntaxFactory.ParameterList(),
await block.ParameterList.AcceptParameterListAsync(_triviaConvertingExpressionVisitor),
ctorCall,
CS.SyntaxFactory.Block(convertedBodyStatements)
);
Expand Down Expand Up @@ -1010,8 +1010,7 @@ public override async Task<CSharpSyntaxNode> VisitDeclareStatement(VBSyntax.Decl
modifiers = modifiers.Add(CS.SyntaxFactory.Token(CS.SyntaxKind.ExternKeyword));

var returnType = await (node.AsClause?.Type).AcceptAsync<TypeSyntax>(_triviaConvertingExpressionVisitor) ?? CS.SyntaxFactory.PredefinedType(CS.SyntaxFactory.Token(CS.SyntaxKind.VoidKeyword));
var parameterListSyntax = await (node.ParameterList).AcceptAsync<ParameterListSyntax>(_triviaConvertingExpressionVisitor) ??
CS.SyntaxFactory.ParameterList();
var parameterListSyntax = await (node.ParameterList).AcceptParameterListAsync(_triviaConvertingExpressionVisitor);

return CS.SyntaxFactory.MethodDeclaration(attributeLists, modifiers, returnType, null, CommonConversions.ConvertIdentifier(node.Identifier), null,
parameterListSyntax, CS.SyntaxFactory.List<TypeParameterConstraintClauseSyntax>(), null, null).WithSemicolonToken(SemicolonToken);
Expand Down
4 changes: 2 additions & 2 deletions CodeConverter/CSharp/LambdaConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public async Task<CSharpSyntaxNode> ConvertMultiLineLambdaAsync(VBSyntax.MultiLi
async Task<CSharpSyntaxNode> ConvertInnerAsync()
{
var body = await ConvertMethodBodyStatementsAsync(node, node.Statements);
var param = await node.SubOrFunctionHeader.ParameterList.AcceptAsync<ParameterListSyntax>(CommonConversions.TriviaConvertingExpressionVisitor);
var param = await node.SubOrFunctionHeader.ParameterList.AcceptParameterListAsync(CommonConversions.TriviaConvertingExpressionVisitor);
return await ConvertAsync(node, param, body.ToList());
}
}
Expand All @@ -66,7 +66,7 @@ async Task<CSharpSyntaxNode> ConvertInnerAsync()
convertedStatements = new[] { SyntaxFactory.ExpressionStatement(csNode) };
}

var param = await node.SubOrFunctionHeader.ParameterList.AcceptAsync<ParameterListSyntax>(CommonConversions.TriviaConvertingExpressionVisitor);
var param = await node.SubOrFunctionHeader.ParameterList.AcceptParameterListAsync(CommonConversions.TriviaConvertingExpressionVisitor);
return await ConvertAsync(node, param, convertedStatements);
}
}
Expand Down
7 changes: 7 additions & 0 deletions CodeConverter/CSharp/SyntaxNodeVisitorExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.VisualBasic;

namespace ICSharpCode.CodeConverter.CSharp;
Expand All @@ -9,6 +10,12 @@ internal static class SyntaxNodeVisitorExtensions
/// <summary>For TOut, specify the most general type acceptable by the calling code (often ExpressionSyntax), this allows error information to be attached to a dummy return node.</summary>
public static async Task<TOut> AcceptAsync<TOut>(this VisualBasicSyntaxNode node, CommentConvertingVisitorWrapper visitorWrapper, SourceTriviaMapKind sourceTriviaMap = SourceTriviaMapKind.All) where TOut : CSharpSyntaxNode =>
node == null ? null : await visitorWrapper.AcceptAsync<TOut>(node, sourceTriviaMap);
/// <summary>
/// VB allows the parentheses to be omitted when there are no parameters (e.g. <c>Delegate Sub Callback</c>, <c>RaiseEvent</c> accessors, <c>Sub Foo</c>), leaving a null parameter list.
/// C# always requires one, so every place that converts a VB parameter list should go via this method so they all agree on an empty list.
/// </summary>
public static async Task<ParameterListSyntax> AcceptParameterListAsync(this VBSyntax.ParameterListSyntax parameterList, CommentConvertingVisitorWrapper visitorWrapper, SourceTriviaMapKind sourceTriviaMap = SourceTriviaMapKind.All) =>
await parameterList.AcceptAsync<ParameterListSyntax>(visitorWrapper, sourceTriviaMap) ?? Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParameterList();
public static async Task<SeparatedSyntaxList<TOut>> AcceptSeparatedListAsync<TIn, TOut>(this SeparatedSyntaxList<TIn> nodes, CommentConvertingVisitorWrapper visitorWrapper, SourceTriviaMapKind sourceTriviaMap = SourceTriviaMapKind.All) where TIn : VisualBasicSyntaxNode where TOut : CSharpSyntaxNode =>
await visitorWrapper.AcceptAsync<TIn, TOut>(nodes, sourceTriviaMap);
}
35 changes: 35 additions & 0 deletions Tests/CSharp/MemberTests/MemberTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1645,6 +1645,41 @@ internal string Join(string s = null)
}");
}

[Fact]
public async Task ParameterlessMembersWithoutParenthesesAsync()
{
await TestConversionVisualBasicToCSharpAsync(
@"Class TestClass
Declare Sub ExternSub Lib ""lib""
Declare Function ExternFunc Lib ""lib"" As Integer
Sub New
End Sub
Sub Foo
End Sub
Function Bar As Integer
Return 1
End Function
End Class", @"using System.Runtime.InteropServices;

internal partial class TestClass
{
[DllImport(""lib"")]
public static extern void ExternSub();
[DllImport(""lib"")]
public static extern int ExternFunc();
public TestClass()
{
}
public void Foo()
{
}
public int Bar()
{
return 1;
}
}");
}

[Fact]
public async Task TestMultipleCharDefaultValuesForStringParametersAsync()
{
Expand Down
19 changes: 19 additions & 0 deletions Tests/CSharp/NamespaceLevelTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,25 @@ await TestConversionVisualBasicToCSharpAsync(
@"public delegate void Test(ref int x);");
}

[Fact]
public async Task TestParameterlessDelegateWithoutParenthesesAsync()
{
await TestConversionVisualBasicToCSharpAsync(
@"Public Delegate Sub Callback",
@"public delegate void Callback();");
await TestConversionVisualBasicToCSharpAsync(
@"Public Delegate Function Provider As Integer",
@"public delegate int Provider();");
}

[Fact]
public async Task TestGenericParameterlessDelegateWithoutParenthesesAsync()
{
await TestConversionVisualBasicToCSharpAsync(
@"Public Delegate Function Operation(Of T) As T",
@"public delegate T Operation<T>();");
}

[Fact]
public async Task TestGenericDelegate771Async()
{
Expand Down
53 changes: 53 additions & 0 deletions Tests/CSharp/SpecialConversionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,59 @@ public void RaiseCustomEvent()
}");
}

[Fact]
public async Task TestCustomEventWithParameterlessRaiseEventWithoutParenthesesAsync()
{
await TestConversionVisualBasicToCSharpAsync(
@"Class TestClass
Public Delegate Sub Callback()
Private Event backingField As Callback

Public Custom Event MyEvent As Callback
AddHandler(ByVal value As Callback)
AddHandler Me.backingField, value
End AddHandler
RemoveHandler(ByVal value As Callback)
RemoveHandler Me.backingField, value
End RemoveHandler
RaiseEvent
Console.WriteLine(""Event Raised"")
End RaiseEvent
End Event ' RaiseEvent moves outside this block

Public Sub RaiseCustomEvent()
RaiseEvent MyEvent()
End Sub
End Class", @"using System;

internal partial class TestClass
{
public delegate void Callback();
private event Callback backingField;

public event Callback MyEvent
{
add
{
backingField += value;
}
remove
{
backingField -= value;
}
} // RaiseEvent moves outside this block
void OnMyEvent()
{
Console.WriteLine(""Event Raised"");
}

public void RaiseCustomEvent()
{
OnMyEvent();
}
}");
}

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