File: src\RoslynAnalyzers\Utilities\FlowAnalysis\FlowAnalysis\Framework\DataFlow\SetAbstractDomain.cs
Web Access
Project: src\src\RoslynAnalyzers\Microsoft.CodeAnalysis.AnalyzerUtilities\Microsoft.CodeAnalysis.AnalyzerUtilities.csproj (Microsoft.CodeAnalysis.AnalyzerUtilities)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Collections.Immutable;
 
#pragma warning disable CA1000 // Do not declare static members on generic types
 
namespace Microsoft.CodeAnalysis.FlowAnalysis.DataFlow
{
    public class SetAbstractDomain<T> : AbstractDomain<ImmutableHashSet<T>>
    {
        private SetAbstractDomain() { }
 
        public static SetAbstractDomain<T> Default { get; } = new SetAbstractDomain<T>();
 
        public override ImmutableHashSet<T> Bottom => ImmutableHashSet<T>.Empty;
 
        public override int Compare(ImmutableHashSet<T> oldValue, ImmutableHashSet<T> newValue, bool assertMonotonicity)
        {
            if (ReferenceEquals(oldValue, newValue))
            {
                return 0;
            }
 
            int result;
            // PERF: Avoid additional hash set allocation by using overload which takes
            // a set argument instead of IEnumerable argument.
            var isSubset = oldValue.IsSubsetOfSet(newValue);
 
            if (isSubset &&
                oldValue.Count == newValue.Count)
            {
                // oldValue == newValue
                result = 0;
            }
            else if (isSubset)
            {
                // oldValue < newValue
                result = -1;
            }
            else
            {
                // oldValue > newValue
                result = 1;
            }
 
            return result;
        }
 
        public override ImmutableHashSet<T> Merge(ImmutableHashSet<T> value1, ImmutableHashSet<T> value2) => MergeOrIntersect(value1, value2, merge: true);
 
        public ImmutableHashSet<T> Intersect(ImmutableHashSet<T> value1, ImmutableHashSet<T> value2) => MergeOrIntersect(value1, value2, merge: false);
 
        private static ImmutableHashSet<T> MergeOrIntersect(ImmutableHashSet<T> value1, ImmutableHashSet<T> value2, bool merge)
        {
            if (value1.IsEmpty)
            {
                return merge ? value2 : value1;
            }
            else if (value2.IsEmpty || ReferenceEquals(value1, value2))
            {
                return merge ? value1 : value2;
            }
 
            // PERF: Avoid additional allocations by using the overload that takes a set argument
            // instead of IEnumerable argument.
            return merge ? ImmutableHashSetExtensions.AddRange(value1, value2) : value1.IntersectSet(value2);
        }
    }
}