Skip to content

Commit 2965c7e

Browse files
authored
Merge pull request #16 from thomashilzendegen/feature/skip-equals-method
Allow skipping of IEquatable<T> and comparison operators
2 parents 477d236 + d9bb6e3 commit 2965c7e

File tree

75 files changed

+1628
-118
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+1628
-118
lines changed

src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/AdHocUnions/AdHocUnionCodeGenerator.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ private void GenerateUnion(CancellationToken cancellationToken)
5858
[global::System.Diagnostics.CodeAnalysis.SuppressMessage(""ThinktectureRuntimeExtensionsAnalyzer"", ""TTRESG1000:Internal Thinktecture.Runtime.Extensions API usage"")]
5959
").Append(_state.IsReferenceType ? "sealed " : "readonly ").Append("partial ").AppendTypeKind(_state).Append(" ").Append(_state.Name).Append(" :");
6060

61-
if (!_state.IsRefStruct)
61+
if (!_state.IsRefStruct && !_state.Settings.SkipEqualityComparison)
6262
{
6363
_sb.Append(@"
6464
global::System.IEquatable<").AppendTypeFullyQualified(_state).Append(@">,
@@ -128,9 +128,13 @@ private void GenerateUnion(CancellationToken cancellationToken)
128128

129129
GenerateConversionsFromValue();
130130
GenerateConversionsToValue();
131-
GenerateEqualityOperators();
132-
GenerateEquals();
133-
GenerateGetHashCode();
131+
132+
if (!_state.Settings.SkipEqualityComparison)
133+
{
134+
GenerateEqualityOperators();
135+
GenerateEquals();
136+
GenerateGetHashCode();
137+
}
134138

135139
if (!_state.Settings.SkipToString)
136140
GenerateToString();

src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/AdHocUnions/AdHocUnionSettings.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ public sealed class AdHocUnionSettings : IEquatable<AdHocUnionSettings>
1313
public string SwitchMapStateParameterName { get; }
1414
public SerializationFrameworks SerializationFrameworks { get; }
1515
public bool UseSingleBackingField { get; }
16+
public bool SkipEqualityComparison { get; }
17+
1618

1719
public AdHocUnionSettings(
1820
AttributeData attribute,
@@ -28,6 +30,7 @@ public AdHocUnionSettings(
2830
SwitchMapStateParameterName = attribute.FindSwitchMapStateParameterName();
2931
SerializationFrameworks = attribute.FindSerializationFrameworks();
3032
UseSingleBackingField = attribute.FindUseSingleBackingField() ?? false;
33+
SkipEqualityComparison = attribute.FindSkipEqualityComparison() ?? false;
3134

3235
var memberTypeSettings = new AdHocUnionMemberTypeSetting[numberOfMemberTypes];
3336
MemberTypeSettings = memberTypeSettings;
@@ -61,6 +64,7 @@ public bool Equals(AdHocUnionSettings? other)
6164
&& SwitchMapStateParameterName == other.SwitchMapStateParameterName
6265
&& SerializationFrameworks == other.SerializationFrameworks
6366
&& UseSingleBackingField == other.UseSingleBackingField
67+
&& SkipEqualityComparison == other.SkipEqualityComparison
6468
&& MemberTypeSettings.SequenceEqual(other.MemberTypeSettings);
6569
}
6670

@@ -78,6 +82,7 @@ public override int GetHashCode()
7882
hashCode = (hashCode * 397) ^ SwitchMapStateParameterName.GetHashCode();
7983
hashCode = (hashCode * 397) ^ (int)SerializationFrameworks;
8084
hashCode = (hashCode * 397) ^ UseSingleBackingField.GetHashCode();
85+
hashCode = (hashCode * 397) ^ SkipEqualityComparison.GetHashCode();
8186
hashCode = (hashCode * 397) ^ MemberTypeSettings.ComputeHashCode();
8287

8388
return hashCode;

src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/Constants.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ public static class Properties
6767
public const string SKIP_ICOMPARABLE = "SkipIComparable";
6868
public const string ALLOW_DEFAULT_STRUCTS = "AllowDefaultStructs";
6969
public const string HAS_CORRESPONDING_CONSTRUCTOR = "HasCorrespondingConstructor";
70+
public const string SKIP_EQUALITY_COMPARISON = "SkipEqualityComparison";
7071
}
7172

7273
public static class ValueObject

src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/Diagnostics/ThinktectureRuntimeExtensionsAnalyzer.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,8 @@ private static void ValidateKeyMemberComparers(
610610
ValidateComparer(context, keyType, keyMemberComparerAttr, tdsLocation);
611611
ValidateComparer(context, keyType, keyMemberEqualityComparerAttr, tdsLocation);
612612

613+
var skipEqualityComparison = attributeOperation.FindSkipEqualityComparison() ?? false;
614+
613615
if (keyMemberComparerAttr is not null && keyMemberEqualityComparerAttr is null)
614616
{
615617
ReportDiagnostic(context,
@@ -619,7 +621,7 @@ private static void ValidateKeyMemberComparers(
619621
}
620622
else if (stringBasedRequiresEqualityComparer
621623
&& keyType.SpecialType == SpecialType.System_String
622-
&& keyMemberEqualityComparerAttr is null)
624+
&& keyMemberEqualityComparerAttr is null && !skipEqualityComparison)
623625
{
624626
ReportDiagnostic(context,
625627
DiagnosticsDescriptors.StringBasedValueObjectNeedsEqualityComparer,
@@ -733,6 +735,7 @@ private static void CheckAssignableMembers(
733735
Location tdsLocation)
734736
{
735737
var allowDefaultStructs = attribute.FindAllowDefaultStructs() ?? false;
738+
var skipEqualityComparison = attribute.FindSkipEqualityComparison() ?? false;
736739

737740
List<string>? membersWithDisallowDefaultValue = null;
738741
var hasStringMembersWithoutComparer = false;
@@ -760,7 +763,7 @@ private static void CheckAssignableMembers(
760763
CheckComparerTypes(context, assignableMember, tdsLocation);
761764
}
762765

763-
if (hasStringMembersWithoutComparer && !attribute.HasDefaultStringComparison())
766+
if (hasStringMembersWithoutComparer && !attribute.HasDefaultStringComparison() && !skipEqualityComparison)
764767
{
765768
ReportDiagnostic(context,
766769
DiagnosticsDescriptors.ComplexValueObjectWithStringMembersNeedsDefaultEqualityComparer,

src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/AllValueObjectSettings.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public sealed class AllValueObjectSettings : IEquatable<AllValueObjectSettings>,
1515
public bool SkipIComparable { get; }
1616
public bool SkipIParsable { get; }
1717
public bool SkipIFormattable { get; }
18+
public bool SkipEqualityComparison { get; }
1819
public bool SkipToString { get; }
1920
public OperatorsGeneration AdditionOperators { get; }
2021
public OperatorsGeneration SubtractionOperators { get; }
@@ -47,6 +48,7 @@ public AllValueObjectSettings(
4748
SkipIComparable = valueObjectAttribute.FindSkipIComparable() ?? false;
4849
SkipIParsable = SkipFactoryMethods || (valueObjectAttribute.FindSkipIParsable() ?? false);
4950
SkipIFormattable = valueObjectAttribute.FindSkipIFormattable() ?? false;
51+
SkipEqualityComparison = valueObjectAttribute.FindSkipEqualityComparison() ?? false;
5052
SkipToString = valueObjectAttribute.FindSkipToString() ?? false;
5153
AdditionOperators = SkipFactoryMethods ? OperatorsGeneration.None : valueObjectAttribute.FindAdditionOperators();
5254
SubtractionOperators = SkipFactoryMethods ? OperatorsGeneration.None : valueObjectAttribute.FindSubtractionOperators();
@@ -65,6 +67,12 @@ public AllValueObjectSettings(
6567
// Comparison operators depend on the equality comparison operators
6668
if (ComparisonOperators > EqualityComparisonOperators)
6769
EqualityComparisonOperators = ComparisonOperators;
70+
71+
if (SkipEqualityComparison)
72+
{
73+
ComparisonOperators = OperatorsGeneration.None;
74+
EqualityComparisonOperators = OperatorsGeneration.None;
75+
}
6876
}
6977

7078
public override bool Equals(object? obj)
@@ -92,6 +100,7 @@ public bool Equals(AllValueObjectSettings? other)
92100
&& SkipIComparable == other.SkipIComparable
93101
&& SkipIParsable == other.SkipIParsable
94102
&& SkipIFormattable == other.SkipIFormattable
103+
&& SkipEqualityComparison == other.SkipEqualityComparison
95104
&& SkipToString == other.SkipToString
96105
&& AdditionOperators == other.AdditionOperators
97106
&& SubtractionOperators == other.SubtractionOperators
@@ -125,6 +134,7 @@ public override int GetHashCode()
125134
hashCode = (hashCode * 397) ^ SkipIComparable.GetHashCode();
126135
hashCode = (hashCode * 397) ^ SkipIParsable.GetHashCode();
127136
hashCode = (hashCode * 397) ^ SkipIFormattable.GetHashCode();
137+
hashCode = (hashCode * 397) ^ SkipEqualityComparison.GetHashCode();
128138
hashCode = (hashCode * 397) ^ SkipToString.GetHashCode();
129139
hashCode = (hashCode * 397) ^ (int)AdditionOperators;
130140
hashCode = (hashCode * 397) ^ (int)SubtractionOperators;

src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ComplexValueObjectCodeGenerator.cs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,16 @@ private void GenerateValueObject(CancellationToken cancellationToken)
5252
{
5353
_sb.Append(@"
5454
[global::System.Diagnostics.CodeAnalysis.SuppressMessage(""ThinktectureRuntimeExtensionsAnalyzer"", ""TTRESG1000:Internal Thinktecture.Runtime.Extensions API usage"")]
55-
").Append(_state.IsReferenceType ? "sealed " : "readonly ").Append("partial ").AppendTypeKind(_state).Append(" ").Append(_state.Name).AppendGenericTypeParameters(_state).Append(" : global::System.IEquatable<").AppendTypeFullyQualifiedNullAnnotated(_state).Append(@">,
56-
global::System.Numerics.IEqualityOperators<").AppendTypeFullyQualified(_state).Append(", ").AppendTypeFullyQualified(_state).Append(@", bool>,
55+
").Append(_state.IsReferenceType ? "sealed " : "readonly ").Append("partial ").AppendTypeKind(_state).Append(" ").Append(_state.Name).AppendGenericTypeParameters(_state).Append(" :");
56+
57+
if (!_state.Settings.SkipEqualityComparison)
58+
{
59+
_sb.Append(@"
60+
global::System.IEquatable<").AppendTypeFullyQualifiedNullAnnotated(_state).Append(@">,
61+
global::System.Numerics.IEqualityOperators<").AppendTypeFullyQualified(_state).Append(", ").AppendTypeFullyQualified(_state).Append(", bool>,");
62+
}
63+
64+
_sb.Append(@"
5765
global::Thinktecture.Internal.IMetadataOwner");
5866

5967
if (_state.DisallowsDefaultValue)
@@ -105,9 +113,13 @@ private void GenerateValueObject(CancellationToken cancellationToken)
105113
cancellationToken.ThrowIfCancellationRequested();
106114

107115
GenerateConstructor();
108-
GenerateEqualityOperators();
109-
GenerateEquals();
110-
GenerateGetHashCode();
116+
117+
if (!_state.Settings.SkipEqualityComparison)
118+
{
119+
GenerateEqualityOperators();
120+
GenerateEquals();
121+
GenerateGetHashCode();
122+
}
111123

112124
if (!_state.Settings.SkipToString)
113125
GenerateToString();

src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/KeyedValueObjectCodeGenerator.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,15 @@ private void GenerateValueObject(CancellationToken cancellationToken)
6262

6363
_sb.Append(@"
6464
[global::System.Diagnostics.CodeAnalysis.SuppressMessage(""ThinktectureRuntimeExtensionsAnalyzer"", ""TTRESG1000:Internal Thinktecture.Runtime.Extensions API usage"")]
65-
").Append(_state.IsReferenceType ? "sealed " : "readonly ").Append("partial ").AppendTypeKind(_state).Append(" ").Append(_state.Name).Append(" : global::System.IEquatable<").AppendTypeFullyQualifiedNullAnnotated(_state).Append(@">,
65+
").Append(_state.IsReferenceType ? "sealed " : "readonly ").Append("partial ").AppendTypeKind(_state).Append(" ").Append(_state.Name).Append(" :");
66+
67+
if (!_state.Settings.SkipEqualityComparison)
68+
{
69+
_sb.Append(@"
70+
global::System.IEquatable<").AppendTypeFullyQualifiedNullAnnotated(_state).Append(">,");
71+
}
72+
73+
_sb.Append(@"
6674
global::Thinktecture.IKeyedObject<").AppendTypeFullyQualified(_state.KeyMember).Append(@">,
6775
global::Thinktecture.IConvertible<").AppendTypeFullyQualified(_state.KeyMember).Append(@">,
6876
global::Thinktecture.Internal.IMetadataOwner");
@@ -136,8 +144,12 @@ private void GenerateValueObject(CancellationToken cancellationToken)
136144
cancellationToken.ThrowIfCancellationRequested();
137145

138146
GenerateConstructor();
139-
GenerateEquals();
140-
GenerateGetHashCode();
147+
148+
if (!_state.Settings.SkipEqualityComparison)
149+
{
150+
GenerateEquals();
151+
GenerateGetHashCode();
152+
}
141153

142154
if (!_state.Settings.SkipToString)
143155
GenerateToString();

src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ValueObjectSettings.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ namespace Thinktecture.CodeAnalysis.ValueObjects;
2222
public bool HasStructLayoutAttribute => _attributeInfo.HasStructLayoutAttribute;
2323
public string? KeyMemberEqualityComparerAccessor => _attributeInfo.KeyMemberEqualityComparerAccessor;
2424
public SerializationFrameworks SerializationFrameworks => _allSettings.SerializationFrameworks;
25+
public bool SkipEqualityComparison => _allSettings.SkipEqualityComparison;
2526

2627
public ValueObjectSettings(
2728
AllValueObjectSettings allSettings,
@@ -49,7 +50,8 @@ public bool Equals(ValueObjectSettings other)
4950
&& DefaultStringComparison == other.DefaultStringComparison
5051
&& HasStructLayoutAttribute == other.HasStructLayoutAttribute
5152
&& KeyMemberEqualityComparerAccessor == other.KeyMemberEqualityComparerAccessor
52-
&& SerializationFrameworks == other.SerializationFrameworks;
53+
&& SerializationFrameworks == other.SerializationFrameworks
54+
&& SkipEqualityComparison == other.SkipEqualityComparison;
5355
}
5456

5557
public override bool Equals(object? obj)
@@ -78,6 +80,7 @@ public override int GetHashCode()
7880
hashCode = (hashCode * 397) ^ HasStructLayoutAttribute.GetHashCode();
7981
hashCode = (hashCode * 397) ^ (KeyMemberEqualityComparerAccessor?.GetHashCode() ?? 0);
8082
hashCode = (hashCode * 397) ^ (int)SerializationFrameworks;
83+
hashCode = (hashCode * 397) ^ SkipEqualityComparison.GetHashCode();
8184

8285
return hashCode;
8386
}

src/Thinktecture.Runtime.Extensions.SourceGenerator/Extensions/AttributeDataExtensions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ public static class AttributeDataExtensions
8080
{
8181
return GetBooleanParameterValue(attributeData, "SkipIFormattable");
8282
}
83+
84+
public static bool? FindSkipEqualityComparison(this AttributeData attributeData)
85+
{
86+
return GetBooleanParameterValue(attributeData, "SkipEqualityComparison");
87+
}
8388

8489
public static OperatorsGeneration FindAdditionOperators(this AttributeData attributeData)
8590
{

src/Thinktecture.Runtime.Extensions.SourceGenerator/Extensions/ObjectCreationOperationExtensions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ public static class ObjectCreationOperationExtensions
2020
return GetBooleanParameterValue(operation.Initializer, Constants.Attributes.Properties.SKIP_KEY_MEMBER);
2121
}
2222

23+
public static bool? FindSkipEqualityComparison(this IObjectCreationOperation operation)
24+
{
25+
return GetBooleanParameterValue(operation.Initializer, Constants.Attributes.Properties.SKIP_EQUALITY_COMPARISON);
26+
}
27+
2328
public static bool? FindAllowDefaultStructs(this IObjectCreationOperation operation)
2429
{
2530
return GetBooleanParameterValue(operation.Initializer, Constants.Attributes.Properties.ALLOW_DEFAULT_STRUCTS);

0 commit comments

Comments
 (0)