Refactor multiphase tests to not use statics

This commit is contained in:
Dan Balasescu
2023-04-28 22:11:12 +09:00
parent 5bbf3cfe08
commit 74bef951b2
6 changed files with 85 additions and 74 deletions

View File

@@ -5,11 +5,11 @@ using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Microsoft.CodeAnalysis;
using osu.Framework.SourceGeneration.Generators;
namespace osu.Framework.SourceGeneration.Tests.Verifiers
{
public partial class CSharpMultiPhaseSourceGeneratorVerifier<TSourceGenerator>
where TSourceGenerator : IIncrementalGenerator, new()
public partial class CSharpMultiPhaseSourceGeneratorVerifier<TSourceGenerator> where TSourceGenerator : IIncrementalGenerator, IGeneratorWithEvents, new()
{
// ReSharper disable once StaticMemberInGenericType
private static readonly Regex multi_phase = new Regex(@"^(?<filename>.*)\.(?<num>\d+)\.cs$", RegexOptions.Compiled);

View File

@@ -6,16 +6,17 @@ using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using osu.Framework.SourceGeneration.Generators.Dependencies;
using osu.Framework.SourceGeneration.Generators;
namespace osu.Framework.SourceGeneration.Tests.Verifiers
{
public partial class CSharpMultiPhaseSourceGeneratorVerifier<TSourceGenerator>
where TSourceGenerator : IIncrementalGenerator, new()
where TSourceGenerator : IIncrementalGenerator, IGeneratorWithEvents, new()
{
public class Test
{
private GeneratorDriver driver;
private TSourceGenerator generator;
private readonly (string filename, string content)[] commonSources;
private readonly (string filename, string content)[] commonGenerated;
private readonly List<List<(string filename, string content)>> multiPhaseSources;
@@ -32,7 +33,7 @@ namespace osu.Framework.SourceGeneration.Tests.Verifiers
List<List<(string filename, string content)>> multiPhaseSources,
List<List<(string filename, string content)>> multiPhaseGenerated)
{
driver = CSharpGeneratorDriver.Create(new TSourceGenerator());
driver = CSharpGeneratorDriver.Create(generator = new TSourceGenerator());
driver = driver.WithUpdatedParseOptions(CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion));
this.commonSources = commonSources;
this.commonGenerated = commonGenerated;
@@ -55,9 +56,9 @@ namespace osu.Framework.SourceGeneration.Tests.Verifiers
emitHits = 0;
};
DependencyInjectionSourceGenerator.GeneratorEvent.SyntaxTargetCreated += _ => syntaxTargetCreated++;
DependencyInjectionSourceGenerator.GeneratorEvent.SemanticTargetCreated += _ => semanticTargetCreated++;
DependencyInjectionSourceGenerator.GeneratorEvent.Emit += _ => emitHits++;
generator.EventDriver.SyntaxTargetCreated += _ => syntaxTargetCreated++;
generator.EventDriver.SemanticTargetCreated += _ => semanticTargetCreated++;
generator.EventDriver.Emit += _ => emitHits++;
PhaseCompleted += () =>
{

View File

@@ -11,17 +11,19 @@ using osu.Framework.SourceGeneration.Generators.Dependencies.Emitters;
namespace osu.Framework.SourceGeneration.Generators.Dependencies
{
[Generator]
public partial class DependencyInjectionSourceGenerator : IIncrementalGenerator
public class DependencyInjectionSourceGenerator : IIncrementalGenerator, IGeneratorWithEvents
{
public GeneratorEventDriver EventDriver { get; } = new GeneratorEventDriver();
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// Stage 1: Create SyntaxTarget objects for all classes.
IncrementalValuesProvider<SyntaxTarget> syntaxTargets =
context.SyntaxProvider.CreateSyntaxProvider(
(n, _) => GeneratorClassCandidate.IsSyntaxTarget(n),
(ctx, _) => returnWithEvent(new SyntaxTarget((ClassDeclarationSyntax)ctx.Node, ctx.SemanticModel), GeneratorEvent.OnSyntaxTargetCreated))
(ctx, _) => returnWithEvent(new SyntaxTarget((ClassDeclarationSyntax)ctx.Node, ctx.SemanticModel), EventDriver.OnSyntaxTargetCreated))
.Select((t, _) => t.WithName())
.Select((t, _) => returnWithEvent(t.WithSemanticTarget(), GeneratorEvent.OnSemanticTargetCreated));
.Select((t, _) => returnWithEvent(t.WithSemanticTarget(), EventDriver.OnSemanticTargetCreated));
// Stage 2: Separate out the old and new syntax targets for the same class object.
// At this point, there are a bunch of old and new syntax targets that may refer to the same class object.
@@ -34,7 +36,7 @@ namespace osu.Framework.SourceGeneration.Generators.Dependencies
.Collect()
.SelectMany((targets, _) =>
{
GeneratorEvent.OnStage2Entry(targets);
EventDriver.OnStage2Entry(targets);
// Ensure all targets have a generation ID. This is over-engineered as two loops to:
// 1. Increment the generation ID locally for deterministic test output.
@@ -50,7 +52,7 @@ namespace osu.Framework.SourceGeneration.Generators.Dependencies
foreach (var target in targets)
target.GenerationId ??= maxGenerationIds[target] + 1;
GeneratorEvent.OnStage2GenerationIdAssigned(targets);
EventDriver.OnStage2GenerationIdAssigned(targets);
HashSet<SyntaxTarget> result = new HashSet<SyntaxTarget>(SyntaxTargetNameComparer.DEFAULT);
@@ -58,7 +60,7 @@ namespace osu.Framework.SourceGeneration.Generators.Dependencies
foreach (SyntaxTarget t in targets.OrderByDescending(t => t.GenerationId))
result.Add(t);
GeneratorEvent.OnStage2Exit(result);
EventDriver.OnStage2Exit(result);
return result;
});
@@ -67,7 +69,7 @@ namespace osu.Framework.SourceGeneration.Generators.Dependencies
private void emit(SourceProductionContext context, GeneratorClassCandidate candidate)
{
GeneratorEvent.OnEmit(candidate);
EventDriver.OnEmit(candidate);
new DependenciesFileEmitter(candidate).Emit(context.AddSource);
}

View File

@@ -1,59 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
namespace osu.Framework.SourceGeneration.Generators.Dependencies
{
public partial class DependencyInjectionSourceGenerator
{
public static class GeneratorEvent
{
public static event Action<SyntaxTarget>? SyntaxTargetCreated;
public static event Action<SyntaxTarget>? SemanticTargetCreated;
public static event Action<ImmutableArray<SyntaxTarget>>? Stage2Entry;
public static event Action<ImmutableArray<SyntaxTarget>>? Stage2GenerationIdAssigned;
public static event Action<HashSet<SyntaxTarget>>? Stage2Exit;
public static event Action<GeneratorClassCandidate>? Emit;
public static void OnSyntaxTargetCreated(SyntaxTarget target)
{
conditionalInvoke(SyntaxTargetCreated, target);
}
public static void OnSemanticTargetCreated(SyntaxTarget target)
{
conditionalInvoke(SemanticTargetCreated, target);
}
public static void OnStage2Entry(ImmutableArray<SyntaxTarget> target)
{
conditionalInvoke(Stage2Entry, target);
}
public static void OnStage2GenerationIdAssigned(ImmutableArray<SyntaxTarget> target)
{
conditionalInvoke(Stage2GenerationIdAssigned, target);
}
public static void OnStage2Exit(HashSet<SyntaxTarget> target)
{
conditionalInvoke(Stage2Exit, target);
}
public static void OnEmit(GeneratorClassCandidate candidate)
{
conditionalInvoke(Emit, candidate);
}
[Conditional("DEBUG")]
private static void conditionalInvoke<T>(Action<T>? @event, T arg)
{
@event?.Invoke(arg);
}
}
}
}

View File

@@ -0,0 +1,57 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using osu.Framework.SourceGeneration.Generators.Dependencies;
namespace osu.Framework.SourceGeneration.Generators
{
public class GeneratorEventDriver
{
public event Action<SyntaxTarget>? SyntaxTargetCreated;
public event Action<SyntaxTarget>? SemanticTargetCreated;
public event Action<ImmutableArray<SyntaxTarget>>? Stage2Entry;
public event Action<ImmutableArray<SyntaxTarget>>? Stage2GenerationIdAssigned;
public event Action<HashSet<SyntaxTarget>>? Stage2Exit;
public event Action<GeneratorClassCandidate>? Emit;
public void OnSyntaxTargetCreated(SyntaxTarget target)
{
conditionalInvoke(SyntaxTargetCreated, target);
}
public void OnSemanticTargetCreated(SyntaxTarget target)
{
conditionalInvoke(SemanticTargetCreated, target);
}
public void OnStage2Entry(ImmutableArray<SyntaxTarget> target)
{
conditionalInvoke(Stage2Entry, target);
}
public void OnStage2GenerationIdAssigned(ImmutableArray<SyntaxTarget> target)
{
conditionalInvoke(Stage2GenerationIdAssigned, target);
}
public void OnStage2Exit(HashSet<SyntaxTarget> target)
{
conditionalInvoke(Stage2Exit, target);
}
public void OnEmit(GeneratorClassCandidate candidate)
{
conditionalInvoke(Emit, candidate);
}
[Conditional("DEBUG")]
private void conditionalInvoke<T>(Action<T>? @event, T arg)
{
@event?.Invoke(arg);
}
}
}

View File

@@ -0,0 +1,10 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
namespace osu.Framework.SourceGeneration.Generators
{
public interface IGeneratorWithEvents
{
GeneratorEventDriver EventDriver { get; }
}
}