namespace Celeste.Mod.Roslyn.ModLifecycleAttributes; internal sealed class LifecycleMethod : IEquatable { public readonly MethodKind Kind; public readonly string TypeFqn; public readonly string Identifier; // excluded from value equality as recommended by the cookbook public readonly MethodDeclarationSyntax Declaration; private LifecycleMethod(MethodDeclarationSyntax declaration, MethodKind kind) { Kind = kind; Declaration = declaration; Identifier = declaration.Identifier.ValueText; Stack fqnParts = []; for (SyntaxNode? parentNode = declaration.Parent; parentNode is not null; parentNode = parentNode.Parent) { switch (parentNode) { case TypeDeclarationSyntax type: fqnParts.Push(type.Identifier.ValueText); break; case BaseNamespaceDeclarationSyntax namespaceBlock: fqnParts.Push(namespaceBlock.Name.ToString()); break; } } TypeFqn = string.Join(".", fqnParts); } public static LifecycleMethod AsLoad(GeneratorAttributeSyntaxContext syntaxContext, CancellationToken token) => new((MethodDeclarationSyntax)syntaxContext.TargetNode, MethodKind.Load); public static LifecycleMethod AsInitialize(GeneratorAttributeSyntaxContext syntaxContext, CancellationToken token) => new((MethodDeclarationSyntax)syntaxContext.TargetNode, MethodKind.Initialize); public static LifecycleMethod AsLoadContent(GeneratorAttributeSyntaxContext syntaxContext, CancellationToken token) => new((MethodDeclarationSyntax)syntaxContext.TargetNode, MethodKind.LoadContent); public static LifecycleMethod AsUnload(GeneratorAttributeSyntaxContext syntaxContext, CancellationToken token) => new((MethodDeclarationSyntax)syntaxContext.TargetNode, MethodKind.Unload); public enum MethodKind { Load, Initialize, LoadContent, Unload, } public override string ToString() => $"{nameof(LifecycleMethod)} ({Kind}): {TypeFqn}::{Identifier}"; #region ide-generated public bool Equals(LifecycleMethod? other) { if (other is null) return false; if (ReferenceEquals(this, other)) return true; return Kind == other.Kind && Identifier == other.Identifier && TypeFqn == other.TypeFqn; } public override bool Equals(object? obj) => ReferenceEquals(this, obj) || obj is LifecycleMethod other && Equals(other); public override int GetHashCode() { unchecked { int hashCode = (int)Kind; hashCode = (hashCode * 397) ^ Identifier.GetHashCode(); hashCode = (hashCode * 397) ^ TypeFqn.GetHashCode(); return hashCode; } } public static bool operator ==(LifecycleMethod? left, LifecycleMethod? right) => Equals(left, right); public static bool operator !=(LifecycleMethod? left, LifecycleMethod? right) => !Equals(left, right); #endregion }