| File: src\11b41c7305441175\PropertySetAbstractValue.cs | Web Access |
| Project: src\sdk\src\Microsoft.CodeAnalysis.NetAnalyzers\src\Microsoft.CodeAnalysis.NetAnalyzers\Microsoft.CodeAnalysis.NetAnalyzers.csproj (Microsoft.CodeAnalysis.NetAnalyzers) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using Analyzer.Utilities.PooledObjects; namespace Analyzer.Utilities.FlowAnalysis.Analysis.PropertySetAnalysis { /// <summary> /// Abstract value for a set properties on an object instance, with each /// individual property represented by a <see /// cref="PropertySetAbstractValueKind"/>. /// </summary> /// <remarks> /// Note that <see cref="KnownPropertyAbstractValues"/> may be /// "incomplete", i.e. it doesn't cover all properties. In such cases, /// missing elements are implicitly <see /// cref="PropertySetAbstractValueKind.Unknown"/>. /// /// The reason for the "sparse" array is so that the Unknown value doesn't /// have to be aware of how many properties are being tracked. /// </remarks> internal partial class PropertySetAbstractValue { public static readonly PropertySetAbstractValue Unknown = new(); private static readonly ValuePool Pool = new(); public static PropertySetAbstractValue GetInstance(PropertySetAbstractValueKind v1) { return Pool.GetInstance(v1); } public static PropertySetAbstractValue GetInstance(PropertySetAbstractValueKind v1, PropertySetAbstractValueKind v2) { return Pool.GetInstance(v1, v2); } public static PropertySetAbstractValue GetInstance(ArrayBuilder<PropertySetAbstractValueKind> propertyAbstractValues) { if (TryGetPooledInstance(propertyAbstractValues, out PropertySetAbstractValue? instance)) { return instance; } else { return new PropertySetAbstractValue(propertyAbstractValues.ToImmutable()); } } public static PropertySetAbstractValue GetInstance(ImmutableArray<PropertySetAbstractValueKind> propertyAbstractValues) { if (TryGetPooledInstance(propertyAbstractValues, out PropertySetAbstractValue? instance)) { return instance; } else { return new PropertySetAbstractValue(propertyAbstractValues); } } private static bool TryGetPooledInstance(IReadOnlyList<PropertySetAbstractValueKind> values, [NotNullWhen(returnValue: true)] out PropertySetAbstractValue? instance) { if (values.Count == 0) { instance = Unknown; return true; } else if (values.Count == 1) { instance = Pool.GetInstance(values[0]); return true; } else if (values.Count == 2) { instance = Pool.GetInstance(values[0], values[1]); return true; } else { for (int i = 2; i < values.Count; i++) { if (values[i] != PropertySetAbstractValueKind.Unknown) { instance = null; return false; } } instance = Pool.GetInstance(values[0], values[1]); return true; } } private PropertySetAbstractValue(ImmutableArray<PropertySetAbstractValueKind> propertyAbstractValues) { this.KnownPropertyAbstractValues = propertyAbstractValues; } private PropertySetAbstractValue() { this.KnownPropertyAbstractValues = ImmutableArray<PropertySetAbstractValueKind>.Empty; } /// <summary> /// Individual values of the set of properties being tracked. /// </summary> /// <remarks> /// Order of the array is the same as the provided <see cref="PropertyMapper"/>s. /// </remarks> private ImmutableArray<PropertySetAbstractValueKind> KnownPropertyAbstractValues { get; } /// <summary> /// Count of how many properties' abstract values are tracked by this instance. /// </summary> public int KnownValuesCount => this.KnownPropertyAbstractValues.Length; /// <summary> /// Gets an individual property's <see cref="PropertySetAbstractValueKind"/>. /// </summary> /// <param name="index">Index of the property, from the corresponding /// <see cref="PropertyMapperCollection"/>'s initialization.</param> /// <returns>The property's <see cref="PropertySetAbstractValueKind"/>.</returns> /// <remarks>If accessing an index greater than or equal to KnownValuesCount, the property's /// abstract value is implicitly <see cref="PropertySetAbstractValueKind.Unknown"/>.</remarks> public PropertySetAbstractValueKind this[int index] { get { if (index < 0) { throw new ArgumentOutOfRangeException(nameof(index)); } if (index >= this.KnownValuesCount) { return PropertySetAbstractValueKind.Unknown; } else { return this.KnownPropertyAbstractValues[index]; } } } internal PropertySetAbstractValue ReplaceAt(int index, PropertySetAbstractValueKind kind) { Debug.Assert(index >= 0); int newLength; if (index >= this.KnownPropertyAbstractValues.Length) { newLength = index + 1; } else { newLength = this.KnownPropertyAbstractValues.Length; } using ArrayBuilder<PropertySetAbstractValueKind> kinds = ArrayBuilder<PropertySetAbstractValueKind>.GetInstance(newLength); kinds.AddRange(this.KnownPropertyAbstractValues); while (kinds.Count < newLength) { kinds.Add(PropertySetAbstractValueKind.Unknown); } kinds[index] = kind; return GetInstance(kinds); } } }