Skip to content

Commit 5889f2d

Browse files
committed
Fix #1242: NullReferenceException in WinformsConversions.CreatePropertyAssignment
When InitializeComponent contains a bare identifier assignment (e.g. `Button1 = New Button()` without the `Me.` prefix), s.Left is a VBSyntax.IdentifierNameSyntax. Calling LastOrDefaultDescendant<IdentifierNameSyntax>() on it returns null because DescendantNodes() does not include the node itself, causing a NullReferenceException in CreatePropertyAssignment. Fix: detect when s.Left is itself an IdentifierNameSyntax and use it directly; also add a null guard so other unexpected shapes fall through gracefully. Regression test added based on the Issue774 test but with a bare identifier (no Me.) in InitializeComponent's WithEvents field assignment. https://claude.ai/code/session_01AkwUvu3XuCdj3D4axoX4UX
1 parent a113695 commit 5889f2d

File tree

2 files changed

+129
-1
lines changed

2 files changed

+129
-1
lines changed

CodeConverter/CSharp/WinformsConversions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ private IEnumerable<Assignment> GetAssignmentsFromInitializeComponent(VBSyntax.M
5656
return CreateNameAssignment(maes.Expression.LastOrDefaultDescendant<VBSyntax.IdentifierNameSyntax>());
5757
}
5858
} else if (ShouldReassignProperty(s)){
59-
return CreatePropertyAssignment(s.Left.LastOrDefaultDescendant<VBSyntax.IdentifierNameSyntax>());
59+
var id = s.Left is VBSyntax.IdentifierNameSyntax directId ? directId : s.Left.LastOrDefaultDescendant<VBSyntax.IdentifierNameSyntax>();
60+
if (id == null) return null;
61+
return CreatePropertyAssignment(id);
6062
}
6163

6264
return null;

Tests/CSharp/MemberTests/EventMemberTests.cs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,132 @@ private void _dep_SomeEvent(object sender, EventArgs e)
734734
");
735735
}
736736

737+
[Fact]
738+
public async Task Issue1242_WinformsNullRefOnBareIdentifierInInitializeComponentAsync()
739+
{
740+
// Regression test: bare identifier (no Me. prefix) in InitializeComponent caused a NullReferenceException
741+
// in WinformsConversions.CreatePropertyAssignment when s.Left is IdentifierNameSyntax and
742+
// LastOrDefaultDescendant returns null (since DescendantNodes does not include the node itself).
743+
await TestConversionVisualBasicToCSharpAsync(@"Imports System
744+
Imports System.Windows.Forms
745+
Imports Microsoft.VisualBasic.CompilerServices
746+
747+
Partial Class BaseForm
748+
Inherits Form
749+
Friend WithEvents BaseButton As Button
750+
End Class
751+
752+
<DesignerGenerated>
753+
Partial Class BaseForm
754+
Inherits System.Windows.Forms.Form
755+
756+
Private Sub InitializeComponent()
757+
BaseButton = New Button()
758+
End Sub
759+
End Class
760+
761+
<DesignerGenerated>
762+
Partial Class Form1
763+
Inherits BaseForm
764+
Private Sub InitializeComponent()
765+
Me.Button1 = New Button()
766+
End Sub
767+
Friend WithEvents Button1 As Button
768+
End Class
769+
770+
Partial Class Form1
771+
Private Sub MultiClickHandler(sender As Object, e As EventArgs) Handles Button1.Click,
772+
BaseButton.Click
773+
End Sub
774+
End Class", @"using System;
775+
using System.Runtime.CompilerServices;
776+
using System.Windows.Forms;
777+
using Microsoft.VisualBasic.CompilerServices; // Install-Package Microsoft.VisualBasic
778+
779+
internal partial class BaseForm : Form
780+
{
781+
private Button _BaseButton;
782+
783+
internal virtual Button BaseButton
784+
{
785+
[MethodImpl(MethodImplOptions.Synchronized)]
786+
get
787+
{
788+
return _BaseButton;
789+
}
790+
791+
[MethodImpl(MethodImplOptions.Synchronized)]
792+
set
793+
{
794+
_BaseButton = value;
795+
}
796+
}
797+
798+
public BaseForm()
799+
{
800+
InitializeComponent();
801+
BaseButton = _BaseButton;
802+
}
803+
}
804+
805+
[DesignerGenerated]
806+
internal partial class BaseForm : Form
807+
{
808+
809+
private void InitializeComponent()
810+
{
811+
_BaseButton = new Button();
812+
}
813+
}
814+
815+
[DesignerGenerated]
816+
internal partial class Form1 : BaseForm
817+
{
818+
internal override Button BaseButton
819+
{
820+
[MethodImpl(MethodImplOptions.Synchronized)]
821+
get
822+
{
823+
return base.BaseButton;
824+
}
825+
826+
[MethodImpl(MethodImplOptions.Synchronized)]
827+
set
828+
{
829+
if (base.BaseButton != null)
830+
{
831+
base.BaseButton.Click -= MultiClickHandler;
832+
}
833+
834+
base.BaseButton = value;
835+
if (base.BaseButton != null)
836+
{
837+
base.BaseButton.Click += MultiClickHandler;
838+
}
839+
}
840+
}
841+
842+
public Form1()
843+
{
844+
InitializeComponent();
845+
}
846+
private void InitializeComponent()
847+
{
848+
Button1 = new Button();
849+
Button1.Click += new EventHandler(MultiClickHandler);
850+
}
851+
internal Button Button1;
852+
}
853+
854+
internal partial class Form1
855+
{
856+
private void MultiClickHandler(object sender, EventArgs e)
857+
{
858+
}
859+
}
860+
");
861+
}
862+
737863
[Fact]
738864
public async Task Test_Issue701_MultiLineHandlesSyntaxAsync()
739865
{

0 commit comments

Comments
 (0)