static void BuildGetHashCode(ITypeSymbol symbol, AttributesMetadata attributesMetadata, StringBuilder sb) { var baseTypeName = symbol.BaseType?.ToFQF(); sb.AppendLine("#nullable enable"); sb.AppendLine(@"public override int GetHashCode() { var hashCode = new global::System.HashCode(); "); sb.AppendLine(baseTypeName == "object" ? "hashCode.Add(this.EqualityContract);" : "hashCode.Add(base.GetHashCode());"); foreach (var property in symbol.GetProperties()) { var propertyName = property.ToFQF(); if (propertyName == "EqualityContract") { continue; } BuildPropertyHashCode(property, attributesMetadata, sb); } sb.AppendLine("return hashCode.ToHashCode();"); sb.AppendLine("}"); sb.AppendLine("#nullable restore"); }
static void BuildEquals(ITypeSymbol symbol, AttributesMetadata attributesMetadata, StringBuilder sb) { var symbolName = symbol.ToFQF(); var baseTypeName = symbol.BaseType?.ToFQF(); sb.AppendLine("#nullable enable"); sb.AppendLine(symbol.IsSealed ? $"public bool Equals({symbolName}? other) {{" : $"public virtual bool Equals({symbolName}? other) {{"); sb.AppendLine(baseTypeName == "object" ? "return !ReferenceEquals(other, null) && EqualityContract == other.EqualityContract" : $"return base.Equals(({baseTypeName}?)other)"); foreach (var property in symbol.GetProperties()) { var propertyName = property.ToFQF(); if (propertyName == "EqualityContract") { continue; } BuildPropertyEquality(attributesMetadata, sb, property); } sb.AppendLine(";"); sb.AppendLine("}"); sb.AppendLine("#nullable restore"); }
static void BuildEquals(ITypeSymbol symbol, AttributesMetadata attributesMetadata, StringBuilder sb, bool explicitMode) { var symbolName = symbol.ToFQF(); var baseTypeName = symbol.BaseType?.ToFQF(); sb.AppendLine(InheritDocComment); sb.AppendLine(GeneratedCodeAttributeDeclaration); sb.AppendLine(symbol.IsSealed ? $"public bool Equals({symbolName}? other) {{" : $"public virtual bool Equals({symbolName}? other) {{"); sb.AppendLine(baseTypeName == "object" ? "return !ReferenceEquals(other, null) && EqualityContract == other.EqualityContract" : $"return base.Equals(({baseTypeName}?)other)"); foreach (var property in symbol.GetProperties()) { var propertyName = property.ToFQF(); if (propertyName == "EqualityContract") { continue; } BuildPropertyEquality(attributesMetadata, sb, property, explicitMode); } sb.AppendLine(";"); sb.AppendLine("}"); }
static void BuildEquals(ITypeSymbol symbol, AttributesMetadata attributesMetadata, StringBuilder sb) { var symbolName = symbol.ToFQF(); var baseTypeName = symbol.BaseType?.ToFQF(); sb.AppendLine("#nullable enable"); sb.AppendLine($"public static bool operator ==({symbolName}? a, {symbolName}? b) => global::System.Collections.Generic.EqualityComparer<{symbolName}>.Default.Equals(a, b);"); sb.AppendLine($"public static bool operator !=({symbolName}? a, {symbolName}? b) => !(a == b);"); sb.AppendLine($"public override bool Equals(object? obj) => Equals(obj as {symbolName});"); sb.AppendLine($"public bool Equals({symbolName}? other) {{"); sb.AppendLine(baseTypeName == "object" ? "return !ReferenceEquals(other, null) && this.GetType() == other.GetType()" : $"return base.Equals(other as {baseTypeName})"); foreach (var property in symbol.GetProperties()) { BuildPropertyEquality(attributesMetadata, sb, property); } sb.AppendLine(";"); sb.AppendLine("}"); sb.AppendLine("#nullable restore"); }
static void BuildGetHashCode(ITypeSymbol symbol, AttributesMetadata attributesMetadata, StringBuilder sb, bool explicitMode) { var baseTypeName = symbol.BaseType?.ToFQF(); sb.AppendLine(InheritDocComment); sb.AppendLine(GeneratedCodeAttributeDeclaration); sb.AppendLine(@"public override int GetHashCode() { var hashCode = new global::System.HashCode(); "); sb.AppendLine(baseTypeName == "object" ? "hashCode.Add(this.EqualityContract);" : "hashCode.Add(base.GetHashCode());"); foreach (var property in symbol.GetProperties()) { var propertyName = property.ToFQF(); if (propertyName == "EqualityContract") { continue; } BuildPropertyHashCode(property, attributesMetadata, sb, explicitMode); } sb.AppendLine("return hashCode.ToHashCode();"); sb.AppendLine("}"); }
static void BuildEquals(ITypeSymbol symbol, AttributesMetadata attributesMetadata, StringBuilder sb, bool explicitMode) { var symbolName = symbol.ToFQF(); var baseTypeName = symbol.BaseType?.ToFQF(); sb.AppendLine(EqualsOperatorCodeComment); sb.AppendLine(GeneratedCodeAttributeDeclaration); sb.AppendLine($"public static bool operator ==({symbolName}? left, {symbolName}? right) => global::System.Collections.Generic.EqualityComparer<{symbolName}?>.Default.Equals(left, right);"); sb.AppendLine(NotEqualsOperatorCodeComment); sb.AppendLine(GeneratedCodeAttributeDeclaration); sb.AppendLine($"public static bool operator !=({symbolName}? left, {symbolName}? right) => !(left == right);"); sb.AppendLine(InheritDocComment); sb.AppendLine(GeneratedCodeAttributeDeclaration); sb.AppendLine($"public override bool Equals(object? obj) => Equals(obj as {symbolName});"); sb.AppendLine(InheritDocComment); sb.AppendLine(GeneratedCodeAttributeDeclaration); sb.AppendLine($"public bool Equals({symbolName}? other) {{"); sb.AppendLine(baseTypeName == "object" ? "return !ReferenceEquals(other, null) && this.GetType() == other.GetType()" : $"return base.Equals(other as {baseTypeName})"); foreach (var property in symbol.GetProperties()) { BuildPropertyEquality(attributesMetadata, sb, property, explicitMode); } sb.AppendLine(";"); sb.AppendLine("}"); }
public static string Generate(ITypeSymbol symbol, AttributesMetadata attributesMetadata) { var code = ContainingTypesBuilder.Build(symbol, includeSelf: true, content: sb => { BuildEquals(symbol, attributesMetadata, sb); BuildGetHashCode(symbol, attributesMetadata, sb); }); return(code); }
public static string Generate(ITypeSymbol symbol, AttributesMetadata attributesMetadata) { var code = ContainingTypesBuilder.Build(symbol, includeSelf: false, content: sb => { var typeName = symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); sb.AppendLine($"partial class {typeName} : global::System.IEquatable<{typeName}> {{"); BuildEquals(symbol, attributesMetadata, sb); BuildGetHashCode(symbol, attributesMetadata, sb); sb.AppendLine("}"); }); return(code); }
public static string Generate(ITypeSymbol symbol, AttributesMetadata attributesMetadata, bool explicitMode) { var code = ContainingTypesBuilder.Build(symbol, includeSelf: true, content: sb => { sb.AppendLine(EnableNullableContext); sb.AppendLine(SuppressObsoleteWarningsPragma); BuildEquals(symbol, attributesMetadata, sb, explicitMode); BuildGetHashCode(symbol, attributesMetadata, sb, explicitMode); sb.AppendLine(RestoreObsoleteWarningsPragma); sb.AppendLine(RestoreNullableContext); }); return(code); }
public static void BuildPropertyHashCode(IPropertySymbol property, AttributesMetadata attributesMetadata, StringBuilder sb) { if (property.HasAttribute(attributesMetadata.IgnoreEquality)) { return; } var propertyName = property.ToFQF(); var typeName = property.Type.ToNullableFQF(); sb.Append($"hashCode.Add(this.{propertyName}!, "); if (property.HasAttribute(attributesMetadata.UnorderedEquality)) { var types = property.GetIDictionaryTypeArguments(); if (types != null) { sb.Append( $"global::Generator.Equals.DictionaryEqualityComparer<{string.Join(", ", types.Value)}>.Default"); } else { types = property.GetIEnumerableTypeArguments() !; sb.Append( $"global::Generator.Equals.UnorderedEqualityComparer<{string.Join(", ", types.Value)}>.Default"); } } else if (property.HasAttribute(attributesMetadata.OrderedEquality)) { var types = property.GetIEnumerableTypeArguments() !; sb.Append( $"global::Generator.Equals.OrderedEqualityComparer<{string.Join(", ", types.Value)}>.Default"); } else if (property.HasAttribute(attributesMetadata.ReferenceEquality)) { sb.Append($"global::Generator.Equals.ReferenceEqualityComparer<{typeName}>.Default"); } else { sb.Append($"global::System.Collections.Generic.EqualityComparer<{typeName}>.Default"); } sb.AppendLine(");"); }
public static string Generate(ITypeSymbol symbol, AttributesMetadata attributesMetadata, bool explicitMode) { var code = ContainingTypesBuilder.Build(symbol, includeSelf: false, content: sb => { var typeName = symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); sb.AppendLine($"partial class {typeName} : global::System.IEquatable<{typeName}> {{"); sb.AppendLine(EnableNullableContext); sb.AppendLine(SuppressObsoleteWarningsPragma); BuildEquals(symbol, attributesMetadata, sb, explicitMode); BuildGetHashCode(symbol, attributesMetadata, sb, explicitMode); sb.AppendLine(RestoreObsoleteWarningsPragma); sb.AppendLine(RestoreNullableContext); sb.AppendLine("}"); }); return(code); }
public static void BuildPropertyEquality(AttributesMetadata attributesMetadata, StringBuilder sb, IPropertySymbol property, bool explicitMode) { if (property.HasAttribute(attributesMetadata.IgnoreEquality)) { return; } var propertyName = property.ToFQF(); var typeName = property.Type.ToNullableFQF(); if (property.HasAttribute(attributesMetadata.UnorderedEquality)) { var types = property.GetIDictionaryTypeArguments(); if (types != null) { sb.AppendLine( $"&& global::Generator.Equals.DictionaryEqualityComparer<{string.Join(", ", types.Value)}>.Default.Equals({propertyName}!, other.{propertyName}!)"); } else { types = property.GetIEnumerableTypeArguments() !; sb.AppendLine( $"&& global::Generator.Equals.UnorderedEqualityComparer<{string.Join(", ", types.Value)}>.Default.Equals({propertyName}!, other.{propertyName}!)"); } } else if (property.HasAttribute(attributesMetadata.OrderedEquality)) { var types = property.GetIEnumerableTypeArguments() !; sb.AppendLine( $"&& global::Generator.Equals.OrderedEqualityComparer<{string.Join(", ", types.Value)}>.Default.Equals({propertyName}!, other.{propertyName}!)"); } else if (property.HasAttribute(attributesMetadata.ReferenceEquality)) { sb.AppendLine( $"&& global::Generator.Equals.ReferenceEqualityComparer<{typeName}>.Default.Equals({propertyName}!, other.{propertyName}!)"); } else if (property.HasAttribute(attributesMetadata.SetEquality)) { var types = property.GetIEnumerableTypeArguments() !; sb.AppendLine( $"&& global::Generator.Equals.SetEqualityComparer<{string.Join(", ", types.Value)}>.Default.Equals({propertyName}!, other.{propertyName}!)"); } else if (property.HasAttribute(attributesMetadata.CustomEquality)) { var attribute = property.GetAttribute(attributesMetadata.CustomEquality); var comparerType = (INamedTypeSymbol)attribute?.ConstructorArguments[0].Value !; var comparerMemberName = (string)attribute?.ConstructorArguments[1].Value !; if (comparerType.GetMembers().Any(x => x.Name == comparerMemberName && x.IsStatic) || comparerType.GetProperties().Any(x => x.Name == comparerMemberName && x.IsStatic)) { sb.AppendLine( $"&& {comparerType.ToFQF()}.{comparerMemberName}.Equals({propertyName}!, other.{propertyName}!)"); } else { sb.AppendLine( $"&& new {comparerType.ToFQF()}().Equals({propertyName}!, other.{propertyName}!)"); } } else if ( !explicitMode || property.HasAttribute(attributesMetadata.DefaultEquality)) { sb.AppendLine( $"&& global::System.Collections.Generic.EqualityComparer<{typeName}>.Default.Equals({propertyName}!, other.{propertyName}!)"); } }