Skip to content

Commit

Permalink
Format and remove unused code
Browse files Browse the repository at this point in the history
  • Loading branch information
wieslawsoltes committed Nov 27, 2024
1 parent 1732310 commit c196f01
Showing 1 changed file with 90 additions and 193 deletions.
283 changes: 90 additions & 193 deletions ReactiveGenerator/ReactiveGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
Expand Down Expand Up @@ -32,18 +30,18 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
// Get both partial class declarations and partial properties
var partialClasses = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: (s, _) => s is ClassDeclarationSyntax c &&
c.Modifiers.Any(m => m.ValueText == "partial") &&
c.AttributeLists.Count > 0,
predicate: (s, _) => s is ClassDeclarationSyntax c &&
c.Modifiers.Any(m => m.ValueText == "partial") &&
c.AttributeLists.Count > 0,
transform: (ctx, _) => GetClassInfo(ctx))
.Where(m => m is not null);

var partialProperties = context.SyntaxProvider
.CreateSyntaxProvider(
// Update predicate to check for [Reactive] attribute
predicate: (s, _) => s is PropertyDeclarationSyntax p &&
predicate: (s, _) => s is PropertyDeclarationSyntax p &&
p.Modifiers.Any(m => m.ValueText == "partial") &&
p.AttributeLists.Any(al => al.Attributes.Any(a =>
p.AttributeLists.Any(al => al.Attributes.Any(a =>
a.Name.ToString() is "Reactive" or "ReactiveAttribute")),
transform: (ctx, _) => GetPropertyInfo(ctx))
.Where(m => m is not null);
Expand Down Expand Up @@ -87,7 +85,7 @@ private static (INamedTypeSymbol Type, Location Location)? GetClassInfo(Generato

return null;
}

private static (IPropertySymbol Property, Location Location)? GetPropertyInfo(GeneratorSyntaxContext context)
{
// Check if this is a property declaration
Expand All @@ -107,6 +105,7 @@ private static (IPropertySymbol Property, Location Location)? GetPropertyInfo(Ge
break;
}
}

if (hasReactiveAttribute) break;
}

Expand All @@ -123,53 +122,7 @@ private static (IPropertySymbol Property, Location Location)? GetPropertyInfo(Ge

return null;
}

private static (ISymbol Symbol, Location Location, bool IsClass)? GetSymbolInfo(GeneratorSyntaxContext context)
{
var semanticModel = context.SemanticModel;

switch (context.Node)
{
case PropertyDeclarationSyntax propertyDeclaration:
foreach (var attributeList in propertyDeclaration.AttributeLists)
{
foreach (var attribute in attributeList.Attributes)
{
var name = attribute.Name.ToString();
if (name is "Reactive" or "ReactiveAttribute")
{
var symbol = semanticModel.GetDeclaredSymbol(propertyDeclaration);
if (symbol != null)
{
return (symbol, propertyDeclaration.GetLocation(), false);
}
}
}
}
break;

case ClassDeclarationSyntax classDeclaration:
foreach (var attributeList in classDeclaration.AttributeLists)
{
foreach (var attribute in attributeList.Attributes)
{
var name = attribute.Name.ToString();
if (name is "Reactive" or "ReactiveAttribute")
{
var symbol = semanticModel.GetDeclaredSymbol(classDeclaration);
if (symbol != null)
{
return (symbol, classDeclaration.GetLocation(), true);
}
}
}
}
break;
}

return null;
}

private static bool InheritsFromReactiveObject(INamedTypeSymbol typeSymbol)
{
var current = typeSymbol;
Expand All @@ -184,65 +137,6 @@ private static bool InheritsFromReactiveObject(INamedTypeSymbol typeSymbol)
return false;
}

private static bool HasReactivePropertiesInHierarchy(INamedTypeSymbol typeSymbol)
{
foreach (var member in typeSymbol.GetMembers().OfType<IPropertySymbol>())
{
if (member.GetAttributes().Any(attr =>
attr.AttributeClass is not null &&
(attr.AttributeClass.Name is "ReactiveAttribute" or "Reactive")))
{
return true;
}
}

return typeSymbol.BaseType is not null && HasReactivePropertiesInHierarchy(typeSymbol.BaseType);
}

private static bool HasReactiveProperties(INamedTypeSymbol typeSymbol)
{
foreach (var member in typeSymbol.GetMembers().OfType<IPropertySymbol>())
{
if (member.GetAttributes().Any(attr =>
attr.AttributeClass is not null &&
(attr.AttributeClass.Name is "ReactiveAttribute" or "Reactive")))
{
return true;
}
}
return false;
}

private static bool ShouldImplementINPC(
Compilation compilation,
INamedTypeSymbol typeSymbol,
HashSet<INamedTypeSymbol> processedTypes)
{
// If the type inherits from ReactiveObject, it doesn't need INPC
if (InheritsFromReactiveObject(typeSymbol))
return false;

// If it already implements INPC or will be implementing it, no need to add it again
if (HasINPCImplementation(compilation, typeSymbol, processedTypes))
return false;

// Check if the type or any of its base types has the [Reactive] attribute
var current = typeSymbol;
while (current is not null)
{
if (current.GetAttributes().Any(attr =>
attr.AttributeClass is not null &&
(attr.AttributeClass.Name is "ReactiveAttribute" or "Reactive")))
{
return true;
}
current = current.BaseType;
}

// Even if no [Reactive] attribute on class, check if the type has any [Reactive] properties
return HasReactiveProperties(typeSymbol);
}

private static int GetTypeHierarchyDepth(INamedTypeSymbol type)
{
int depth = 0;
Expand All @@ -252,100 +146,102 @@ private static int GetTypeHierarchyDepth(INamedTypeSymbol type)
depth++;
current = current.BaseType;
}

return depth;
}

private static void Execute(
Compilation compilation,
List<(INamedTypeSymbol Type, Location Location)> reactiveClasses,
List<(IPropertySymbol Property, Location Location)> properties,
bool useLegacyMode,
SourceProductionContext context)
{
if (properties.Count == 0 && reactiveClasses.Count == 0)
return;

var processedTypes = new HashSet<INamedTypeSymbol>(SymbolEqualityComparer.Default);
var reactiveTypesSet = new HashSet<INamedTypeSymbol>(
reactiveClasses.Select(rc => rc.Type),
SymbolEqualityComparer.Default);

// Group properties by containing type
var propertyGroups = properties
.GroupBy(p => p.Property.ContainingType, SymbolEqualityComparer.Default)
.ToDictionary(g => g.Key, g => g.ToList(), SymbolEqualityComparer.Default);

// Get all types that need processing
var allTypes = new HashSet<INamedTypeSymbol>(SymbolEqualityComparer.Default);

// Add types from reactive classes
foreach (var reactiveClass in reactiveClasses)
allTypes.Add(reactiveClass.Type);

// Add types from properties with [Reactive] attribute
foreach (var property in properties)
{
if (property.Property.ContainingType is INamedTypeSymbol type)
allTypes.Add(type);
}

// First pass: Process base types that need INPC
var typesToProcess = allTypes.ToList(); // Create a copy to avoid modification during enumeration
foreach (var type in typesToProcess)
private static void Execute(
Compilation compilation,
List<(INamedTypeSymbol Type, Location Location)> reactiveClasses,
List<(IPropertySymbol Property, Location Location)> properties,
bool useLegacyMode,
SourceProductionContext context)
{
var current = type.BaseType;
while (current is not null)
{
allTypes.Add(current); // Add base type to processing queue
current = current.BaseType;
}
}
if (properties.Count == 0 && reactiveClasses.Count == 0)
return;

// Process types in correct order (base types first)
foreach (var type in allTypes.OrderBy(t => GetTypeHierarchyDepth(t)))
{
// Skip if type already processed or inherits from ReactiveObject
if (processedTypes.Contains(type) || InheritsFromReactiveObject(type))
continue;
var processedTypes = new HashSet<INamedTypeSymbol>(SymbolEqualityComparer.Default);
var reactiveTypesSet = new HashSet<INamedTypeSymbol>(
reactiveClasses.Select(rc => rc.Type),
SymbolEqualityComparer.Default);

// Group properties by containing type
var propertyGroups = properties
.GroupBy(p => p.Property.ContainingType, SymbolEqualityComparer.Default)
.ToDictionary(g => g.Key, g => g.ToList(), SymbolEqualityComparer.Default);

// Get all types that need processing
var allTypes = new HashSet<INamedTypeSymbol>(SymbolEqualityComparer.Default);

// Check if type needs INPC implementation
var needsInpc = !HasINPCImplementation(compilation, type, processedTypes) &&
(reactiveTypesSet.Contains(type) || // Has [Reactive] class attribute
propertyGroups.ContainsKey(type)); // Has [Reactive] properties
// Add types from reactive classes
foreach (var reactiveClass in reactiveClasses)
allTypes.Add(reactiveClass.Type);

if (needsInpc)
// Add types from properties with [Reactive] attribute
foreach (var property in properties)
{
var inpcSource = GenerateINPCImplementation(type);
if (!string.IsNullOrEmpty(inpcSource))
if (property.Property.ContainingType is INamedTypeSymbol type)
allTypes.Add(type);
}

// First pass: Process base types that need INPC
var typesToProcess = allTypes.ToList(); // Create a copy to avoid modification during enumeration
foreach (var type in typesToProcess)
{
var current = type.BaseType;
while (current is not null)
{
var fileName = $"{type.Name}.INPC.g.cs";
context.AddSource(fileName, SourceText.From(inpcSource, Encoding.UTF8));
processedTypes.Add(type);
allTypes.Add(current); // Add base type to processing queue
current = current.BaseType;
}
}
}

// Process properties
foreach (var group in propertyGroups)
{
var typeSymbol = group.Key as INamedTypeSymbol;
if (typeSymbol == null) continue;
// Process types in correct order (base types first)
foreach (var type in allTypes.OrderBy(t => GetTypeHierarchyDepth(t)))
{
// Skip if type already processed or inherits from ReactiveObject
if (processedTypes.Contains(type) || InheritsFromReactiveObject(type))
continue;

// Check if type needs INPC implementation
var needsInpc = !HasINPCImplementation(compilation, type, processedTypes) &&
(reactiveTypesSet.Contains(type) || // Has [Reactive] class attribute
propertyGroups.ContainsKey(type)); // Has [Reactive] properties

var source = GenerateClassSource(
typeSymbol,
group.Value.Select(p => p.Property).ToList(),
implementInpc: false, // INPC already implemented in first pass if needed
useLegacyMode);
if (needsInpc)
{
var inpcSource = GenerateINPCImplementation(type);
if (!string.IsNullOrEmpty(inpcSource))
{
var fileName = $"{type.Name}.INPC.g.cs";
context.AddSource(fileName, SourceText.From(inpcSource, Encoding.UTF8));
processedTypes.Add(type);
}
}
}

if (!string.IsNullOrEmpty(source))
// Process properties
foreach (var group in propertyGroups)
{
var fileName = $"{typeSymbol.Name}.ReactiveProperties.g.cs";
context.AddSource(fileName, SourceText.From(source, Encoding.UTF8));
var typeSymbol = group.Key as INamedTypeSymbol;
if (typeSymbol == null) continue;

var source = GenerateClassSource(
typeSymbol,
group.Value.Select(p => p.Property).ToList(),
implementInpc: false, // INPC already implemented in first pass if needed
useLegacyMode);

if (!string.IsNullOrEmpty(source))
{
var fileName = $"{typeSymbol.Name}.ReactiveProperties.g.cs";
context.AddSource(fileName, SourceText.From(source, Encoding.UTF8));
}
}
}
}

private static bool HasINPCImplementation(Compilation compilation, INamedTypeSymbol typeSymbol, HashSet<INamedTypeSymbol> processedTypes)
private static bool HasINPCImplementation(Compilation compilation, INamedTypeSymbol typeSymbol,
HashSet<INamedTypeSymbol> processedTypes)
{
var inpcType = compilation.GetTypeByMetadataName("System.ComponentModel.INotifyPropertyChanged");
if (inpcType is null)
Expand Down Expand Up @@ -392,7 +288,7 @@ private static string GetAccessorAccessibility(IMethodSymbol? accessor)
_ => accessor.DeclaredAccessibility.ToString().ToLowerInvariant()
};
}

private static string GenerateINPCImplementation(INamedTypeSymbol classSymbol)
{
var namespaceName = classSymbol.ContainingNamespace.IsGlobalNamespace
Expand All @@ -404,7 +300,7 @@ private static string GenerateINPCImplementation(INamedTypeSymbol classSymbol)
sb.AppendLine("// <auto-generated/>");
sb.AppendLine("#nullable enable");
sb.AppendLine();

sb.AppendLine("using System.ComponentModel;");
sb.AppendLine("using System.Runtime.CompilerServices;");
sb.AppendLine();
Expand All @@ -422,7 +318,8 @@ private static string GenerateINPCImplementation(INamedTypeSymbol classSymbol)
sb.AppendLine(" public event PropertyChangedEventHandler? PropertyChanged;");
sb.AppendLine();

sb.AppendLine(" protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)");
sb.AppendLine(
" protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)");
sb.AppendLine(" {");
sb.AppendLine(" PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));");
sb.AppendLine(" }");
Expand Down

0 comments on commit c196f01

Please sign in to comment.