-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
using System; | ||
|
||
namespace OpenRA | ||
{ | ||
[AttributeUsage(AttributeTargets.Class)] | ||
public class SyncGenerationAttribute : Attribute | ||
{ | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.Linq; | ||
using Microsoft.CodeAnalysis; | ||
|
||
namespace OpenRA.SourceGenerators.Sync | ||
{ | ||
public sealed class SyncClassInfo : IEquatable<SyncClassInfo> | ||
{ | ||
public string? Namespace { get; } | ||
Check failure on line 11 in OpenRA.SourceGenerators/Sync/SyncClassInfo.cs GitHub Actions / Windows (.NET 6.0)
|
||
public string Name { get; } | ||
public IReadOnlyList<SyncMember> SyncMembers { get; } | ||
|
||
public SyncClassInfo(ITypeSymbol type) | ||
{ | ||
Namespace = type.ContainingNamespace.IsGlobalNamespace ? null : type.ContainingNamespace.ToString(); | ||
Name = type.Name; | ||
//Debugger.Launch(); | ||
Check failure on line 19 in OpenRA.SourceGenerators/Sync/SyncClassInfo.cs GitHub Actions / Windows (.NET 6.0)
Check failure on line 19 in OpenRA.SourceGenerators/Sync/SyncClassInfo.cs GitHub Actions / Windows (.NET 6.0)
Check failure on line 19 in OpenRA.SourceGenerators/Sync/SyncClassInfo.cs GitHub Actions / Windows (.NET 6.0)
Check failure on line 19 in OpenRA.SourceGenerators/Sync/SyncClassInfo.cs GitHub Actions / Linux (.NET 6.0)
Check failure on line 19 in OpenRA.SourceGenerators/Sync/SyncClassInfo.cs GitHub Actions / Linux (.NET 6.0)
Check failure on line 19 in OpenRA.SourceGenerators/Sync/SyncClassInfo.cs GitHub Actions / Linux (.NET 6.0)
|
||
|
||
var result = new List<SyncMember>(); | ||
var members = type.GetMembers().Where(m => m.GetAttributes().Any(a => a.AttributeClass.Name == "SyncAttribute")) | ||
.ToList(); | ||
|
||
foreach (var member in members) | ||
{ | ||
if (member is IFieldSymbol field) | ||
{ | ||
result.Add(new SyncMember | ||
{ | ||
Name = field.Name, | ||
Type = field.Type.Name | ||
}); | ||
} | ||
|
||
if (member is IPropertySymbol property) | ||
{ | ||
result.Add(new SyncMember | ||
{ | ||
Name = property.Name, | ||
Type = property.Type.Name | ||
}); | ||
} | ||
} | ||
Check failure on line 44 in OpenRA.SourceGenerators/Sync/SyncClassInfo.cs GitHub Actions / Windows (.NET 6.0)
Check failure on line 44 in OpenRA.SourceGenerators/Sync/SyncClassInfo.cs GitHub Actions / Linux (.NET 6.0)
|
||
//HasNameProperty = type.GetMembers().Any(m => m.Name == "Name" | ||
Check failure on line 45 in OpenRA.SourceGenerators/Sync/SyncClassInfo.cs GitHub Actions / Windows (.NET 6.0)
Check failure on line 45 in OpenRA.SourceGenerators/Sync/SyncClassInfo.cs GitHub Actions / Linux (.NET 6.0)
|
||
// && m is IPropertySymbol property | ||
// && property.Type.SpecialType == SpecialType.System_String); | ||
Check failure on line 47 in OpenRA.SourceGenerators/Sync/SyncClassInfo.cs GitHub Actions / Windows (.NET 6.0)
Check failure on line 47 in OpenRA.SourceGenerators/Sync/SyncClassInfo.cs GitHub Actions / Linux (.NET 6.0)
|
||
|
||
SyncMembers = result; | ||
} | ||
|
||
public override bool Equals(object? obj) | ||
Check failure on line 52 in OpenRA.SourceGenerators/Sync/SyncClassInfo.cs GitHub Actions / Windows (.NET 6.0)
|
||
{ | ||
return obj is SyncClassInfo other && Equals(other); | ||
} | ||
|
||
public bool Equals(SyncClassInfo? other) | ||
Check failure on line 57 in OpenRA.SourceGenerators/Sync/SyncClassInfo.cs GitHub Actions / Windows (.NET 6.0)
|
||
{ | ||
if (ReferenceEquals(null, other)) | ||
return false; | ||
if (ReferenceEquals(this, other)) | ||
return true; | ||
|
||
return Namespace == other.Namespace | ||
&& Name == other.Name; | ||
} | ||
|
||
public override int GetHashCode() | ||
{ | ||
unchecked | ||
{ | ||
var hashCode = (Namespace != null ? Namespace.GetHashCode() : 0); | ||
hashCode = (hashCode * 397) ^ Name.GetHashCode(); | ||
|
||
return hashCode; | ||
} | ||
} | ||
} | ||
|
||
public class SyncMember | ||
{ | ||
public string Name { get; set; } | ||
public string Type { get; set; } | ||
|
||
} | ||
Check failure on line 85 in OpenRA.SourceGenerators/Sync/SyncClassInfo.cs GitHub Actions / Windows (.NET 6.0)
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.Linq; | ||
using System.Text; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
|
||
namespace OpenRA.SourceGenerators.Sync | ||
{ | ||
public static class SyncCodeGenerator | ||
{ | ||
public static string Generate(SyncClassInfo syncClassInfo) | ||
{ | ||
var ns = syncClassInfo.Namespace; | ||
var name = syncClassInfo.Name; | ||
|
||
var sb = new StringBuilder(@"// <auto-generated /> | ||
#nullable enable"); | ||
|
||
|
||
sb.Append($@" | ||
using OpenRA; | ||
{(ns is null ? null : $@"namespace {ns} | ||
{{")} | ||
partial class {name} | ||
{{ | ||
public int GetSyncHash() | ||
{{ | ||
return "); | ||
|
||
GenerateHashCode(sb, syncClassInfo.SyncMembers); | ||
|
||
sb.Append($@" | ||
}} | ||
}} | ||
{(ns is null ? null : @"} | ||
")}"); | ||
|
||
return sb.ToString(); | ||
} | ||
|
||
private static void GenerateHashCode(StringBuilder sb, IReadOnlyList<SyncMember> itemNames) | ||
{ | ||
var delimiter = ""; | ||
|
||
//Debugger.Launch(); | ||
|
||
foreach (var item in itemNames) | ||
{ | ||
sb.Append(delimiter); | ||
if (item.Type == "Boolean") | ||
{ | ||
sb.Append($"Sync.HashBool({item.Name})"); | ||
} | ||
else if(item.Type == "WPos") | ||
{ | ||
sb.Append($"{item.Name}.GetHashCode()"); | ||
} | ||
else if (item.Type == "CPos") | ||
{ | ||
sb.Append($"{item.Name}.Bits"); | ||
} | ||
else if (item.Type == "WAngle") | ||
{ | ||
sb.Append($"{item.Name}.GetHashCode()"); | ||
} | ||
|
||
delimiter = " ^ "; | ||
} | ||
|
||
sb.Append(";"); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using System.Diagnostics; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
|
||
namespace OpenRA.SourceGenerators.Sync | ||
{ | ||
[Generator] | ||
public class SyncGenerator : IIncrementalGenerator | ||
{ | ||
const string SyncGenerationAttribute = "OpenRA.SyncGenerationAttribute"; | ||
public void Initialize(IncrementalGeneratorInitializationContext context) | ||
{ | ||
|
||
var enumTypes = context.SyntaxProvider | ||
.ForAttributeWithMetadataName(SyncGenerationAttribute, | ||
CouldBeEnumerationAsync, | ||
GetSyncClassInfo) | ||
.Collect() | ||
.SelectMany((classInfos, _) => classInfos.Distinct()); | ||
|
||
context.RegisterSourceOutput(enumTypes, GenerateCode); | ||
} | ||
|
||
|
||
private static bool CouldBeEnumerationAsync(SyntaxNode syntaxNode, CancellationToken cancellationToken) | ||
{ | ||
return syntaxNode is ClassDeclarationSyntax classDeclaration && IsPartial(classDeclaration); | ||
} | ||
|
||
private SyncClassInfo GetSyncClassInfo(GeneratorAttributeSyntaxContext context, CancellationToken cancellationToken) | ||
{ | ||
var type = (INamedTypeSymbol)context.TargetSymbol; | ||
var enumInfo = new SyncClassInfo(type); | ||
|
||
|
||
|
||
return enumInfo; | ||
} | ||
|
||
public static bool IsPartial(ClassDeclarationSyntax classDeclaration) | ||
{ | ||
return classDeclaration.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword)); | ||
} | ||
|
||
private static void GenerateCode(SourceProductionContext context, SyncClassInfo classInfo) | ||
{ | ||
|
||
var ns = classInfo.Namespace is null ? null : $"{classInfo.Namespace}."; | ||
var code = SyncCodeGenerator.Generate(classInfo); | ||
|
||
if (!String.IsNullOrWhiteSpace(code)) | ||
context.AddSource($"{ns}{classInfo.Name}.g.cs", code); | ||
|
||
} | ||
|
||
} | ||
|
||
} | ||
Check failure on line 65 in OpenRA.SourceGenerators/Sync/SyncGenerator.cs GitHub Actions / Linux (.NET 6.0)
|