| File: SourceGeneration\Nodes\GeneratorRunStateTable.cs | Web Access |
| Project: src\roslyn\src\Compilers\Core\Portable\Microsoft.CodeAnalysis.csproj (Microsoft.CodeAnalysis) |
// 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.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis { internal sealed class GeneratorRunStateTable { private GeneratorRunStateTable(ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>> executedSteps, ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>> outputSteps) { ExecutedSteps = executedSteps; OutputSteps = outputSteps; } public ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>> ExecutedSteps { get; } public ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>> OutputSteps { get; } public sealed class Builder { private readonly Dictionary<string, HashSet<IncrementalGeneratorRunStep>>? _namedSteps; private readonly Dictionary<string, HashSet<IncrementalGeneratorRunStep>>? _outputSteps; public Builder(bool recordingExecutedSteps) { if (recordingExecutedSteps) { _namedSteps = new Dictionary<string, HashSet<IncrementalGeneratorRunStep>>(); _outputSteps = new Dictionary<string, HashSet<IncrementalGeneratorRunStep>>(); } } public void RecordStepsFromOutputNodeUpdate(IStateTable table) { Debug.Assert(RecordingExecutedSteps); Debug.Assert(table.HasTrackedSteps); foreach (var step in table.Steps) { RecordStepTree(step, addToOutputSteps: true); } } [MemberNotNullWhen(true, nameof(_namedSteps), nameof(_outputSteps))] public bool RecordingExecutedSteps => _namedSteps is not null; public GeneratorRunStateTable ToImmutableAndFree() { return new GeneratorRunStateTable(StepCollectionToImmutable(_namedSteps), StepCollectionToImmutable(_outputSteps)); } private static ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>> StepCollectionToImmutable(Dictionary<string, HashSet<IncrementalGeneratorRunStep>>? builder) { if (builder is null) { return ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>>.Empty; } ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>>.Builder resultBuilder = ImmutableDictionary.CreateBuilder<string, ImmutableArray<IncrementalGeneratorRunStep>>(); foreach (var stepsByName in builder) { resultBuilder.Add(stepsByName.Key, stepsByName.Value.ToImmutableArrayOrEmpty()); } return resultBuilder.ToImmutable(); } private void RecordStepTree(IncrementalGeneratorRunStep step, bool addToOutputSteps) { Debug.Assert(RecordingExecutedSteps); foreach (var (inputStep, _) in step.Inputs) { RecordStepTree(inputStep, addToOutputSteps: false); } // If the step name is not null, we record it in the easily accessible collections. // Otherwise, it will be available only through graph traversal. if (step.Name is not null) { addToNamedStepCollection(_namedSteps, step); if (addToOutputSteps) { addToNamedStepCollection(_outputSteps, step); } } static void addToNamedStepCollection(Dictionary<string, HashSet<IncrementalGeneratorRunStep>> stepCollectionBuilder, IncrementalGeneratorRunStep step) { Debug.Assert(step.Name is not null); if (!stepCollectionBuilder.TryGetValue(step.Name, out var stepsByName)) { stepsByName = new HashSet<IncrementalGeneratorRunStep>(); stepCollectionBuilder.Add(step.Name, stepsByName); } stepsByName.Add(step); } } } } }