From d9b78a257971fec7d220c90cca29f0de5da6827f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Apr 2026 16:51:50 +0000 Subject: [PATCH 1/5] Initial plan From 67bdc984de4704c4636d91ae2ae897c6d0339f65 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Apr 2026 17:48:51 +0000 Subject: [PATCH 2/5] Strip partial modifier from method syntax in ComInterfaceGenerator and VtableIndexStubGenerator The ComInterfaceGenerator and VtableIndexStubGenerator were copying the partial modifier from user-declared interface methods to the generated stub code, producing invalid C#. This change strips the partial keyword from method modifiers when creating the method syntax template, similar to how the new keyword and accessibility modifiers are already stripped. Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/de757761-5c54-412d-9875-7403edd00714 Co-authored-by: jtschuster <36744439+jtschuster@users.noreply.github.com> --- .../ComInterfaceGenerator.cs | 2 +- .../VtableIndexStubGenerator.cs | 2 +- .../Compiles.cs | 30 +++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs index dad35781688f1a..b38cb42f77649e 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs @@ -363,7 +363,7 @@ internal static IncrementalMethodStubGenerationContext CalculateStubInformation( var containingSyntaxContext = new ContainingSyntaxContext(syntax); var methodSyntaxTemplate = new ContainingSyntax( - new SyntaxTokenList(syntax.Modifiers.Where(static m => !m.IsKind(SyntaxKind.NewKeyword))).StripAccessibilityModifiers(), + new SyntaxTokenList(syntax.Modifiers.Where(static m => !m.IsKind(SyntaxKind.NewKeyword) && !m.IsKind(SyntaxKind.PartialKeyword))).StripAccessibilityModifiers(), SyntaxKind.MethodDeclaration, syntax.Identifier, syntax.TypeParameterList); diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGenerator.cs index 4db8815cb94a8e..a27b52ea31733f 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGenerator.cs @@ -268,7 +268,7 @@ internal static SourceAvailableIncrementalMethodStubGenerationContext CalculateS var containingSyntaxContext = new ContainingSyntaxContext(syntax); - var methodSyntaxTemplate = new ContainingSyntax(syntax.Modifiers.StripAccessibilityModifiers(), SyntaxKind.MethodDeclaration, syntax.Identifier, syntax.TypeParameterList); + var methodSyntaxTemplate = new ContainingSyntax(new SyntaxTokenList(syntax.Modifiers.Where(static m => !m.IsKind(SyntaxKind.PartialKeyword))).StripAccessibilityModifiers(), SyntaxKind.MethodDeclaration, syntax.Identifier, syntax.TypeParameterList); ImmutableArray callConv = VirtualMethodPointerStubGenerator.GenerateCallConvSyntaxFromAttributes(suppressGCTransitionAttribute, unmanagedCallConvAttribute, defaultCallingConventions: ImmutableArray.Empty); diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs index c0806b2853d8f5..2318576ff2c290 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs @@ -376,6 +376,36 @@ public async Task ValidateComInterfaceSnippets(string id, string source) await VerifyComInterfaceGenerator.VerifySourceGeneratorAsync(source); } + [Fact] + public async Task PartialMethodModifierOnComInterfaceMethodCompiles() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [GeneratedComInterface] + [Guid("9D3FD745-3C90-4C10-B140-FAFB01E3541D")] + internal partial interface IComInterface + { + void Method(); + public partial void PartialMethod(); + } + internal partial interface IComInterface + { + public partial void PartialMethod() { } + } + """; + + // CS0539 is expected because the partial method's default implementation + // conflicts with the generated explicit interface implementation. + // The important verification is that no additional errors are produced + // from the 'partial' modifier being incorrectly copied to generated code. + await VerifyComInterfaceGenerator.VerifySourceGeneratorAsync(source, + DiagnosticResult.CompilerError("CS0539") + .WithSpan("Microsoft.Interop.ComInterfaceGenerator/Microsoft.Interop.ComInterfaceGenerator/IComInterface.cs", 78, 32, 78, 45) + .WithArguments("InterfaceImplementation.PartialMethod()")); + } + [Fact] public async Task DocumentedComInterfaceDoesNotProduceCS1591Warnings() { From 570e59139503ec5e89582f7127efeed97027fc55 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Thu, 9 Apr 2026 11:33:22 -0700 Subject: [PATCH 3/5] Apply suggestions from code review Co-authored-by: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> --- .../ComInterfaceGenerator.Unit.Tests/Compiles.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs index 2318576ff2c290..89ed79e0805237 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs @@ -385,25 +385,19 @@ public async Task PartialMethodModifierOnComInterfaceMethodCompiles() [GeneratedComInterface] [Guid("9D3FD745-3C90-4C10-B140-FAFB01E3541D")] - internal partial interface IComInterface + internal virtual partial interface IComInterface { void Method(); public partial void PartialMethod(); } - internal partial interface IComInterface + internal virtual partial interface IComInterface { public partial void PartialMethod() { } } """; // CS0539 is expected because the partial method's default implementation - // conflicts with the generated explicit interface implementation. - // The important verification is that no additional errors are produced - // from the 'partial' modifier being incorrectly copied to generated code. - await VerifyComInterfaceGenerator.VerifySourceGeneratorAsync(source, - DiagnosticResult.CompilerError("CS0539") - .WithSpan("Microsoft.Interop.ComInterfaceGenerator/Microsoft.Interop.ComInterfaceGenerator/IComInterface.cs", 78, 32, 78, 45) - .WithArguments("InterfaceImplementation.PartialMethod()")); + await VerifyComInterfaceGenerator.VerifySourceGeneratorAsync(source); } [Fact] From b788d1dbfb6dc01d125f916d35019727399ddf5d Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 10 Apr 2026 14:57:07 -0700 Subject: [PATCH 4/5] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> --- .../tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs index 89ed79e0805237..7b853db968adb1 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs @@ -385,18 +385,17 @@ public async Task PartialMethodModifierOnComInterfaceMethodCompiles() [GeneratedComInterface] [Guid("9D3FD745-3C90-4C10-B140-FAFB01E3541D")] - internal virtual partial interface IComInterface + internal partial interface IComInterface { void Method(); - public partial void PartialMethod(); + public virtual partial void PartialMethod(); } - internal virtual partial interface IComInterface + internal partial interface IComInterface { - public partial void PartialMethod() { } + public virtual partial void PartialMethod() { } } """; - // CS0539 is expected because the partial method's default implementation await VerifyComInterfaceGenerator.VerifySourceGeneratorAsync(source); } From 852730f14a9c1a9ae49c67a3d50e1f6e29182028 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Apr 2026 19:03:35 +0000 Subject: [PATCH 5/5] Also strip virtual modifier from generated COM interface method stubs Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/82488d5d-6c3d-426f-9d23-9e5eb6e75992 Co-authored-by: jtschuster <36744439+jtschuster@users.noreply.github.com> --- .../gen/ComInterfaceGenerator/ComInterfaceGenerator.cs | 2 +- .../gen/ComInterfaceGenerator/VtableIndexStubGenerator.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs index b38cb42f77649e..3b110111667f92 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs @@ -363,7 +363,7 @@ internal static IncrementalMethodStubGenerationContext CalculateStubInformation( var containingSyntaxContext = new ContainingSyntaxContext(syntax); var methodSyntaxTemplate = new ContainingSyntax( - new SyntaxTokenList(syntax.Modifiers.Where(static m => !m.IsKind(SyntaxKind.NewKeyword) && !m.IsKind(SyntaxKind.PartialKeyword))).StripAccessibilityModifiers(), + new SyntaxTokenList(syntax.Modifiers.Where(static m => !m.IsKind(SyntaxKind.NewKeyword) && !m.IsKind(SyntaxKind.PartialKeyword) && !m.IsKind(SyntaxKind.VirtualKeyword))).StripAccessibilityModifiers(), SyntaxKind.MethodDeclaration, syntax.Identifier, syntax.TypeParameterList); diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGenerator.cs index a27b52ea31733f..c6e61bc8166386 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGenerator.cs @@ -268,7 +268,7 @@ internal static SourceAvailableIncrementalMethodStubGenerationContext CalculateS var containingSyntaxContext = new ContainingSyntaxContext(syntax); - var methodSyntaxTemplate = new ContainingSyntax(new SyntaxTokenList(syntax.Modifiers.Where(static m => !m.IsKind(SyntaxKind.PartialKeyword))).StripAccessibilityModifiers(), SyntaxKind.MethodDeclaration, syntax.Identifier, syntax.TypeParameterList); + var methodSyntaxTemplate = new ContainingSyntax(new SyntaxTokenList(syntax.Modifiers.Where(static m => !m.IsKind(SyntaxKind.PartialKeyword) && !m.IsKind(SyntaxKind.VirtualKeyword))).StripAccessibilityModifiers(), SyntaxKind.MethodDeclaration, syntax.Identifier, syntax.TypeParameterList); ImmutableArray callConv = VirtualMethodPointerStubGenerator.GenerateCallConvSyntaxFromAttributes(suppressGCTransitionAttribute, unmanagedCallConvAttribute, defaultCallingConventions: ImmutableArray.Empty);