using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols; internal static class ConstantEvaluationHelpers { [DebuggerDisplay("{GetDebuggerDisplay(), nq}")] internal readonly struct FieldInfo(SourceFieldSymbolWithSyntaxReference field, bool startsCycle) { public readonly SourceFieldSymbolWithSyntaxReference Field = field; public readonly bool StartsCycle = startsCycle; private string GetDebuggerDisplay() { string text = Field.ToString(); if (StartsCycle) { text += " [cycle]"; } return text; } } private struct Node where T : class { public ImmutableHashSet Dependencies; public ImmutableHashSet DependedOnBy; } internal static void OrderAllDependencies(this SourceFieldSymbolWithSyntaxReference field, ArrayBuilder order, bool earlyDecodingWellKnownAttributes) { PooledDictionary> instance = PooledDictionary>.GetInstance(); CreateGraph((Dictionary>)(object)instance, field, earlyDecodingWellKnownAttributes); OrderGraph((Dictionary>)(object)instance, order); instance.Free(); } private static void CreateGraph(Dictionary> graph, SourceFieldSymbolWithSyntaxReference field, bool earlyDecodingWellKnownAttributes) { ArrayBuilder instance = ArrayBuilder.GetInstance(); ArrayBuilderExtensions.Push(instance, field); while (instance.Count > 0) { field = ArrayBuilderExtensions.Pop(instance); if (graph.TryGetValue(field, out var value)) { if (value.Dependencies != null) { continue; } } else { value = new Node { DependedOnBy = ImmutableHashSet.Empty }; } ImmutableHashSet immutableHashSet = (value.Dependencies = field.GetConstantValueDependencies(earlyDecodingWellKnownAttributes)); graph[field] = value; foreach (SourceFieldSymbolWithSyntaxReference item in immutableHashSet) { ArrayBuilderExtensions.Push(instance, item); if (!graph.TryGetValue(item, out value)) { value = new Node { DependedOnBy = ImmutableHashSet.Empty }; } value.DependedOnBy = value.DependedOnBy.Add(field); graph[item] = value; } } instance.Free(); } private static void OrderGraph(Dictionary> graph, ArrayBuilder order) { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) PooledHashSet val = null; ArrayBuilder fieldsInvolvedInCycles = null; while (graph.Count > 0) { IEnumerable enumerable = (IEnumerable)val; IEnumerable obj = enumerable ?? graph.Keys; ArrayBuilder instance = ArrayBuilder.GetInstance(); foreach (SourceFieldSymbolWithSyntaxReference item in obj) { if (graph.TryGetValue(item, out var value) && value.Dependencies.Count == 0) { instance.Add(item); } } val?.Free(); val = null; if (instance.Count > 0) { PooledHashSet instance2 = PooledHashSet.GetInstance(); Enumerator enumerator2 = instance.GetEnumerator(); while (enumerator2.MoveNext()) { SourceFieldSymbolWithSyntaxReference current2 = enumerator2.Current; foreach (SourceFieldSymbolWithSyntaxReference item2 in graph[current2].DependedOnBy) { Node value2 = graph[item2]; value2.Dependencies = value2.Dependencies.Remove(current2); graph[item2] = value2; ((HashSet)(object)instance2).Add(item2); } graph.Remove(current2); } enumerator2 = instance.GetEnumerator(); while (enumerator2.MoveNext()) { SourceFieldSymbolWithSyntaxReference current4 = enumerator2.Current; order.Add(new FieldInfo(current4, startsCycle: false)); } val = instance2; } else { SourceFieldSymbolWithSyntaxReference startOfFirstCycle = GetStartOfFirstCycle(graph, ref fieldsInvolvedInCycles); foreach (SourceFieldSymbolWithSyntaxReference dependency in graph[startOfFirstCycle].Dependencies) { Node value3 = graph[dependency]; value3.DependedOnBy = value3.DependedOnBy.Remove(startOfFirstCycle); graph[dependency] = value3; } Node node = graph[startOfFirstCycle]; PooledHashSet instance3 = PooledHashSet.GetInstance(); foreach (SourceFieldSymbolWithSyntaxReference item3 in node.DependedOnBy) { Node value4 = graph[item3]; value4.Dependencies = value4.Dependencies.Remove(startOfFirstCycle); graph[item3] = value4; ((HashSet)(object)instance3).Add(item3); } graph.Remove(startOfFirstCycle); order.Add(new FieldInfo(startOfFirstCycle, startsCycle: true)); val = instance3; } instance.Free(); } val?.Free(); fieldsInvolvedInCycles?.Free(); } private static SourceFieldSymbolWithSyntaxReference GetStartOfFirstCycle(Dictionary> graph, ref ArrayBuilder fieldsInvolvedInCycles) { if (fieldsInvolvedInCycles == null) { fieldsInvolvedInCycles = ArrayBuilder.GetInstance(graph.Count); fieldsInvolvedInCycles.AddRange((from f in graph.Keys group f by f.DeclaringCompilation).SelectMany((IGrouping g) => EnumerableExtensions.OrderByDescending((IEnumerable)g, (Comparison)((SourceFieldSymbolWithSyntaxReference f1, SourceFieldSymbolWithSyntaxReference f2) => ((Compilation)g.Key).CompareSourceLocations(f1.ErrorLocation, f2.ErrorLocation))))); } SourceFieldSymbolWithSyntaxReference sourceFieldSymbolWithSyntaxReference; do { sourceFieldSymbolWithSyntaxReference = ArrayBuilderExtensions.Pop(fieldsInvolvedInCycles); } while (!graph.ContainsKey(sourceFieldSymbolWithSyntaxReference) || !IsPartOfCycle(graph, sourceFieldSymbolWithSyntaxReference)); return sourceFieldSymbolWithSyntaxReference; } private static bool IsPartOfCycle(Dictionary> graph, SourceFieldSymbolWithSyntaxReference field) { PooledHashSet instance = PooledHashSet.GetInstance(); ArrayBuilder instance2 = ArrayBuilder.GetInstance(); SourceFieldSymbolWithSyntaxReference item = field; bool result = false; ArrayBuilderExtensions.Push(instance2, field); while (instance2.Count > 0) { field = ArrayBuilderExtensions.Pop(instance2); Node node = graph[field]; if (node.Dependencies.Contains(item)) { result = true; break; } foreach (SourceFieldSymbolWithSyntaxReference dependency in node.Dependencies) { if (((HashSet)(object)instance).Add(dependency)) { ArrayBuilderExtensions.Push(instance2, dependency); } } } instance2.Free(); instance.Free(); return result; } [Conditional("DEBUG")] private static void CheckGraph(Dictionary> graph) { int num = 10; foreach (KeyValuePair> item in graph) { _ = item.Key; Node value = item.Value; foreach (SourceFieldSymbolWithSyntaxReference dependency in value.Dependencies) { graph.TryGetValue(dependency, out var _); } foreach (SourceFieldSymbolWithSyntaxReference item2 in value.DependedOnBy) { graph.TryGetValue(item2, out var _); } num--; if (num == 0) { break; } } } }