File: src\RoslynAnalyzers\Utilities\FlowAnalysis\FlowAnalysis\Analysis\ParameterValidationAnalysis\ParameterValidationAnalysisContext.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.Diagnostics;
using Analyzer.Utilities;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.CopyAnalysis;
using Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.PointsToAnalysis;
using Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.ValueContentAnalysis;
 
namespace Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.ParameterValidationAnalysis
{
    using CopyAnalysisResult = DataFlowAnalysisResult<CopyBlockAnalysisResult, CopyAbstractValue>;
    using InterproceduralParameterValidationAnalysisData = InterproceduralAnalysisData<DictionaryAnalysisData<AbstractLocation, ParameterValidationAbstractValue>, ParameterValidationAnalysisContext, ParameterValidationAbstractValue>;
    using ParameterValidationAnalysisData = DictionaryAnalysisData<AbstractLocation, ParameterValidationAbstractValue>;
    using ValueContentAnalysisResult = DataFlowAnalysisResult<ValueContentBlockAnalysisResult, ValueContentAbstractValue>;
 
    /// <summary>
    /// Analysis context for execution of <see cref="ParameterValidationAnalysis"/> on a control flow graph.
    /// </summary>
    internal sealed class ParameterValidationAnalysisContext : AbstractDataFlowAnalysisContext<ParameterValidationAnalysisData, ParameterValidationAnalysisContext, ParameterValidationAnalysisResult, ParameterValidationAbstractValue>
    {
        private ParameterValidationAnalysisContext(
            AbstractValueDomain<ParameterValidationAbstractValue> valueDomain,
            WellKnownTypeProvider wellKnownTypeProvider,
            ControlFlowGraph controlFlowGraph,
            ISymbol owningSymbol,
            AnalyzerOptions analyzerOptions,
            SymbolNamesWithValueOption<Unit> nullCheckValidationMethods,
            InterproceduralAnalysisConfiguration interproceduralAnalysisConfig,
            bool pessimisticAnalysis,
            PointsToAnalysisResult? pointsToAnalysisResult,
            Func<ParameterValidationAnalysisContext, ParameterValidationAnalysisResult?> tryGetOrComputeAnalysisResult,
            ControlFlowGraph? parentControlFlowGraph,
            InterproceduralParameterValidationAnalysisData? interproceduralAnalysisData,
            bool trackHazardousParameterUsages)
            : base(valueDomain, wellKnownTypeProvider, controlFlowGraph, owningSymbol, analyzerOptions, interproceduralAnalysisConfig,
                  pessimisticAnalysis, predicateAnalysis: false, exceptionPathsAnalysis: false,
                  copyAnalysisResult: null, pointsToAnalysisResult, valueContentAnalysisResult: null,
                  tryGetOrComputeAnalysisResult, parentControlFlowGraph, interproceduralAnalysisData,
                  interproceduralAnalysisPredicate: null)
        {
            TrackHazardousParameterUsages = trackHazardousParameterUsages;
            NullCheckValidationMethodNames = nullCheckValidationMethods;
        }
 
        public static ParameterValidationAnalysisContext Create(
            AbstractValueDomain<ParameterValidationAbstractValue> valueDomain,
            WellKnownTypeProvider wellKnownTypeProvider,
            ControlFlowGraph controlFlowGraph,
            ISymbol owningSymbol,
            AnalyzerOptions analyzerOptions,
            SymbolNamesWithValueOption<Unit> nullCheckValidationMethods,
            InterproceduralAnalysisConfiguration interproceduralAnalysisConfig,
            bool pessimisticAnalysis,
            PointsToAnalysisResult? pointsToAnalysisResult,
            Func<ParameterValidationAnalysisContext, ParameterValidationAnalysisResult?> tryGetOrComputeAnalysisResult)
        {
            return new ParameterValidationAnalysisContext(
                valueDomain, wellKnownTypeProvider, controlFlowGraph, owningSymbol,
                analyzerOptions, nullCheckValidationMethods, interproceduralAnalysisConfig,
                pessimisticAnalysis, pointsToAnalysisResult, tryGetOrComputeAnalysisResult, parentControlFlowGraph: null,
                interproceduralAnalysisData: null, trackHazardousParameterUsages: false);
        }
 
        public override ParameterValidationAnalysisContext ForkForInterproceduralAnalysis(
            IMethodSymbol invokedMethod,
            ControlFlowGraph invokedCfg,
            PointsToAnalysisResult? pointsToAnalysisResult,
            CopyAnalysisResult? copyAnalysisResult,
            ValueContentAnalysisResult? valueContentAnalysisResult,
            InterproceduralParameterValidationAnalysisData? interproceduralAnalysisData)
        {
            Debug.Assert(pointsToAnalysisResult != null);
            Debug.Assert(copyAnalysisResult == null);
            Debug.Assert(valueContentAnalysisResult == null);
 
            // Do not invoke any interprocedural analysis more than one level down.
            // We only care about analyzing validation methods.
            return new ParameterValidationAnalysisContext(
                ValueDomain, WellKnownTypeProvider, invokedCfg, invokedMethod, AnalyzerOptions,
                NullCheckValidationMethodNames, InterproceduralAnalysisConfiguration,
                PessimisticAnalysis, pointsToAnalysisResult, TryGetOrComputeAnalysisResult, ControlFlowGraph,
                interproceduralAnalysisData, TrackHazardousParameterUsages);
        }
 
        public ParameterValidationAnalysisContext WithTrackHazardousParameterUsages()
            => new(
                ValueDomain, WellKnownTypeProvider, ControlFlowGraph,
                OwningSymbol, AnalyzerOptions, NullCheckValidationMethodNames,
                InterproceduralAnalysisConfiguration, PessimisticAnalysis,
                PointsToAnalysisResult, TryGetOrComputeAnalysisResult, ParentControlFlowGraph,
                InterproceduralAnalysisData, trackHazardousParameterUsages: true);
 
        public bool TrackHazardousParameterUsages { get; }
 
        private SymbolNamesWithValueOption<Unit> NullCheckValidationMethodNames { get; }
        public bool IsNullCheckValidationMethod(IMethodSymbol method)
            => NullCheckValidationMethodNames.Contains(method);
 
        protected override void ComputeHashCodePartsSpecific(ref RoslynHashCode hashCode)
        {
            hashCode.Add(TrackHazardousParameterUsages.GetHashCode());
            hashCode.Add(NullCheckValidationMethodNames.GetHashCode());
        }
 
        protected override bool ComputeEqualsByHashCodeParts(AbstractDataFlowAnalysisContext<ParameterValidationAnalysisData, ParameterValidationAnalysisContext, ParameterValidationAnalysisResult, ParameterValidationAbstractValue> obj)
        {
            var other = (ParameterValidationAnalysisContext)obj;
            return TrackHazardousParameterUsages.GetHashCode() == other.TrackHazardousParameterUsages.GetHashCode()
                && NullCheckValidationMethodNames.GetHashCode() == other.NullCheckValidationMethodNames.GetHashCode();
        }
    }
}