From 51b9d17de76061796505a4c1d0c5ce87de00abe0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 16 Jan 2026 23:57:14 +0000 Subject: [PATCH 1/5] Initial plan From 60a3afb263d366c4bf13c2950ca823a723060de5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 17 Jan 2026 00:23:43 +0000 Subject: [PATCH 2/5] Fix BitArray.LeftShift to clear dangling high bits Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../tests/BitArray/BitArray_OperatorsTests.cs | 14 ++++++++++++++ .../src/System/Collections/BitArray.cs | 2 ++ 2 files changed, 16 insertions(+) diff --git a/src/libraries/System.Collections/tests/BitArray/BitArray_OperatorsTests.cs b/src/libraries/System.Collections/tests/BitArray/BitArray_OperatorsTests.cs index 888c523ef7e86e..8843b13b6f9e72 100644 --- a/src/libraries/System.Collections/tests/BitArray/BitArray_OperatorsTests.cs +++ b/src/libraries/System.Collections/tests/BitArray/BitArray_OperatorsTests.cs @@ -387,5 +387,19 @@ public static void PopCount(BitArray array, int expected) { Assert.Equal(expected, array.PopCount()); } + + [Fact] + public static void LeftShift_PopCountReturnsCorrectCount() + { + BitArray ba = new(33); + ba[^1] = true; + + Assert.True(ba.HasAnySet()); + Assert.Equal(1, ba.PopCount()); + + ba.LeftShift(1); + Assert.False(ba.HasAnySet()); + Assert.Equal(0, ba.PopCount()); + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/BitArray.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/BitArray.cs index 015985a464f8f9..43bb7c4930aa20 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/BitArray.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/BitArray.cs @@ -603,6 +603,8 @@ public BitArray LeftShift(int count) } intSpan[lastIndex] = ReverseIfBE(ReverseIfBE(intSpan[fromindex]) << shiftCount); } + + ClearHighExtraBits(); } else { From b649b14e747147d1974d8b70a2de85f9b99620c2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 17 Jan 2026 16:51:30 +0000 Subject: [PATCH 3/5] Add comprehensive shift+PopCount tests as Theory with various patterns Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../tests/BitArray/BitArray_OperatorsTests.cs | 69 ++++++++++++++++--- 1 file changed, 60 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Collections/tests/BitArray/BitArray_OperatorsTests.cs b/src/libraries/System.Collections/tests/BitArray/BitArray_OperatorsTests.cs index 8843b13b6f9e72..793d67a7502925 100644 --- a/src/libraries/System.Collections/tests/BitArray/BitArray_OperatorsTests.cs +++ b/src/libraries/System.Collections/tests/BitArray/BitArray_OperatorsTests.cs @@ -388,18 +388,69 @@ public static void PopCount(BitArray array, int expected) Assert.Equal(expected, array.PopCount()); } - [Fact] - public static void LeftShift_PopCountReturnsCorrectCount() + public static IEnumerable Shift_PopCount_TestData() { - BitArray ba = new(33); - ba[^1] = true; + // Test various lengths that include edge cases around int32 boundaries + foreach (int length in new[] { 1, BitsPerByte, BitsPerInt32 - 1, BitsPerInt32, BitsPerInt32 + 1, 2 * BitsPerInt32, 2 * BitsPerInt32 + 1 }) + { + // Test various shift amounts + foreach (int shift in new[] { 1, length / 2, length - 1, length, length + 1 }.Where(s => s > 0).Distinct()) + { + // Test with bit set at various positions + foreach (int bitPosition in new[] { 0, length / 2, length - 1 }.Distinct()) + { + yield return new object[] { length, bitPosition, shift }; + } + } + } + } + + [Theory] + [MemberData(nameof(Shift_PopCount_TestData))] + public static void LeftShift_PopCount(int length, int bitPosition, int shift) + { + BitArray ba = new(length); + ba[bitPosition] = true; - Assert.True(ba.HasAnySet()); - Assert.Equal(1, ba.PopCount()); + int expectedPopCount = bitPosition + shift < length ? 1 : 0; + ba.LeftShift(shift); + Assert.Equal(expectedPopCount, ba.PopCount()); + } - ba.LeftShift(1); - Assert.False(ba.HasAnySet()); - Assert.Equal(0, ba.PopCount()); + [Theory] + [MemberData(nameof(Shift_PopCount_TestData))] + public static void RightShift_PopCount(int length, int bitPosition, int shift) + { + BitArray ba = new(length); + ba[bitPosition] = true; + + int expectedPopCount = bitPosition - shift >= 0 ? 1 : 0; + ba.RightShift(shift); + Assert.Equal(expectedPopCount, ba.PopCount()); + } + + [Theory] + [MemberData(nameof(Shift_PopCount_TestData))] + public static void LeftShift_HasAnySet(int length, int bitPosition, int shift) + { + BitArray ba = new(length); + ba[bitPosition] = true; + + bool expectedHasAny = bitPosition + shift < length; + ba.LeftShift(shift); + Assert.Equal(expectedHasAny, ba.HasAnySet()); + } + + [Theory] + [MemberData(nameof(Shift_PopCount_TestData))] + public static void RightShift_HasAnySet(int length, int bitPosition, int shift) + { + BitArray ba = new(length); + ba[bitPosition] = true; + + bool expectedHasAny = bitPosition - shift >= 0; + ba.RightShift(shift); + Assert.Equal(expectedHasAny, ba.HasAnySet()); } } } From 066cb7c521b17a2098adc731fcf5bf7fba0cdb60 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 17 Jan 2026 16:53:06 +0000 Subject: [PATCH 4/5] Improve test data generator readability Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../tests/BitArray/BitArray_OperatorsTests.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Collections/tests/BitArray/BitArray_OperatorsTests.cs b/src/libraries/System.Collections/tests/BitArray/BitArray_OperatorsTests.cs index 793d67a7502925..b9396e21cde539 100644 --- a/src/libraries/System.Collections/tests/BitArray/BitArray_OperatorsTests.cs +++ b/src/libraries/System.Collections/tests/BitArray/BitArray_OperatorsTests.cs @@ -390,14 +390,20 @@ public static void PopCount(BitArray array, int expected) public static IEnumerable Shift_PopCount_TestData() { - // Test various lengths that include edge cases around int32 boundaries - foreach (int length in new[] { 1, BitsPerByte, BitsPerInt32 - 1, BitsPerInt32, BitsPerInt32 + 1, 2 * BitsPerInt32, 2 * BitsPerInt32 + 1 }) + // Test lengths that cover edge cases around int32 boundaries + int[] lengths = [1, BitsPerByte, BitsPerInt32 - 1, BitsPerInt32, BitsPerInt32 + 1, 2 * BitsPerInt32, 2 * BitsPerInt32 + 1]; + + foreach (int length in lengths) { - // Test various shift amounts - foreach (int shift in new[] { 1, length / 2, length - 1, length, length + 1 }.Where(s => s > 0).Distinct()) + // Generate valid shift amounts based on array length + int[] shifts = [1, length / 2, length - 1, length, length + 1]; + + // Test with bit set at start, middle, and end positions + int[] bitPositions = length > 1 ? [0, length / 2, length - 1] : [0]; + + foreach (int shift in shifts.Where(s => s > 0).Distinct()) { - // Test with bit set at various positions - foreach (int bitPosition in new[] { 0, length / 2, length - 1 }.Distinct()) + foreach (int bitPosition in bitPositions.Distinct()) { yield return new object[] { length, bitPosition, shift }; } From 611026fd2ee2a43ab948d273d14c770b67fbb902 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Feb 2026 19:58:33 +0000 Subject: [PATCH 5/5] Add ClearHighExtraBits call in deserialization constructor Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../System.Private.CoreLib/src/System/Collections/BitArray.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/BitArray.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/BitArray.cs index 43bb7c4930aa20..a325147a8f0bc5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/BitArray.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/BitArray.cs @@ -98,6 +98,8 @@ private BitArray(SerializationInfo info, StreamingContext context) { BinaryPrimitives.ReverseEndianness(array, MemoryMarshal.Cast((Span)_array)); } + + ClearHighExtraBits(); } /// Generates serialization data for the BitArray in a way that's compatible with the original .NET Framework implementation.