rspec/rules/S7417/rust/rule.adoc
github-actions[bot] b16523921f
Create rule S7417 Manual PartialOrd implementation should be avoided when Ord is derived (#4757)
* Create rule S7417

* Update rule.adoc

* Update metadata.json

* Update metadata.json

---------

Co-authored-by: sallaigy <sallaigy@users.noreply.github.com>
Co-authored-by: Gyula Sallai <gyula.sallai@sonarsource.com>
2025-03-19 14:09:19 +00:00

60 lines
1.5 KiB
Plaintext

== Why is this an issue?
Manually implementing `PartialOrd` for a type that derives `Ord` can lead to inconsistencies, as the implementations of these traits must agree for sorting and other comparisons. According to the trait contract, the following must hold for any type implementing `Ord`:
[source,rust]
----
k1.cmp(&k2) == k1.partial_cmp(&k2).unwrap()
----
Using a default-generated `Ord` implementation with an explicitly defined `PartialOrd` is a risky practice that may cause unexpected behavior.
=== Code examples
==== Noncompliant code example
[source,rust,diff-id=1,diff-type=noncompliant]
----
#[derive(Ord, PartialEq, Eq)]
struct Foo;
impl PartialOrd for Foo {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
None // Noncompliant: Manually implemented PartialOrd when Ord is derived.
}
}
----
==== Compliant solution
[source,rust,diff-id=1,diff-type=compliant]
----
#[derive(PartialEq, Eq)]
struct Foo;
impl PartialOrd for Foo {
fn partial_cmp(&self, other: &Foo) -> Option<Ordering> {
Some(self.cmp(other)) // Compliant: Manual implementation is consistent with Ord.
}
}
impl Ord for Foo {
fn cmp(&self, other: &Foo) -> Ordering {
// Implementation here
}
}
----
Or, if a custom ordering is not needed:
[source,rust,diff-id=1,diff-type=compliant]
----
#[derive(Ord, PartialOrd, PartialEq, Eq)]
struct Foo; // Compliant: Both Ord and PartialOrd are derived.
----
== Resources
=== Documentation
* Clippy Lints - https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord