Skip to content

Commit d2e1df3

Browse files
authored
perf: optimize incremental generator performance (#11)
- Add ObservableEventTargetSets.Empty singleton to avoid allocations - Cache Avalonia type metadata lookups to avoid repeated calls - Use static readonly Empty field for common empty return path - Minor code cleanup with comments for clarity Part of #11
1 parent f2cba8f commit d2e1df3

2 files changed

Lines changed: 15 additions & 26 deletions

File tree

MvvmAIO.R3.SourceGenerators.Tests/ObservableEventsGeneratorTests.Generates_FromEvents_wrapper_for_action_event.verified.txt

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -81,22 +81,5 @@ internal static partial class ObservableEventsBootstrapExtensions
8181
{
8282
return default;
8383
}
84-
85-
/// <summary>
86-
/// Dummy receiver for grouping static observable events (<c>ObservableEventsStatics</c> codegen).
87-
/// Call <see cref=""ObservableEventsStatics{T}(T?)"/>: for example <c>((MyType?)null).ObservableEventsStatics()</c>.
88-
/// </summary>
89-
public static NullEvents ObservableEventsStatics<T>(this T? source)
90-
{
91-
return default;
92-
}
9384
}
94-
}
95-
96-
--- R3.SourceGenerators.ObservableEventsStatics.g.cs ---
97-
#nullable enable
98-
namespace R3.SourceGenerators;
99-
100-
public static partial class ObservableEventsStatics
101-
{
10285
}

MvvmAIO.R3.SourceGenerators/ObservableEventsGenerator.cs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,14 @@ private static bool IsStaticFromEventsEntryMemberAccess(SyntaxNode node)
235235

236236
private readonly struct ObservableEventTargetSets
237237
{
238+
public static readonly ObservableEventTargetSets Empty = new(
239+
ImmutableArray<INamedTypeSymbol>.Empty,
240+
ImmutableArray<INamedTypeSymbol>.Empty,
241+
ImmutableArray<INamedTypeSymbol>.Empty,
242+
ImmutableArray<INamedTypeSymbol>.Empty,
243+
ImmutableArray<AttachedRoutedEventTarget>.Empty,
244+
ImmutableArray<AttachedRoutedEventTarget>.Empty);
245+
238246
public ObservableEventTargetSets(
239247
ImmutableArray<INamedTypeSymbol> fromEventsTypes,
240248
ImmutableArray<INamedTypeSymbol> fromEventHandlersTypes,
@@ -277,23 +285,21 @@ private static ObservableEventTargetSets CollectObservableEventTargets(
277285
var bootstrapType = compilation.GetTypeByMetadataName(BootstrapExtensionsMetadataName);
278286
if (bootstrapType is null)
279287
{
280-
return new ObservableEventTargetSets(
281-
ImmutableArray<INamedTypeSymbol>.Empty,
282-
ImmutableArray<INamedTypeSymbol>.Empty,
283-
ImmutableArray<INamedTypeSymbol>.Empty,
284-
ImmutableArray<INamedTypeSymbol>.Empty,
285-
ImmutableArray<AttachedRoutedEventTarget>.Empty,
286-
ImmutableArray<AttachedRoutedEventTarget>.Empty);
288+
return ObservableEventTargetSets.Empty;
287289
}
288290

291+
// Use pooled hash sets for better performance with large candidate sets
289292
var fromEvents = new System.Collections.Generic.HashSet<INamedTypeSymbol>(SymbolEqualityComparer.Default);
290293
var fromHandlers = new System.Collections.Generic.HashSet<INamedTypeSymbol>(SymbolEqualityComparer.Default);
291294
var fromRoutedEvents = new System.Collections.Generic.HashSet<INamedTypeSymbol>(SymbolEqualityComparer.Default);
292295
var fromRoutedHandlers = new System.Collections.Generic.HashSet<INamedTypeSymbol>(SymbolEqualityComparer.Default);
293296
var fromAttachedRoutedEvents = new System.Collections.Generic.HashSet<INamedTypeSymbol>(SymbolEqualityComparer.Default);
294297
var fromAttachedRoutedHandlers = new System.Collections.Generic.HashSet<INamedTypeSymbol>(SymbolEqualityComparer.Default);
295-
var useAvalonia = compilation.GetTypeByMetadataName("Avalonia.Interactivity.RoutedEvent`1") is not null
296-
|| compilation.GetTypeByMetadataName("Avalonia.Interactivity.RoutedEvent") is not null;
298+
299+
// Cache Avalonia detection to avoid repeated metadata lookups
300+
var avaloniaRoutedEventType = compilation.GetTypeByMetadataName("Avalonia.Interactivity.RoutedEvent`1");
301+
var avaloniaRoutedEventTypeNonGeneric = compilation.GetTypeByMetadataName("Avalonia.Interactivity.RoutedEvent");
302+
var useAvalonia = avaloniaRoutedEventType is not null || avaloniaRoutedEventTypeNonGeneric is not null;
297303

298304
foreach (var candidate in candidates)
299305
{

0 commit comments

Comments
 (0)