diff --git a/src/Utilities/FlowAnalysis/FlowAnalysis/Framework/DataFlow/AnalysisEntityBasedPredicateAnalysisData.cs b/src/Utilities/FlowAnalysis/FlowAnalysis/Framework/DataFlow/AnalysisEntityBasedPredicateAnalysisData.cs index 5061463415..3542b71241 100644 --- a/src/Utilities/FlowAnalysis/FlowAnalysis/Framework/DataFlow/AnalysisEntityBasedPredicateAnalysisData.cs +++ b/src/Utilities/FlowAnalysis/FlowAnalysis/Framework/DataFlow/AnalysisEntityBasedPredicateAnalysisData.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; +using Analyzer.Utilities.PooledObjects; namespace Microsoft.CodeAnalysis.FlowAnalysis.DataFlow { @@ -170,6 +171,11 @@ private void ClearOverlappingAnalysisDataForIndexedEntity(AnalysisEntity analysi return; } + // Collect all the overlapping indexed entities whose value needs to be updated into a builder. + // Ensure that we perform these state updates after the foreach loop to avoid modifying the + // underlying CoreAnalysisData within the loop. + // See https://github.com/dotnet/roslyn-analyzers/issues/6929 for more details. + using var builder = ArrayBuilder<(AnalysisEntity, TValue)>.GetInstance(CoreAnalysisData.Count); foreach (var entity in CoreAnalysisData.Keys) { if (entity.Indices.Length != analysisEntity.Indices.Length || @@ -197,10 +203,15 @@ private void ClearOverlappingAnalysisDataForIndexedEntity(AnalysisEntity analysi var mergedValue = ValueDomain.Merge(value, existingValue); if (!existingValue!.Equals(mergedValue)) { - SetAbstractValue(entity, mergedValue); + builder.Add((entity, mergedValue)); } } } + + foreach (var (entity, newValue) in builder.AsEnumerable()) + { + SetAbstractValue(entity, newValue); + } } protected override void Dispose(bool disposing)