Skip to content

Fix false positive for Equals/CompareTo with nullable reference types#21328

Draft
Copilot wants to merge 3 commits intomainfrom
copilot/fix-equatable-equals-alert
Draft

Fix false positive for Equals/CompareTo with nullable reference types#21328
Copilot wants to merge 3 commits intomainfrom
copilot/fix-equatable-equals-alert

Conversation

Copy link
Contributor

Copilot AI commented Feb 16, 2026

Problem

CodeQL queries ClassDoesNotImplementEquals.ql and IncorrectEqualsSignature.ql incorrectly flag classes implementing Equals(object?) as not implementing Equals(object):

#nullable enable

class MyClass : IEquatable<MyClass>
{
    public bool Equals(MyClass? other) => /* ... */;
    
    // False positive: "Class 'MyClass' does not implement Equals(object)"
    public override bool Equals(object? obj) => /* ... */;
    
    public override int GetHashCode() => /* ... */;
}

Changes

Removed redundant instanceof ObjectType parameter type checks from framework method identifiers in System.qll:

  • SystemIComparableInterface.getCompareToMethod()
  • SystemObjectClass.getEqualsMethod()
  • SystemObjectClass.getStaticEqualsMethod()
  • SystemObjectClass.getReferenceEqualsMethod()

These methods identify specific framework methods where declaring type + method name + parameter count already provide unique identification. The parameter type checks were unnecessary and caused false positives with nullable reference types.

Tests

  • Added NullableTest.cs with nullable Equals implementations
  • Extended library tests in Equals.cs for nullable patterns
Original prompt

This section details on the original issue you should resolve

<issue_title>False positive - C# IEquatable: Equals(object) not implemented alert when Equals(object?) is implemented</issue_title>
<issue_description>Description of the false positive

CodeQL will complain about a missing override for Equals(object obj) not existing, if the Equals method is implemented within a nullable object as parameter. Using Equals(object? obj) is valid.

Two different alerts appeared on a PR.

Code sample

Sadly, working in closed source, but this sample should do. I do not know if this triggers the false positive in practice, as I can't push it to test, but it should give you a good example. I also added a small a bit of code to show that Equals(object? obj) is valid and working when using Equals().

using System;
using System.Linq;

#nullable enable
public class Program
{
	public class MyClass : IEquatable<MyClass>
	{
		private object property;
		public MyClass()
		{
			property = 1;
		}

		public bool Equals(MyClass? other)
		{
			Console.WriteLine("MyClass? called");
			if (ReferenceEquals(null, other))
			{
				return true;
			}

			return Equals(property, other.property);
		}

		public override bool Equals(object? obj)
		{
			Console.WriteLine("object? called");
			if (ReferenceEquals(null, obj))
			{
				return false;
			}

			if (ReferenceEquals(this, obj))
			{
				return true;
			}

			if (obj.GetType() != GetType())
			{
				return false;
			}

			return Equals((MyClass)obj);
		}

		public override int GetHashCode()
		{
			return HashCode.Combine(property);
		}
	}

	public static void Main()
	{
		var a = new MyClass();
		var b = new MyClass();
		Console.WriteLine(a.Equals(b)); // Equals(MyClass? other)
		Console.WriteLine(Equals(a, b)); // Equals(object? obj)
		Console.WriteLine(IEquatable<MyClass>.Equals(a, b)); // Equals(object? obj)
	}
}

Check 1 (failure check)

The CodeQl error message goes as follows for the override bool Equals(object? obj) line:
Class 'MyClass' does not implement Equals(object), but it implements IEquatable.Equals
The IEquatable.Equals points to bool Equals(MyClass? other).

Error 2 (alert):
The warning goes for the same function override bool Equals(object? obj)
The declaring(MyClass) type of this 'Equals(Object)' method does not override 'Equals(object)'.

Source for alerts
https://github.com/github/codeql/blob/main/csharp/ql/src/API%20Abuse/ClassDoesNotImplementEquals.ql

https://github.com/github/codeql/blob/28b6aa8616a393ebb45186e3ba4df004a0f3ef4e/csharp/ql/src/API%20Abuse/IncorrectEqualsSignature.ql</issue_description>

Comments on the Issue (you are @copilot in this section)

@hvitved I believe the fix here may be to remove all the `result.getParameter(0).getType() instanceof ObjectType` occurrences from https://github.com/github/codeql/blob/28b6aa8616a393ebb45186e3ba4df004a0f3ef4e/csharp/ql/lib/semmle/code/csharp/frameworks/System.qll.

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits February 16, 2026 10:34
Removes instanceof ObjectType checks from method signatures in System.qll to support
nullable reference types (object?). This fixes false positives when Equals(object?)
is used instead of Equals(object), as they are the same underlying type with different
nullability annotations.

Fixes:
- SystemIComparableInterface.getCompareToMethod()
- SystemObjectClass.getEqualsMethod()
- SystemObjectClass.getStaticEqualsMethod()
- SystemObjectClass.getReferenceEqualsMethod()

Co-authored-by: hvitved <3667920+hvitved@users.noreply.github.com>
Adds test cases for Equals methods with nullable reference type parameters
(object?) to verify the fix works correctly.

Co-authored-by: hvitved <3667920+hvitved@users.noreply.github.com>
@github-actions github-actions bot added the C# label Feb 16, 2026
Copilot AI changed the title [WIP] Fix false positive alert for IEquatable Equals implementation Fix false positive for Equals/CompareTo with nullable reference types Feb 16, 2026
Copilot AI requested a review from hvitved February 16, 2026 10:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

False positive - C# IEquatable: Equals(object) not implemented alert when Equals(object?) is implemented

2 participants