@@ -210,6 +210,29 @@ private static IdentifierNameSyntax GetGenerationalMethodName(IdentifierNameSynt
210210 return SyntaxFactory . IdentifierName ( baseName . Identifier . ValueText + generation . ToString ( CultureInfo . InvariantCulture ) ) ;
211211 }
212212
213+ /// <summary>
214+ /// Checks whether a type defines equality operators for itself.
215+ /// </summary>
216+ /// <param name="symbol">The type to check.</param>
217+ /// <returns><c>true</c> if the == and != operators are defined on the type.</returns>
218+ private static bool HasEqualityOperators ( ITypeSymbol symbol )
219+ {
220+ Requires . NotNull ( symbol , nameof ( symbol ) ) ;
221+
222+ // Reference types inherit their equality operators from System.Object.
223+ if ( symbol . IsReferenceType )
224+ {
225+ return true ;
226+ }
227+
228+ var equalityOperators = from method in symbol . GetMembers ( ) . OfType < IMethodSymbol > ( )
229+ where method . MethodKind == MethodKind . BuiltinOperator || method . MethodKind == MethodKind . UserDefinedOperator
230+ where method . Parameters . Length == 2 && method . Parameters . All ( p => p . Type == symbol )
231+ where method . Name == "op_Equality"
232+ select method ;
233+ return equalityOperators . Any ( ) ;
234+ }
235+
213236 private void ReportDiagnostic ( string id , SyntaxNode blamedSyntax , params string [ ] formattingArgs )
214237 {
215238 Requires . NotNull ( blamedSyntax , nameof ( blamedSyntax ) ) ;
@@ -533,18 +556,20 @@ private IEnumerable<MethodDeclarationSyntax> CreateWithCoreMethods()
533556 private MemberDeclarationSyntax CreateWithFactoryMethod ( )
534557 {
535558 // (field.IsDefined && field.Value != this.field)
536- Func < IdentifierNameSyntax , IdentifierNameSyntax , ExpressionSyntax > isChangedByNames = ( propertyName , fieldName ) =>
537- SyntaxFactory . ParenthesizedExpression (
538- SyntaxFactory . BinaryExpression (
539- SyntaxKind . LogicalAndExpression ,
540- Syntax . OptionalIsDefined ( fieldName ) ,
559+ Func < IdentifierNameSyntax , IdentifierNameSyntax , ITypeSymbol , ExpressionSyntax > isChangedByNames = ( propertyName , fieldName , fieldType ) =>
560+ fieldType == null || HasEqualityOperators ( fieldType ) ?
561+ ( ExpressionSyntax ) SyntaxFactory . ParenthesizedExpression (
541562 SyntaxFactory . BinaryExpression (
542- SyntaxKind . NotEqualsExpression ,
543- Syntax . OptionalValue ( fieldName ) ,
544- Syntax . ThisDot ( propertyName ) ) ) ) ;
545- Func < MetaField , ExpressionSyntax > isChanged = v => isChangedByNames ( v . NameAsProperty , v . NameAsField ) ;
563+ SyntaxKind . LogicalAndExpression ,
564+ Syntax . OptionalIsDefined ( fieldName ) ,
565+ SyntaxFactory . BinaryExpression (
566+ SyntaxKind . NotEqualsExpression ,
567+ Syntax . OptionalValue ( fieldName ) ,
568+ Syntax . ThisDot ( propertyName ) ) ) ) :
569+ Syntax . OptionalIsDefined ( fieldName ) ;
570+ Func < MetaField , ExpressionSyntax > isChanged = v => isChangedByNames ( v . NameAsProperty , v . NameAsField , v . Symbol . Type ) ;
546571 var anyChangesExpression =
547- new ExpressionSyntax [ ] { isChangedByNames ( IdentityPropertyName , IdentityParameterName ) } . Concat (
572+ new ExpressionSyntax [ ] { isChangedByNames ( IdentityPropertyName , IdentityParameterName , null ) } . Concat (
548573 this . applyToMetaType . AllFields . Select ( isChanged ) )
549574 . ChainBinaryExpressions ( SyntaxKind . LogicalOrExpression ) ;
550575
0 commit comments