From 5eb9ab3a5231e074b9bd505814cd6c6aa0c095ca Mon Sep 17 00:00:00 2001 From: Chris Sienkiewicz Date: Tue, 6 Jul 2021 15:52:11 -0700 Subject: [PATCH] Ensure we don't try and build an empty table when modifying entries with no values (#54639) --- .../SourceGeneration/StateTableTests.cs | 22 +++++++++++++++++++ .../SourceGeneration/Nodes/NodeStateTable.cs | 8 +++++++ 2 files changed, 30 insertions(+) diff --git a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs index e7726b7505f87..2a86998678c58 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs @@ -155,6 +155,28 @@ public void Node_Table_Single_Returns_Second_Item_When_First_Is_Removed() Assert.Equal(2, table.Single()); } + [Fact] + public void Node_Builder_Handles_Modification_When_Both_Tables_Have_Empty_Entries() + { + var builder = NodeStateTable.Empty.ToBuilder(); + builder.AddEntries(ImmutableArray.Create(1, 2), EntryState.Added); + builder.AddEntries(ImmutableArray.Empty, EntryState.Added); + builder.AddEntries(ImmutableArray.Create(3, 4), EntryState.Added); + var previousTable = builder.ToImmutableAndFree(); + + var expected = ImmutableArray.Create((1, EntryState.Added), (2, EntryState.Added), (3, EntryState.Added), (4, EntryState.Added)); + AssertTableEntries(previousTable, expected); + + builder = previousTable.ToBuilder(); + Assert.True(builder.TryModifyEntries(ImmutableArray.Create(3, 2), EqualityComparer.Default)); // ((3, EntryState.Modified), (2, EntryState.Cached)) + Assert.True(builder.TryModifyEntries(ImmutableArray.Empty, EqualityComparer.Default)); // nothing + Assert.True(builder.TryModifyEntries(ImmutableArray.Create(3, 5), EqualityComparer.Default)); // ((3, EntryState.Cached), (5, EntryState.Modified)) + var newTable = builder.ToImmutableAndFree(); + + expected = ImmutableArray.Create((3, EntryState.Modified), (2, EntryState.Cached), (3, EntryState.Cached), (5, EntryState.Modified)); + AssertTableEntries(newTable, expected); + } + [Fact] public void Driver_Table_Calls_Into_Node_With_Self() { diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/NodeStateTable.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/NodeStateTable.cs index 210877d5d4ed2..5b7d5356795a0 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/NodeStateTable.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/NodeStateTable.cs @@ -205,6 +205,14 @@ public bool TryModifyEntries(ImmutableArray outputs, IEqualityComparer com // - Added when new item position < previousTable.length var previousEntry = _previous._states[_states.Count]; + + // when both entries have no items, we can short circuit + if (previousEntry.Count == 0 && outputs.Length == 0) + { + _states.Add(previousEntry); + return true; + } + var modified = new TableEntry.Builder(); var sharedCount = Math.Min(previousEntry.Count, outputs.Length);