File: src\RoslynAnalyzers\Utilities\FlowAnalysis\FlowAnalysis\Analysis\PropertySetAnalysis\PropertyMapper.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 Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.PointsToAnalysis;
using Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.ValueContentAnalysis;
 
namespace Analyzer.Utilities.FlowAnalysis.Analysis.PropertySetAnalysis
{
    /// <summary>
    /// Information for mapping an object's property's assigned value to a <see cref="PropertySetAbstractValueKind"/>.
    /// </summary>
#pragma warning disable CA1812 // Is too instantiated.
    internal sealed class PropertyMapper
#pragma warning restore CA1812
    {
        /// <summary>
        /// Mapping from <see cref="ValueContentAbstractValue"/> to a <see cref="PropertySetAbstractValueKind"/>
        /// </summary>
        /// <param name="valueContentAbstractValue">Property's assigned value's <see cref="ValueContentAbstractValue"/>.</param>
        /// <returns>What the property's assigned value should map to.</returns>
        public delegate PropertySetAbstractValueKind ValueContentAbstractValueCallback(ValueContentAbstractValue valueContentAbstractValue);
 
        /// <summary>
        /// Mapping from <see cref="PointsToAbstractValue"/> to a <see cref="PropertySetAbstractValueKind"/>
        /// </summary>
        /// <param name="pointsToAbstractValue">Property's assigned value's <see cref="PointsToAbstractValue"/>.</param>
        /// <returns>What the property's assigned value should map to.</returns>
        public delegate PropertySetAbstractValueKind PointsToAbstractValueCallback(PointsToAbstractValue pointsToAbstractValue);
 
        /// <summary>
        /// Initializes a <see cref="PropertyMapper"/> that maps a property's assigned value's <see cref="ValueContentAbstractValue"/> to a <see cref="PropertySetAbstractValueKind"/>.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="mapFromValueContentAbstractValueCallback">Callback that implements the mapping.</param>
        public PropertyMapper(string propertyName, ValueContentAbstractValueCallback mapFromValueContentAbstractValueCallback)
        {
            PropertyName = propertyName ?? throw new ArgumentNullException(nameof(propertyName));
            MapFromValueContentAbstractValue = mapFromValueContentAbstractValueCallback ?? throw new ArgumentNullException(nameof(mapFromValueContentAbstractValueCallback));
        }
 
        /// <summary>
        /// Initializes a <see cref="PropertyMapper"/> that maps a property's assigned value's <see cref="ValueContentAbstractValue"/> to a <see cref="PropertySetAbstractValueKind"/>.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="mapFromValueContentAbstractValueCallback">Callback that implements the mapping.</param>
        /// <param name="propertyIndex">Internal index into the <see cref="PropertySetAbstractValueKind"/> array.</param>
        /// <remarks>This overload is useful if there are properties that effectively aliases of the same underlying value.</remarks>
        public PropertyMapper(string propertyName, ValueContentAbstractValueCallback mapFromValueContentAbstractValueCallback, int propertyIndex)
        {
            PropertyName = propertyName ?? throw new ArgumentNullException(nameof(propertyName));
            MapFromValueContentAbstractValue = mapFromValueContentAbstractValueCallback ?? throw new ArgumentNullException(nameof(mapFromValueContentAbstractValueCallback));
            PropertyIndex = propertyIndex;
            if (propertyIndex < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(propertyIndex), "propertyIndex must be non-negative");
            }
        }
 
        /// <summary>
        /// Initializes a <see cref="PropertyMapper"/> that maps a property's assigned value's <see cref="NullAbstractValue"/> to a <see cref="PropertySetAbstractValueKind"/>.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="mapFromPointsToAbstractValueCallback">Callback that implements the mapping.</param>
        public PropertyMapper(string propertyName, PointsToAbstractValueCallback mapFromPointsToAbstractValueCallback)
        {
            PropertyName = propertyName ?? throw new ArgumentNullException(nameof(propertyName));
            MapFromPointsToAbstractValue = mapFromPointsToAbstractValueCallback ?? throw new ArgumentNullException(nameof(mapFromPointsToAbstractValueCallback));
        }
 
        /// <summary>
        /// Initializes a <see cref="PropertyMapper"/> that maps a property's assigned value's <see cref="NullAbstractValue"/> to a <see cref="PropertySetAbstractValueKind"/>.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="mapFromPointsToAbstractValueCallback">Callback that implements the mapping.</param>
        /// <param name="propertyIndex">Internal index into the <see cref="PropertySetAbstractValueKind"/> array.</param>
        /// <remarks>This overload is useful if there are properties that effectively aliases of the same underlying value.</remarks>
        public PropertyMapper(string propertyName, PointsToAbstractValueCallback mapFromPointsToAbstractValueCallback, int propertyIndex)
        {
            PropertyName = propertyName ?? throw new ArgumentNullException(nameof(propertyName));
            MapFromPointsToAbstractValue = mapFromPointsToAbstractValueCallback ?? throw new ArgumentNullException(nameof(mapFromPointsToAbstractValueCallback));
            PropertyIndex = propertyIndex;
            if (propertyIndex < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(propertyIndex), "propertyIndex must be non-negative");
            }
        }
 
        /// <summary>
        /// Doesn't construct.
        /// </summary>
        private PropertyMapper()
        {
            throw new NotSupportedException();
        }
 
        /// <summary>
        /// Name of the property.
        /// </summary>
        internal string PropertyName { get; }
 
        internal int PropertyIndex { get; } = -1;
 
        /// <summary>
        /// Callback for mapping from <see cref="ValueContentAbstractValue"/> to a <see cref="PropertySetAbstractValueKind"/>, or null.
        /// </summary>
        internal ValueContentAbstractValueCallback? MapFromValueContentAbstractValue { get; }
 
        /// <summary>
        /// Callback for mapping from <see cref="PointsToAbstractValue"/> to a <see cref="PropertySetAbstractValueKind"/>, or null.
        /// </summary>
        internal PointsToAbstractValueCallback? MapFromPointsToAbstractValue { get; }
 
        /// <summary>
        /// Indicates that this <see cref="PropertyMapper"/> uses <see cref="ValueContentAbstractValue"/>s.
        /// </summary>
        internal bool RequiresValueContentAnalysis => this.MapFromValueContentAbstractValue != null;
 
        public override int GetHashCode()
        {
            return RoslynHashCode.Combine(
                this.PropertyName.GetHashCodeOrDefault(),
                this.MapFromValueContentAbstractValue.GetHashCodeOrDefault(),
                this.MapFromPointsToAbstractValue.GetHashCodeOrDefault());
        }
 
        public override bool Equals(object obj)
        {
            return this.Equals(obj as PropertyMapper);
        }
 
        public bool Equals(PropertyMapper? other)
        {
            return other != null
                && this.PropertyName == other.PropertyName
                && this.MapFromValueContentAbstractValue == other.MapFromValueContentAbstractValue
                && this.MapFromPointsToAbstractValue == other.MapFromPointsToAbstractValue;
        }
    }
}