From a677aa94e8297b9cf053232c380c07227bd4af48 Mon Sep 17 00:00:00 2001 From: YourRobotOverlord <47068588+YourRobotOverlord@users.noreply.github.com> Date: Sat, 4 Apr 2026 19:51:34 -0600 Subject: [PATCH] Fixes NullReferenceException in AdornmentView.Contains when Adornment is null AdornmentView has a parameter-less constructor (for AllViewsTester reflection support) that leaves Adornment = null. When such a view is placed inside a SuperView (e.g. the Themes UICatalog scenario creates AdornmentView/MarginView via reflection), moving the mouse over it caused a NullReferenceException at Adornment!.Thickness.Contains(...) because the null-forgiving ! operator did not prevent the dereference. Fix: add a guard clause returning false when Adornment is null, matching the existing pattern used in OnClearingViewport, OnDrawingText, and OnDrawingSubViews. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../ViewBase/Adornment/AdornmentView.cs | 7 +++++- .../ViewBase/Adornment/AdornmentViewTests.cs | 25 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 Tests/UnitTestsParallelizable/ViewBase/Adornment/AdornmentViewTests.cs diff --git a/Terminal.Gui/ViewBase/Adornment/AdornmentView.cs b/Terminal.Gui/ViewBase/Adornment/AdornmentView.cs index db14b87888..5ec5c43a6c 100644 --- a/Terminal.Gui/ViewBase/Adornment/AdornmentView.cs +++ b/Terminal.Gui/ViewBase/Adornment/AdornmentView.cs @@ -190,10 +190,15 @@ public override bool Contains (in Point location) } } + if (Adornment is null) + { + return false; + } + Rectangle outside = Frame; outside.Offset (parentOrSuperView.Frame.Location); - return Adornment!.Thickness.Contains (outside, location); + return Adornment.Thickness.Contains (outside, location); } #endregion View Overrides diff --git a/Tests/UnitTestsParallelizable/ViewBase/Adornment/AdornmentViewTests.cs b/Tests/UnitTestsParallelizable/ViewBase/Adornment/AdornmentViewTests.cs new file mode 100644 index 0000000000..8e35729fda --- /dev/null +++ b/Tests/UnitTestsParallelizable/ViewBase/Adornment/AdornmentViewTests.cs @@ -0,0 +1,25 @@ +namespace ViewBaseTests.Adornments; + +// Copilot +public class AdornmentViewTests +{ + /// + /// Regression test for https://github.com/gui-cs/Terminal.Gui/issues/4883. + /// AdornmentView.Contains must not throw NullReferenceException when Adornment is null + /// (i.e. the view was created via its parameter-less constructor, as happens when + /// AllViewsTester / Themes UICatalog scenario creates it via reflection). + /// + [Fact] + public void Contains_Returns_False_When_Adornment_Is_Null () + { + // Arrange - parameter-less ctor leaves Adornment = null + AdornmentView adornmentView = new (); + + // Act & Assert - must not throw NullReferenceException + bool result = adornmentView.Contains (new Point (0, 0)); + + Assert.False (result); + } + + +}