File: src\RoslynAnalyzers\Utilities\FlowAnalysis\FlowAnalysis\Analysis\PointsToAnalysis\PointsToAnalysisData.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;
using System.Collections.Generic;
using System.Diagnostics;
 
namespace Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.PointsToAnalysis
{
    using CorePointsToAnalysisData = DictionaryAnalysisData<AnalysisEntity, PointsToAbstractValue>;
 
    /// <summary>
    /// Aggregated PointsTo analysis data tracked by <see cref="PointsToAnalysis"/>.
    /// Contains the <see cref="CorePointsToAnalysisData"/> for entity PointsTo values and
    /// the predicated values based on true/false runtime values of predicated entities.
    /// </summary>
    public sealed class PointsToAnalysisData : AnalysisEntityBasedPredicateAnalysisData<PointsToAbstractValue>
    {
        private readonly Func<ITypeSymbol?, bool> _isDisposable;
 
        internal PointsToAnalysisData(Func<ITypeSymbol?, bool> isDisposable)
        {
            _isDisposable = isDisposable;
        }
 
        internal PointsToAnalysisData(IDictionary<AnalysisEntity, PointsToAbstractValue> fromData, Func<ITypeSymbol?, bool> isDisposable)
            : base(fromData)
        {
            _isDisposable = isDisposable;
 
            AssertValidPointsToAnalysisData(fromData, isDisposable);
        }
 
        internal PointsToAnalysisData(
            CorePointsToAnalysisData mergedCoreAnalysisData,
            PredicatedAnalysisData<AnalysisEntity, PointsToAbstractValue> predicatedData1,
            PredicatedAnalysisData<AnalysisEntity, PointsToAbstractValue> predicatedData2,
            bool isReachableData,
            MapAbstractDomain<AnalysisEntity, PointsToAbstractValue> coreDataAnalysisDomain,
            Func<ITypeSymbol?, bool> isDisposable)
            : base(mergedCoreAnalysisData, predicatedData1, predicatedData2, isReachableData, coreDataAnalysisDomain)
        {
            _isDisposable = isDisposable;
 
            AssertValidPointsToAnalysisData(mergedCoreAnalysisData, isDisposable);
            AssertValidPointsToAnalysisData();
        }
 
        private PointsToAnalysisData(PointsToAnalysisData fromData)
            : base(fromData)
        {
            _isDisposable = fromData._isDisposable;
 
            fromData.AssertValidPointsToAnalysisData();
        }
 
        private PointsToAnalysisData(PointsToAnalysisData data1, PointsToAnalysisData data2, MapAbstractDomain<AnalysisEntity, PointsToAbstractValue> coreDataAnalysisDomain)
            : base(data1, data2, coreDataAnalysisDomain)
        {
            _isDisposable = data1._isDisposable;
 
            data1.AssertValidPointsToAnalysisData();
            data2.AssertValidPointsToAnalysisData();
            AssertValidPointsToAnalysisData();
        }
 
        protected override AbstractValueDomain<PointsToAbstractValue> ValueDomain => PointsToAnalysis.ValueDomainInstance;
        public override AnalysisEntityBasedPredicateAnalysisData<PointsToAbstractValue> Clone() => new PointsToAnalysisData(this);
 
        public override int Compare(AnalysisEntityBasedPredicateAnalysisData<PointsToAbstractValue> other, MapAbstractDomain<AnalysisEntity, PointsToAbstractValue> coreDataAnalysisDomain)
            => BaseCompareHelper(other, coreDataAnalysisDomain);
 
        public override AnalysisEntityBasedPredicateAnalysisData<PointsToAbstractValue> WithMergedData(AnalysisEntityBasedPredicateAnalysisData<PointsToAbstractValue> data, MapAbstractDomain<AnalysisEntity, PointsToAbstractValue> coreDataAnalysisDomain)
        {
            Debug.Assert(IsReachableBlockData || !data.IsReachableBlockData);
            var mergedData = new PointsToAnalysisData(this, (PointsToAnalysisData)data, coreDataAnalysisDomain);
            mergedData.AssertValidPointsToAnalysisData();
            return mergedData;
        }
 
        public override void SetAbstractValue(AnalysisEntity key, PointsToAbstractValue value)
        {
            AssertValidPointsToAnalysisKeyValuePair(key, value, _isDisposable);
            base.SetAbstractValue(key, value);
        }
 
        public override void Reset(Func<AnalysisEntity, PointsToAbstractValue, PointsToAbstractValue> getResetValue)
        {
            base.Reset(getResetValue);
            AssertValidPointsToAnalysisData();
        }
 
        [Conditional("DEBUG")]
        internal void AssertNoFlowCaptureEntitiesTracked()
        {
            AssertNoFlowCaptureEntitiesTracked(CoreAnalysisData);
#pragma warning disable IDE0200 // Remove unnecessary lambda expression - https://github.com/dotnet/roslyn/issues/63464
            AssertValidPredicatedAnalysisData(map => AssertNoFlowCaptureEntitiesTracked(map));
#pragma warning restore IDE0200 // Remove unnecessary lambda expression
        }
 
        [Conditional("DEBUG")]
        private static void AssertNoFlowCaptureEntitiesTracked(CorePointsToAnalysisData map)
        {
            foreach (var key in map.Keys)
            {
                Debug.Assert(key.CaptureId == null);
            }
        }
 
        [Conditional("DEBUG")]
        internal void AssertValidPointsToAnalysisData()
        {
            AssertValidPointsToAnalysisData(CoreAnalysisData, _isDisposable);
#pragma warning disable IDE0200 // Remove unnecessary lambda expression - https://github.com/dotnet/roslyn/issues/63464
            AssertValidPredicatedAnalysisData(map => AssertValidPointsToAnalysisData(map, _isDisposable));
#pragma warning restore IDE0200 // Remove unnecessary lambda expression
        }
 
        [Conditional("DEBUG")]
        internal static void AssertValidPointsToAnalysisData(IDictionary<AnalysisEntity, PointsToAbstractValue> map, Func<ITypeSymbol?, bool> isDisposable)
        {
            if (map is CorePointsToAnalysisData corePointsToAnalysisData)
            {
                Debug.Assert(!corePointsToAnalysisData.IsDisposed);
            }
 
            foreach (var kvp in map)
            {
                AssertValidPointsToAnalysisKeyValuePair(kvp.Key, kvp.Value, isDisposable);
            }
        }
 
        [Conditional("DEBUG")]
        internal static void AssertValidPointsToAnalysisKeyValuePair(
            AnalysisEntity key,
            PointsToAbstractValue value,
            Func<ITypeSymbol?, bool> isDisposable)
        {
            Debug.Assert(value.Kind != PointsToAbstractValueKind.Undefined);
            Debug.Assert(!key.IsLValueFlowCaptureEntity || value.Kind == PointsToAbstractValueKind.KnownLValueCaptures);
            Debug.Assert(PointsToAnalysis.ShouldBeTracked(key, PointsToAnalysisKind.Complete, isDisposable));
        }
    }
}