| File: SourceGeneration\RunResults.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; using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis { /// <summary> /// Represents the results of running a generation pass over a set of <see cref="ISourceGenerator"/>s. /// </summary> public class GeneratorDriverRunResult { private ImmutableArray<Diagnostic> _lazyDiagnostics; private ImmutableArray<SyntaxTree> _lazyGeneratedTrees; internal GeneratorDriverRunResult(ImmutableArray<GeneratorRunResult> results, TimeSpan elapsedTime) { this.Results = results; ElapsedTime = elapsedTime; } /// <summary> /// The individual result of each <see cref="ISourceGenerator"/> that was run in this generator pass, one per generator. /// </summary> public ImmutableArray<GeneratorRunResult> Results { get; } /// <summary> /// The wall clock time that this generator pass took to execute. /// </summary> internal TimeSpan ElapsedTime { get; } /// <summary> /// The <see cref="Diagnostic"/>s produced by all generators run during this generation pass. /// </summary> /// <remarks> /// This is equivalent to the union of all <see cref="GeneratorRunResult.Diagnostics"/> in <see cref="Results"/>. /// </remarks> public ImmutableArray<Diagnostic> Diagnostics { get { if (_lazyDiagnostics.IsDefault) { ImmutableInterlocked.InterlockedInitialize(ref _lazyDiagnostics, Results.Where(r => !r.Diagnostics.IsDefaultOrEmpty).SelectMany(r => r.Diagnostics).ToImmutableArray()); } return _lazyDiagnostics; } } /// <summary> /// The <see cref="SyntaxTree"/>s produced during this generation pass by parsing each <see cref="SourceText"/> added by each generator. /// </summary> /// <remarks> /// This is equivalent to the union of all <see cref="GeneratedSourceResult.SyntaxTree"/>s in each <see cref="GeneratorRunResult.GeneratedSources"/> in each <see cref="Results"/> /// </remarks> public ImmutableArray<SyntaxTree> GeneratedTrees { get { if (_lazyGeneratedTrees.IsDefault) { ImmutableInterlocked.InterlockedInitialize(ref _lazyGeneratedTrees, Results.Where(r => !r.GeneratedSources.IsDefaultOrEmpty).SelectMany(r => r.GeneratedSources.Select(g => g.SyntaxTree)).ToImmutableArray()); } return _lazyGeneratedTrees; } } } /// <summary> /// Represents the results of a single <see cref="ISourceGenerator"/> generation pass. /// </summary> public readonly struct GeneratorRunResult { internal GeneratorRunResult( ISourceGenerator generator, ImmutableArray<GeneratedSourceResult> generatedSources, ImmutableArray<Diagnostic> diagnostics, ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>> namedSteps, ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>> outputSteps, ImmutableDictionary<string, object> hostOutputs, Exception? exception, TimeSpan elapsedTime) { Debug.Assert(exception is null || diagnostics.Length == 1); this.Generator = generator; this.GeneratedSources = generatedSources; this.Diagnostics = diagnostics; this.TrackedSteps = namedSteps; this.TrackedOutputSteps = outputSteps; #pragma warning disable RSEXPERIMENTAL004 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. this.HostOutputs = hostOutputs; #pragma warning restore RSEXPERIMENTAL004 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. this.Exception = exception; this.ElapsedTime = elapsedTime; } /// <summary> /// The <see cref="ISourceGenerator"/> that produced this result. /// </summary> public ISourceGenerator Generator { get; } /// <summary> /// The sources that were added by <see cref="Generator"/> during the generation pass this result represents. /// </summary> public ImmutableArray<GeneratedSourceResult> GeneratedSources { get; } /// <summary> /// A collection of <see cref="Diagnostic"/>s reported by <see cref="Generator"/> /// </summary> /// <remarks> /// When generation fails due to an <see cref="Exception"/> being thrown, a single diagnostic is added /// to represent the failure. Any generator reported diagnostics up to the failure point are not included. /// </remarks> public ImmutableArray<Diagnostic> Diagnostics { get; } /// <summary> /// A collection of items added via <see cref="HostOutputProductionContext.AddOutput(string, object)"/>. /// </summary> [Experimental(RoslynExperiments.GeneratorHostOutputs, UrlFormat = RoslynExperiments.GeneratorHostOutputs_Url)] public ImmutableDictionary<string, object> HostOutputs { get; } /// <summary> /// An <see cref="System.Exception"/> instance that was thrown by the generator, or <c>null</c> if the generator completed without error. /// </summary> /// <remarks> /// When this property has a value, the <see cref="Diagnostics"/> collection will contain a single /// diagnostic indicating that the generator failed. Generally <see cref="GeneratedSources"/> will be empty /// in this case, however, sources produced by a pre-compilation phase that completed successfully prior to /// the failure are preserved (because they were already observed by other generators in the augmented /// compilation, so dropping them would produce inconsistent results). /// </remarks> public Exception? Exception { get; } /// <summary> /// The wall clock time that elapsed while this generator was running. /// </summary> internal TimeSpan ElapsedTime { get; } /// <summary> /// A collection of the named incremental steps (both intermediate and final output ones) /// executed during the generator pass this result represents. /// </summary> /// <remarks> /// Steps can be named by extension method WithTrackingName. /// </remarks> public ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>> TrackedSteps { get; } /// <summary> /// A collection of the named output steps executed during the generator pass this result represents. /// </summary> /// <remarks> /// Steps can be named by extension method WithTrackingName. /// </remarks> public ImmutableDictionary<string, ImmutableArray<IncrementalGeneratorRunStep>> TrackedOutputSteps { get; } } /// <summary> /// Represents the results of an <see cref="ISourceGenerator"/> calling <see cref="GeneratorExecutionContext.AddSource(string, SourceText)"/>. /// </summary> /// <remarks> /// This contains the original <see cref="SourceText"/> added by the generator, along with the parsed representation of that text in <see cref="SyntaxTree"/>. /// </remarks> public readonly struct GeneratedSourceResult { internal GeneratedSourceResult(SyntaxTree tree, SourceText text, string hintName) { this.SyntaxTree = tree; this.SourceText = text; this.HintName = hintName; } /// <summary> /// The <see cref="SyntaxTree"/> that was produced from parsing the <see cref="GeneratedSourceResult.SourceText"/>. /// </summary> public SyntaxTree SyntaxTree { get; } /// <summary> /// The <see cref="SourceText"/> that was added by the generator. /// </summary> public SourceText SourceText { get; } /// <summary> /// An identifier provided by the generator that identifies the added <see cref="SourceText"/>. /// </summary> public string HintName { get; } } /// <summary> /// Contains timing information for a full generation pass. /// </summary> public readonly struct GeneratorDriverTimingInfo { internal GeneratorDriverTimingInfo(TimeSpan elapsedTime, ImmutableArray<GeneratorTimingInfo> generatorTimes) { ElapsedTime = elapsedTime; GeneratorTimes = generatorTimes; } /// <summary> /// The wall clock time that the entire generation pass took. /// </summary> /// <remarks> /// This can be more than the sum of times in <see cref="GeneratorTimes"/> as it includes other costs such as setup. /// </remarks> public TimeSpan ElapsedTime { get; } /// <summary> /// Individual timings per generator. /// </summary> public ImmutableArray<GeneratorTimingInfo> GeneratorTimes { get; } } /// <summary> /// Contains timing information for a single generator. /// </summary> public readonly struct GeneratorTimingInfo { internal GeneratorTimingInfo(ISourceGenerator generator, TimeSpan elapsedTime) { Generator = generator; ElapsedTime = elapsedTime; } /// <summary> /// The <see cref="ISourceGenerator"/> that was running during the recorded time. /// </summary> public ISourceGenerator Generator { get; } /// <summary> /// The wall clock time the generator spent running. /// </summary> public TimeSpan ElapsedTime { get; } } }