File: src\RoslynAnalyzers\Utilities\FlowAnalysis\FlowAnalysis\Framework\DataFlow\InterproceduralAnalysisData.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.Immutable;
using Analyzer.Utilities;
using Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.CopyAnalysis;
using Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.PointsToAnalysis;
 
namespace Microsoft.CodeAnalysis.FlowAnalysis.DataFlow
{
    /// <summary>
    /// Contains the caller's analysis context data passed to context sensitive interprocedural analysis, <see cref="InterproceduralAnalysisKind.ContextSensitive"/>.
    /// This includes the following:
    /// 1. Caller's tracked analysis data at the call site, which is the initial analysis data for callee.
    /// 2. Information about the invocation instance on which the method is invoked.
    /// 3. Information about arguments for the invocation.
    /// 4. Captured variables (for lambda/local function invocations).
    /// 5. Information about ref/out parameter entities that share address with callee's parameters.
    /// 6. Operation call stack for the current interprocedural analysis.
    /// 7. Set of analysis contexts currently being analyzed.
    /// </summary>
    public sealed class InterproceduralAnalysisData<TAnalysisData, TAnalysisContext, TAbstractAnalysisValue>
        : CacheBasedEquatable<InterproceduralAnalysisData<TAnalysisData, TAnalysisContext, TAbstractAnalysisValue>>
        where TAnalysisContext : class, IDataFlowAnalysisContext
        where TAnalysisData : AbstractAnalysisData
    {
        public InterproceduralAnalysisData(
            TAnalysisData? initialAnalysisData,
            (AnalysisEntity?, PointsToAbstractValue)? invocationInstance,
            (AnalysisEntity, PointsToAbstractValue)? thisOrMeInstanceForCaller,
            ImmutableDictionary<IParameterSymbol, ArgumentInfo<TAbstractAnalysisValue>> argumentValuesMap,
            ImmutableDictionary<ISymbol, PointsToAbstractValue> capturedVariablesMap,
            ImmutableDictionary<AnalysisEntity, CopyAbstractValue> addressSharedEntities,
            ImmutableStack<IOperation> callStack,
            ImmutableHashSet<TAnalysisContext> methodsBeingAnalyzed,
            Func<IOperation, TAbstractAnalysisValue> getCachedAbstractValueFromCaller,
            Func<IMethodSymbol, ControlFlowGraph?> getInterproceduralControlFlowGraph,
            Func<IOperation, AnalysisEntity?> getAnalysisEntityForFlowCapture,
            Func<ISymbol, ImmutableStack<IOperation>?> getInterproceduralCallStackForOwningSymbol)
        {
            InitialAnalysisData = initialAnalysisData;
            InvocationInstance = invocationInstance;
            ThisOrMeInstanceForCaller = thisOrMeInstanceForCaller;
            ArgumentValuesMap = argumentValuesMap;
            CapturedVariablesMap = capturedVariablesMap;
            AddressSharedEntities = addressSharedEntities;
            CallStack = callStack;
            MethodsBeingAnalyzed = methodsBeingAnalyzed;
            GetCachedAbstractValueFromCaller = getCachedAbstractValueFromCaller;
            GetInterproceduralControlFlowGraph = getInterproceduralControlFlowGraph;
            GetAnalysisEntityForFlowCapture = getAnalysisEntityForFlowCapture;
            GetInterproceduralCallStackForOwningSymbol = getInterproceduralCallStackForOwningSymbol;
        }
 
        public TAnalysisData? InitialAnalysisData { get; }
        public (AnalysisEntity? Instance, PointsToAbstractValue PointsToValue)? InvocationInstance { get; }
        public (AnalysisEntity Instance, PointsToAbstractValue PointsToValue)? ThisOrMeInstanceForCaller { get; }
        public ImmutableDictionary<IParameterSymbol, ArgumentInfo<TAbstractAnalysisValue>> ArgumentValuesMap { get; }
        public ImmutableDictionary<ISymbol, PointsToAbstractValue> CapturedVariablesMap { get; }
        public ImmutableDictionary<AnalysisEntity, CopyAbstractValue> AddressSharedEntities { get; }
        public ImmutableStack<IOperation> CallStack { get; }
        public ImmutableHashSet<TAnalysisContext> MethodsBeingAnalyzed { get; }
        public Func<IOperation, TAbstractAnalysisValue> GetCachedAbstractValueFromCaller { get; }
        public Func<IMethodSymbol, ControlFlowGraph?> GetInterproceduralControlFlowGraph { get; }
        public Func<IOperation, AnalysisEntity?> GetAnalysisEntityForFlowCapture { get; }
        public Func<ISymbol, ImmutableStack<IOperation>?> GetInterproceduralCallStackForOwningSymbol { get; }
 
        protected override void ComputeHashCodeParts(ref RoslynHashCode hashCode)
        {
            hashCode.Add(InitialAnalysisData.GetHashCodeOrDefault());
            AddHashCodeParts(InvocationInstance, ref hashCode);
            AddHashCodeParts(ThisOrMeInstanceForCaller, ref hashCode);
            hashCode.Add(HashUtilities.Combine(ArgumentValuesMap));
            hashCode.Add(HashUtilities.Combine(CapturedVariablesMap));
            hashCode.Add(HashUtilities.Combine(AddressSharedEntities));
            hashCode.Add(HashUtilities.Combine(CallStack));
            hashCode.Add(HashUtilities.Combine(MethodsBeingAnalyzed));
        }
 
        protected override bool ComputeEqualsByHashCodeParts(CacheBasedEquatable<InterproceduralAnalysisData<TAnalysisData, TAnalysisContext, TAbstractAnalysisValue>> obj)
        {
            var other = (InterproceduralAnalysisData<TAnalysisData, TAnalysisContext, TAbstractAnalysisValue>)obj;
            return InitialAnalysisData.GetHashCodeOrDefault() == other.InitialAnalysisData.GetHashCodeOrDefault()
                && EqualsByHashCodeParts(InvocationInstance, other.InvocationInstance)
                && EqualsByHashCodeParts(ThisOrMeInstanceForCaller, other.ThisOrMeInstanceForCaller)
                && HashUtilities.Combine(ArgumentValuesMap) == HashUtilities.Combine(other.ArgumentValuesMap)
                && HashUtilities.Combine(CapturedVariablesMap) == HashUtilities.Combine(other.CapturedVariablesMap)
                && HashUtilities.Combine(AddressSharedEntities) == HashUtilities.Combine(other.AddressSharedEntities)
                && HashUtilities.Combine(CallStack) == HashUtilities.Combine(other.CallStack)
                && HashUtilities.Combine(MethodsBeingAnalyzed) == HashUtilities.Combine(other.MethodsBeingAnalyzed);
        }
 
        private static void AddHashCodeParts(
            (AnalysisEntity? Instance, PointsToAbstractValue PointsToValue)? instanceAndPointsToValue,
            ref RoslynHashCode hashCode)
        {
            if (instanceAndPointsToValue.HasValue)
            {
                hashCode.Add(instanceAndPointsToValue.Value.Instance.GetHashCodeOrDefault());
                hashCode.Add(instanceAndPointsToValue.Value.PointsToValue.GetHashCode());
            }
            else
            {
                hashCode.Add(0);
            }
        }
 
        private static bool EqualsByHashCodeParts(
            (AnalysisEntity? Instance, PointsToAbstractValue PointsToValue)? left,
            (AnalysisEntity? Instance, PointsToAbstractValue PointsToValue)? right)
        {
            if (left is null)
                return right is null;
            else if (right is null)
                return false;
 
            return left.Value.Instance.GetHashCodeOrDefault() == right.Value.Instance.GetHashCodeOrDefault()
                && left.Value.PointsToValue.GetHashCode() == right.Value.PointsToValue.GetHashCode();
        }
    }
}