Skip to content

Commit 8d23f1b

Browse files
committed
refactor(#127): fix Rider/Unity background generator crashes and caching issues
- Convert the `Generate` method to `static` in both Sync and Async source generators. This prevents the incremental compilation delegates from capturing the generator instance, which was breaking Rider's background incremental updates. - Introduce a 100-iteration depth safety net to all recursive `BaseType` traversal loops in `GetClassData` to prevent infinite analyzer hangs and freezes when typing incomplete or cyclic inheritance hierarchies. - Add null-safety guards to the `GetNonNullableType`, `FullyQualifyTypeWithoutNullable`, and `IsNullableTypeSymbol` helpers to prevent compiler crashes on unresolved types during background analysis.
1 parent fc89e23 commit 8d23f1b

2 files changed

Lines changed: 52 additions & 16 deletions

File tree

ManualDi.Async/ManualDi.Async.Generators/ManualDiSourceGenerator.cs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
2323
GetClassData)
2424
.Where(x => x is not null);
2525

26-
context.RegisterSourceOutput(classData, Generate!);
26+
context.RegisterSourceOutput(classData, static (spc, data) => Generate(spc, data!));
2727
}
2828

2929
private static bool IsSyntaxNodeValid(SyntaxNode node, CancellationToken ct)
@@ -93,15 +93,17 @@ private static bool IsSyntaxNodeValid(SyntaxNode node, CancellationToken ct)
9393
baseTypesAndInterfaces.Add(i.ToDisplayString());
9494
}
9595
var tempBase = symbol.BaseType;
96-
while (tempBase != null)
96+
int tempBaseDepth = 0;
97+
while (tempBase != null && tempBaseDepth++ < 100)
9798
{
9899
baseTypesAndInterfaces.Add(tempBase.ToDisplayString());
99100
tempBase = tempBase.BaseType;
100101
}
101102

102103
INamedTypeSymbol? baseDiSymbol = null;
103104
var currentBase = symbol.BaseType;
104-
while (currentBase != null)
105+
int currentBaseDepth = 0;
106+
while (currentBase != null && currentBaseDepth++ < 100)
105107
{
106108
if (wellKnownTypes.HasManualDiAttribute(currentBase))
107109
{
@@ -121,7 +123,8 @@ private static bool IsSyntaxNodeValid(SyntaxNode node, CancellationToken ct)
121123
baseDiTypesAndInterfaces.Add(i.ToDisplayString());
122124
}
123125
var tempBaseDi = baseDiSymbol.BaseType;
124-
while (tempBaseDi != null)
126+
int tempBaseDiDepth = 0;
127+
while (tempBaseDi != null && tempBaseDiDepth++ < 100)
125128
{
126129
baseDiTypesAndInterfaces.Add(tempBaseDi.ToDisplayString());
127130
tempBaseDi = tempBaseDi.BaseType;
@@ -394,7 +397,7 @@ private static Resolution CreateResolution(IParameterSymbol parameter, WellKnown
394397
return new ServiceResolution(typeName, injectId, method, isCyclic);
395398
}
396399

397-
private void Generate(SourceProductionContext context, ClassData data)
400+
private static void Generate(SourceProductionContext context, ClassData data)
398401
{
399402
var stringBuilder = new StringBuilder();
400403

@@ -692,8 +695,13 @@ private static string DetermineDependencyMethod(bool isCyclic, bool isNullable)
692695
}
693696
}
694697

695-
private static string FullyQualifyTypeWithoutNullable(ITypeSymbol typeSymbol)
698+
private static string FullyQualifyTypeWithoutNullable(ITypeSymbol? typeSymbol)
696699
{
700+
if (typeSymbol is null)
701+
{
702+
return string.Empty;
703+
}
704+
697705
var nonNullableType = GetNonNullableType(typeSymbol);
698706
if (nonNullableType is not null)
699707
{
@@ -703,14 +711,24 @@ private static string FullyQualifyTypeWithoutNullable(ITypeSymbol typeSymbol)
703711
return typeSymbol.ToDisplayString();
704712
}
705713

706-
private static bool IsNullableTypeSymbol(ITypeSymbol typeSymbol)
714+
private static bool IsNullableTypeSymbol(ITypeSymbol? typeSymbol)
707715
{
716+
if (typeSymbol is null)
717+
{
718+
return false;
719+
}
720+
708721
return typeSymbol.NullableAnnotation is NullableAnnotation.Annotated ||
709722
typeSymbol.OriginalDefinition.SpecialType is SpecialType.System_Nullable_T;
710723
}
711724

712-
private static ITypeSymbol? GetNonNullableType(ITypeSymbol typeSymbol)
725+
private static ITypeSymbol? GetNonNullableType(ITypeSymbol? typeSymbol)
713726
{
727+
if (typeSymbol is null)
728+
{
729+
return null;
730+
}
731+
714732
if (typeSymbol.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T &&
715733
typeSymbol is INamedTypeSymbol namedTypeSymbol)
716734
{

ManualDi.Sync/ManualDi.Sync.Generators/ManualDiSourceGenerator.cs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
2323
GetClassData)
2424
.Where(x => x is not null);
2525

26-
context.RegisterSourceOutput(classData, Generate!);
26+
context.RegisterSourceOutput(classData, static (spc, data) => Generate(spc, data!));
2727
}
2828

2929
private static bool IsSyntaxNodeValid(SyntaxNode node, CancellationToken ct)
@@ -92,15 +92,17 @@ private static bool IsSyntaxNodeValid(SyntaxNode node, CancellationToken ct)
9292
baseTypesAndInterfaces.Add(i.ToDisplayString());
9393
}
9494
var tempBase = symbol.BaseType;
95-
while (tempBase != null)
95+
int tempBaseDepth = 0;
96+
while (tempBase != null && tempBaseDepth++ < 100)
9697
{
9798
baseTypesAndInterfaces.Add(tempBase.ToDisplayString());
9899
tempBase = tempBase.BaseType;
99100
}
100101

101102
INamedTypeSymbol? baseDiSymbol = null;
102103
var currentBase = symbol.BaseType;
103-
while (currentBase != null)
104+
int currentBaseDepth = 0;
105+
while (currentBase != null && currentBaseDepth++ < 100)
104106
{
105107
if (wellKnownTypes.HasManualDiAttribute(currentBase))
106108
{
@@ -120,7 +122,8 @@ private static bool IsSyntaxNodeValid(SyntaxNode node, CancellationToken ct)
120122
baseDiTypesAndInterfaces.Add(i.ToDisplayString());
121123
}
122124
var tempBaseDi = baseDiSymbol.BaseType;
123-
while (tempBaseDi != null)
125+
int tempBaseDiDepth = 0;
126+
while (tempBaseDi != null && tempBaseDiDepth++ < 100)
124127
{
125128
baseDiTypesAndInterfaces.Add(tempBaseDi.ToDisplayString());
126129
tempBaseDi = tempBaseDi.BaseType;
@@ -374,7 +377,7 @@ private static Resolution CreateResolution(IParameterSymbol parameter, WellKnown
374377
return new ServiceResolution(typeName, injectId, method);
375378
}
376379

377-
private void Generate(SourceProductionContext context, ClassData data)
380+
private static void Generate(SourceProductionContext context, ClassData data)
378381
{
379382
var stringBuilder = new StringBuilder();
380383

@@ -591,8 +594,13 @@ private static void AppendResolution(StringBuilder sb, Resolution resolution)
591594
}
592595
}
593596

594-
private static string FullyQualifyTypeWithoutNullable(ITypeSymbol typeSymbol)
597+
private static string FullyQualifyTypeWithoutNullable(ITypeSymbol? typeSymbol)
595598
{
599+
if (typeSymbol is null)
600+
{
601+
return string.Empty;
602+
}
603+
596604
var nonNullableType = GetNonNullableType(typeSymbol);
597605
if (nonNullableType is not null)
598606
{
@@ -602,14 +610,24 @@ private static string FullyQualifyTypeWithoutNullable(ITypeSymbol typeSymbol)
602610
return typeSymbol.ToDisplayString();
603611
}
604612

605-
private static bool IsNullableTypeSymbol(ITypeSymbol typeSymbol)
613+
private static bool IsNullableTypeSymbol(ITypeSymbol? typeSymbol)
606614
{
615+
if (typeSymbol is null)
616+
{
617+
return false;
618+
}
619+
607620
return typeSymbol.NullableAnnotation is NullableAnnotation.Annotated ||
608621
typeSymbol.OriginalDefinition.SpecialType is SpecialType.System_Nullable_T;
609622
}
610623

611-
private static ITypeSymbol? GetNonNullableType(ITypeSymbol typeSymbol)
624+
private static ITypeSymbol? GetNonNullableType(ITypeSymbol? typeSymbol)
612625
{
626+
if (typeSymbol is null)
627+
{
628+
return null;
629+
}
630+
613631
if (typeSymbol.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T &&
614632
typeSymbol is INamedTypeSymbol namedTypeSymbol)
615633
{

0 commit comments

Comments
 (0)