diff --git a/CodeConverter/CSharp/DeclarationNodeVisitor.cs b/CodeConverter/CSharp/DeclarationNodeVisitor.cs index 1863a4e0..6e855471 100644 --- a/CodeConverter/CSharp/DeclarationNodeVisitor.cs +++ b/CodeConverter/CSharp/DeclarationNodeVisitor.cs @@ -655,7 +655,7 @@ public override async Task VisitMethodBlock(VBSyntax.MethodBlo var methodBlock = await node.SubOrFunctionStatement.AcceptAsync(TriviaConvertingDeclarationVisitor, SourceTriviaMapKind.SubNodesOnly); var declaredSymbol = ModelExtensions.GetDeclaredSymbol(_semanticModel, node); - if (!declaredSymbol.CanHaveMethodBody()) { + if (declaredSymbol?.CanHaveMethodBody() == false) { return methodBlock; } var csReturnVariableOrNull = CommonConversions.GetRetVariableNameOrNull(node); @@ -786,7 +786,8 @@ public override async Task VisitMethodStatement(VBSyntax.Metho null ); - return hasBody && declaredSymbol.CanHaveMethodBody() ? decl : decl.WithSemicolonToken(SemicolonToken); + bool canHaveMethodBody = declaredSymbol?.CanHaveMethodBody() != false; + return hasBody && canHaveMethodBody ? decl : decl.WithSemicolonToken(SemicolonToken); } public override async Task VisitEventBlock(VBSyntax.EventBlockSyntax node) diff --git a/CodeConverter/Util/ISymbolExtensions.cs b/CodeConverter/Util/ISymbolExtensions.cs index ad910b0c..c5fe84a1 100644 --- a/CodeConverter/Util/ISymbolExtensions.cs +++ b/CodeConverter/Util/ISymbolExtensions.cs @@ -1,3 +1,4 @@ +#nullable enable namespace ICSharpCode.CodeConverter.Util; internal static class ISymbolExtensions @@ -18,12 +19,9 @@ public static ISymbol GetBaseSymbol(this ISymbol symbol, Func sel : symbol; } - public static bool IsDefinedInSource(this ISymbol symbol) - { - return symbol.Locations.Any(loc => loc.IsInSource); - } + public static bool IsDefinedInSource(this ISymbol symbol) => symbol.Locations.Any(loc => loc.IsInSource); - public static TSymbol ExtractBestMatch(this SymbolInfo info, Func isMatch = null) where TSymbol : class, ISymbol + public static TSymbol? ExtractBestMatch(this SymbolInfo info, Func? isMatch = null) where TSymbol : class, ISymbol { isMatch ??= (_ => true); if (info.Symbol == null && info.CandidateSymbols.Length == 0) @@ -38,16 +36,16 @@ public static TSymbol ExtractBestMatch(this SymbolInfo info, Func + declaredSymbol is IMethodSymbol {PartialDefinitionPart: not null}; - public static bool CanHaveMethodBody(this ISymbol declaredSymbol) - { - return !(declaredSymbol is IMethodSymbol ms) || ms.PartialImplementationPart == null && !ms.IsExtern; - } + public static bool CanHaveMethodBody(this ISymbol? declaredSymbol) => + declaredSymbol is IMethodSymbol {IsExtern: false} && !IsPartialMethodDefinition(declaredSymbol); - public static bool IsPartialMethodDefinition(this ISymbol declaredSymbol) - { - return declaredSymbol is IMethodSymbol ms && ms.PartialImplementationPart != null; - } + public static bool IsPartialMethodDefinition(this ISymbol? declaredSymbol) => + declaredSymbol is IMethodSymbol {PartialImplementationPart: not null} + or IMethodSymbol {IsPartialDefinition: true}; - public static bool IsPartialClassDefinition(this ISymbol declaredSymbol) + public static bool IsPartialClassDefinition(this ISymbol? declaredSymbol) { - return declaredSymbol is ITypeSymbol ts && (ts.DeclaringSyntaxReferences.Length > 1 - || ts.ContainingAssembly.Name == ForcePartialTypesAssemblyName); + return declaredSymbol is ITypeSymbol {DeclaringSyntaxReferences.Length: > 1} + or ITypeSymbol {ContainingAssembly.Name: ForcePartialTypesAssemblyName}; } - public static bool IsReducedTypeParameterMethod(this ISymbol symbol) - { - return symbol is IMethodSymbol ms && ms.ReducedFrom?.TypeParameters.Length > ms.TypeParameters.Length; - } + public static bool IsReducedTypeParameterMethod(this ISymbol? symbol) => + symbol is IMethodSymbol ms && ms.ReducedFrom?.TypeParameters.Length > ms.TypeParameters.Length; /// /// Since non value types can't be ref types for extension methods in C#, convert to a static invocation /// https://github.com/icsharpcode/CodeConverter/issues/785 /// - public static bool ValidCSharpExtensionMethodParameter(this IParameterSymbol vbSymbol) => vbSymbol != null && (vbSymbol.RefKind != RefKind.Ref || vbSymbol.Type.IsValueType); + public static bool ValidCSharpExtensionMethodParameter(this IParameterSymbol? vbSymbol) => vbSymbol != null && (vbSymbol.RefKind != RefKind.Ref || vbSymbol.Type.IsValueType); } \ No newline at end of file diff --git a/Tests/CSharp/MemberTests/MemberTests.cs b/Tests/CSharp/MemberTests/MemberTests.cs index 8b7c94ce..c43138a5 100644 --- a/Tests/CSharp/MemberTests/MemberTests.cs +++ b/Tests/CSharp/MemberTests/MemberTests.cs @@ -921,6 +921,13 @@ public partial class TestClass // VB doesn't require partial here (when just a s }"); } + [Fact] + public async Task Issue1097_PartialMethodAsync() + { + await TestConversionVisualBasicToCSharpAsync(@"Partial Private Sub DummyMethod() + End Sub", @"partial void DummyMethod();"); + } + [Fact] public async Task NestedClassAsync() {