| File: src\afc74d572e54ec72\DisposeAnalysis.DisposeAbstractValueDomain.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.Diagnostics; namespace Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.DisposeAnalysis { using DisposeAnalysisData = DictionaryAnalysisData<AbstractLocation, DisposeAbstractValue>; public partial class DisposeAnalysis : ForwardDataFlowAnalysis<DisposeAnalysisData, DisposeAnalysisContext, DisposeAnalysisResult, DisposeBlockAnalysisResult, DisposeAbstractValue> { /// <summary> /// Abstract value domain for <see cref="DisposeAnalysis"/> to merge and compare <see cref="DisposeAbstractValue"/> values. /// </summary> private sealed class DisposeAbstractValueDomain : AbstractValueDomain<DisposeAbstractValue> { public static DisposeAbstractValueDomain Default = new(); private readonly SetAbstractDomain<IOperation> _disposingOperationsDomain = SetAbstractDomain<IOperation>.Default; private DisposeAbstractValueDomain() { } public override DisposeAbstractValue Bottom => DisposeAbstractValue.NotDisposable; public override DisposeAbstractValue UnknownOrMayBeValue => DisposeAbstractValue.Unknown; public override int Compare(DisposeAbstractValue oldValue, DisposeAbstractValue newValue, bool assertMonotonicity) { if (ReferenceEquals(oldValue, newValue)) { return 0; } if (oldValue.Kind == newValue.Kind) { return _disposingOperationsDomain.Compare(oldValue.DisposingOrEscapingOperations, newValue.DisposingOrEscapingOperations); } else if (oldValue.Kind < newValue.Kind || newValue.Kind == DisposeAbstractValueKind.Invalid || newValue.Kind == DisposeAbstractValueKind.Disposed) { return -1; } else { FireNonMonotonicAssertIfNeeded(assertMonotonicity); return 1; } } public override DisposeAbstractValue Merge(DisposeAbstractValue value1, DisposeAbstractValue value2) { if (value1 == null) { return value2; } else if (value2 == null) { return value1; } else if (value1.Kind == DisposeAbstractValueKind.Invalid) { return value2; } else if (value2.Kind == DisposeAbstractValueKind.Invalid) { return value1; } else if (value1.Kind == DisposeAbstractValueKind.NotDisposable || value2.Kind == DisposeAbstractValueKind.NotDisposable) { return DisposeAbstractValue.NotDisposable; } else if (value1.Kind == DisposeAbstractValueKind.Unknown || value2.Kind == DisposeAbstractValueKind.Unknown) { return DisposeAbstractValue.Unknown; } else if (value1.Kind == DisposeAbstractValueKind.NotDisposed && value2.Kind == DisposeAbstractValueKind.NotDisposed) { return DisposeAbstractValue.NotDisposed; } var mergedDisposingOperations = _disposingOperationsDomain.Merge(value1.DisposingOrEscapingOperations, value2.DisposingOrEscapingOperations); Debug.Assert(!mergedDisposingOperations.IsEmpty); return new DisposeAbstractValue(mergedDisposingOperations, GetMergedKind()); // Local functions. DisposeAbstractValueKind GetMergedKind() { Debug.Assert(!value1.DisposingOrEscapingOperations.IsEmpty || !value2.DisposingOrEscapingOperations.IsEmpty); if (value1.Kind == value2.Kind) { return value1.Kind; } else if (value1.Kind == DisposeAbstractValueKind.MaybeDisposed || value2.Kind == DisposeAbstractValueKind.MaybeDisposed) { return DisposeAbstractValueKind.MaybeDisposed; } switch (value1.Kind) { case DisposeAbstractValueKind.NotDisposed: switch (value2.Kind) { case DisposeAbstractValueKind.Escaped: case DisposeAbstractValueKind.NotDisposedOrEscaped: return DisposeAbstractValueKind.NotDisposedOrEscaped; case DisposeAbstractValueKind.Disposed: return DisposeAbstractValueKind.MaybeDisposed; } break; case DisposeAbstractValueKind.Escaped: switch (value2.Kind) { case DisposeAbstractValueKind.NotDisposed: case DisposeAbstractValueKind.NotDisposedOrEscaped: return DisposeAbstractValueKind.NotDisposedOrEscaped; case DisposeAbstractValueKind.Disposed: return DisposeAbstractValueKind.Disposed; } break; case DisposeAbstractValueKind.NotDisposedOrEscaped: switch (value2.Kind) { case DisposeAbstractValueKind.NotDisposed: case DisposeAbstractValueKind.Escaped: return DisposeAbstractValueKind.NotDisposedOrEscaped; case DisposeAbstractValueKind.Disposed: return DisposeAbstractValueKind.MaybeDisposed; } break; case DisposeAbstractValueKind.Disposed: switch (value2.Kind) { case DisposeAbstractValueKind.Escaped: return DisposeAbstractValueKind.Disposed; case DisposeAbstractValueKind.NotDisposed: case DisposeAbstractValueKind.NotDisposedOrEscaped: return DisposeAbstractValueKind.MaybeDisposed; } break; } Debug.Fail($"Unhandled dispose value kind merge: {value1.Kind} and {value2.Kind}"); return DisposeAbstractValueKind.MaybeDisposed; } } } } }