diff --git a/src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameIncrementalGenerator.cs b/src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameIncrementalGenerator.cs index 3dd889e9ec..6623a791ca 100644 --- a/src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameIncrementalGenerator.cs +++ b/src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameIncrementalGenerator.cs @@ -20,7 +20,7 @@ public class AvaloniaNameIncrementalGenerator : IIncrementalGenerator // Map MSBuild properties onto readonly GeneratorOptions. var options = context.AnalyzerConfigOptionsProvider .Select(static (options, _) => new GeneratorOptions(options.GlobalOptions)) - .WithTrackingName(TrackingNames.XamlGeneratorOptionsProvider); + .WithTrackingName(TrackingNames.XamlGeneratorOptions); // Filter additional texts, we only need Avalonia XAML files. var xamlFiles = context.AdditionalTextsProvider @@ -52,7 +52,7 @@ public class AvaloniaNameIncrementalGenerator : IIncrementalGenerator return true; }) .Select(static (pair, _) => pair.Left) - .WithTrackingName(TrackingNames.InputXamlFilesProvider); + .WithTrackingName(TrackingNames.InputXamlFiles); // Actual parsing step. We input XAML files one by one, but don't resolve any types. // That's why we use NoOp type system here, allowing parsing to run detached from C# compilation. @@ -93,16 +93,22 @@ public class AvaloniaNameIncrementalGenerator : IIncrementalGenerator .Where(request => request is not null) .WithTrackingName(TrackingNames.ParsedXamlClasses); + // Map compilation into readonly XAML type system. + // Which is ONLY updated when any compilation references have changed. + var typeSystem = context.CompilationProvider + .WithComparer(new CompilationReferencesComparer()) + .Select(static (compilation, _) => new RoslynTypeSystem(compilation)) + .WithTrackingName(TrackingNames.XamlTypeSystem); + // Note: this step will be re-executed on any C# file changes. // As much as possible heavy tasks should be moved outside of this step, like XAML parsing. var resolvedNames = parsedXamlClasses.Collect() - .Combine(context.CompilationProvider) + .Combine(typeSystem) .SelectMany(static (pair, _) => { - var (classes, compilation) = pair; - var roslynTypeSystem = new RoslynTypeSystem(compilation); + var (classes, roslynTypeSystem) = pair; var compiler = MiniCompiler.CreateRoslyn(roslynTypeSystem, MiniCompiler.AvaloniaXmlnsDefinitionAttribute); - var hasDevToolsReference = compilation.ReferencedAssemblyNames.Any(r => r.Name == "Avalonia.Diagnostics"); + var hasDevToolsReference = roslynTypeSystem.FindAssembly("Avalonia.Diagnostics") is not null; var nameResolver = new XamlXNameResolver(); var outputs = new List(); @@ -149,7 +155,7 @@ public class AvaloniaNameIncrementalGenerator : IIncrementalGenerator return outputs; }) - .WithTrackingName(TrackingNames.ResolvedNamesProvider); + .WithTrackingName(TrackingNames.ResolvedNames); context.RegisterSourceOutput(resolvedNames.Combine(options), static (context, pair) => { diff --git a/src/tools/Avalonia.Generators/NameGenerator/TrackingNames.cs b/src/tools/Avalonia.Generators/NameGenerator/TrackingNames.cs index 0ed928a532..cab6a788a1 100644 --- a/src/tools/Avalonia.Generators/NameGenerator/TrackingNames.cs +++ b/src/tools/Avalonia.Generators/NameGenerator/TrackingNames.cs @@ -2,8 +2,9 @@ namespace Avalonia.Generators.NameGenerator; internal static class TrackingNames { - public const string ResolvedNamesProvider = nameof(ResolvedNamesProvider); - public const string XamlGeneratorOptionsProvider = nameof(XamlGeneratorOptionsProvider); - public const string InputXamlFilesProvider = nameof(InputXamlFilesProvider); + public const string ResolvedNames = nameof(ResolvedNames); + public const string XamlGeneratorOptions = nameof(XamlGeneratorOptions); + public const string InputXamlFiles = nameof(InputXamlFiles); public const string ParsedXamlClasses = nameof(ParsedXamlClasses); + public const string XamlTypeSystem = nameof(XamlTypeSystem); }