Skip to content

Commit 3bf2f1a

Browse files
Merge pull request #1189 from jrmoreno1/Issue1097
VB -> C#: private partial methods do not compile
2 parents add696c + 81ff635 commit 3bf2f1a

File tree

3 files changed

+29
-30
lines changed

3 files changed

+29
-30
lines changed

CodeConverter/CSharp/DeclarationNodeVisitor.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ public override async Task<CSharpSyntaxNode> VisitMethodBlock(VBSyntax.MethodBlo
655655
var methodBlock = await node.SubOrFunctionStatement.AcceptAsync<BaseMethodDeclarationSyntax>(TriviaConvertingDeclarationVisitor, SourceTriviaMapKind.SubNodesOnly);
656656

657657
var declaredSymbol = ModelExtensions.GetDeclaredSymbol(_semanticModel, node);
658-
if (!declaredSymbol.CanHaveMethodBody()) {
658+
if (declaredSymbol?.CanHaveMethodBody() == false) {
659659
return methodBlock;
660660
}
661661
var csReturnVariableOrNull = CommonConversions.GetRetVariableNameOrNull(node);
@@ -786,7 +786,8 @@ public override async Task<CSharpSyntaxNode> VisitMethodStatement(VBSyntax.Metho
786786
null
787787
);
788788

789-
return hasBody && declaredSymbol.CanHaveMethodBody() ? decl : decl.WithSemicolonToken(SemicolonToken);
789+
bool canHaveMethodBody = declaredSymbol?.CanHaveMethodBody() != false;
790+
return hasBody && canHaveMethodBody ? decl : decl.WithSemicolonToken(SemicolonToken);
790791
}
791792

792793
public override async Task<CSharpSyntaxNode> VisitEventBlock(VBSyntax.EventBlockSyntax node)

CodeConverter/Util/ISymbolExtensions.cs

Lines changed: 19 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#nullable enable
12
namespace ICSharpCode.CodeConverter.Util;
23

34
internal static class ISymbolExtensions
@@ -18,12 +19,9 @@ public static ISymbol GetBaseSymbol(this ISymbol symbol, Func<ISymbol, bool> sel
1819
: symbol;
1920
}
2021

21-
public static bool IsDefinedInSource(this ISymbol symbol)
22-
{
23-
return symbol.Locations.Any(loc => loc.IsInSource);
24-
}
22+
public static bool IsDefinedInSource(this ISymbol symbol) => symbol.Locations.Any(loc => loc.IsInSource);
2523

26-
public static TSymbol ExtractBestMatch<TSymbol>(this SymbolInfo info, Func<TSymbol, bool> isMatch = null) where TSymbol : class, ISymbol
24+
public static TSymbol? ExtractBestMatch<TSymbol>(this SymbolInfo info, Func<TSymbol, bool>? isMatch = null) where TSymbol : class, ISymbol
2725
{
2826
isMatch ??= (_ => true);
2927
if (info.Symbol == null && info.CandidateSymbols.Length == 0)
@@ -38,16 +36,16 @@ public static TSymbol ExtractBestMatch<TSymbol>(this SymbolInfo info, Func<TSymb
3836
return null;
3937
}
4038

41-
public static string ToCSharpDisplayString(this ISymbol symbol, SymbolDisplayFormat format = null)
39+
public static string? ToCSharpDisplayString(this ISymbol symbol, SymbolDisplayFormat? format = null)
4240
{
4341
if (TryGetSpecialVBTypeConversion(symbol, out var cSharpDisplayString)) return cSharpDisplayString;
4442

4543
return symbol.ToDisplayString(format);
4644
}
4745

48-
private static bool TryGetSpecialVBTypeConversion(ISymbol symbol, out string cSharpDisplayString)
46+
private static bool TryGetSpecialVBTypeConversion(ISymbol symbol, out string? cSharpDisplayString)
4947
{
50-
var containingNamespace = symbol?.ContainingNamespace?.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat);
48+
var containingNamespace = symbol.ContainingNamespace?.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat);
5149
if (containingNamespace == "Microsoft.VisualBasic" || containingNamespace == "System") {
5250
if (symbol is ITypeSymbol && TypesToConvertToDateTime.Contains(symbol.Name)) {
5351
{
@@ -68,35 +66,28 @@ private static bool TryGetSpecialVBTypeConversion(ISymbol symbol, out string cSh
6866
return false;
6967
}
7068

71-
public static bool IsPartialMethodImplementation(this ISymbol declaredSymbol)
72-
{
73-
return declaredSymbol is IMethodSymbol ms && ms.PartialDefinitionPart != null;
74-
}
69+
public static bool IsPartialMethodImplementation(this ISymbol? declaredSymbol) =>
70+
declaredSymbol is IMethodSymbol {PartialDefinitionPart: not null};
7571

76-
public static bool CanHaveMethodBody(this ISymbol declaredSymbol)
77-
{
78-
return !(declaredSymbol is IMethodSymbol ms) || ms.PartialImplementationPart == null && !ms.IsExtern;
79-
}
72+
public static bool CanHaveMethodBody(this ISymbol? declaredSymbol) =>
73+
declaredSymbol is IMethodSymbol {IsExtern: false} && !IsPartialMethodDefinition(declaredSymbol);
8074

81-
public static bool IsPartialMethodDefinition(this ISymbol declaredSymbol)
82-
{
83-
return declaredSymbol is IMethodSymbol ms && ms.PartialImplementationPart != null;
84-
}
75+
public static bool IsPartialMethodDefinition(this ISymbol? declaredSymbol) =>
76+
declaredSymbol is IMethodSymbol {PartialImplementationPart: not null}
77+
or IMethodSymbol {IsPartialDefinition: true};
8578

86-
public static bool IsPartialClassDefinition(this ISymbol declaredSymbol)
79+
public static bool IsPartialClassDefinition(this ISymbol? declaredSymbol)
8780
{
88-
return declaredSymbol is ITypeSymbol ts && (ts.DeclaringSyntaxReferences.Length > 1
89-
|| ts.ContainingAssembly.Name == ForcePartialTypesAssemblyName);
81+
return declaredSymbol is ITypeSymbol {DeclaringSyntaxReferences.Length: > 1}
82+
or ITypeSymbol {ContainingAssembly.Name: ForcePartialTypesAssemblyName};
9083
}
9184

92-
public static bool IsReducedTypeParameterMethod(this ISymbol symbol)
93-
{
94-
return symbol is IMethodSymbol ms && ms.ReducedFrom?.TypeParameters.Length > ms.TypeParameters.Length;
95-
}
85+
public static bool IsReducedTypeParameterMethod(this ISymbol? symbol) =>
86+
symbol is IMethodSymbol ms && ms.ReducedFrom?.TypeParameters.Length > ms.TypeParameters.Length;
9687

9788
/// <summary>
9889
/// Since non value types can't be ref types for extension methods in C#, convert to a static invocation
9990
/// https://github.com/icsharpcode/CodeConverter/issues/785
10091
/// </summary>
101-
public static bool ValidCSharpExtensionMethodParameter(this IParameterSymbol vbSymbol) => vbSymbol != null && (vbSymbol.RefKind != RefKind.Ref || vbSymbol.Type.IsValueType);
92+
public static bool ValidCSharpExtensionMethodParameter(this IParameterSymbol? vbSymbol) => vbSymbol != null && (vbSymbol.RefKind != RefKind.Ref || vbSymbol.Type.IsValueType);
10293
}

Tests/CSharp/MemberTests/MemberTests.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,13 @@ public partial class TestClass // VB doesn't require partial here (when just a s
921921
}");
922922
}
923923

924+
[Fact]
925+
public async Task Issue1097_PartialMethodAsync()
926+
{
927+
await TestConversionVisualBasicToCSharpAsync(@"Partial Private Sub DummyMethod()
928+
End Sub", @"partial void DummyMethod();");
929+
}
930+
924931
[Fact]
925932
public async Task NestedClassAsync()
926933
{

0 commit comments

Comments
 (0)