diff --git a/rules/S7417/metadata.json b/rules/S7417/metadata.json new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/rules/S7417/metadata.json @@ -0,0 +1,2 @@ +{ +} diff --git a/rules/S7417/rust/metadata.json b/rules/S7417/rust/metadata.json new file mode 100644 index 0000000000..57b0556971 --- /dev/null +++ b/rules/S7417/rust/metadata.json @@ -0,0 +1,24 @@ +{ + "title": "Manual PartialOrd implementation should be avoided when Ord is derived", + "type": "BUG", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + "clippy" + ], + "defaultSeverity": "Critical", + "ruleSpecification": "RSPEC-7417", + "sqKey": "S7417", + "scope": "All", + "defaultQualityProfiles": ["Sonar way"], + "quickfix": "unknown", + "code": { + "impacts": { + "RELIABILITY": "HIGH" + }, + "attribute": "LOGICAL" + } +} diff --git a/rules/S7417/rust/rule.adoc b/rules/S7417/rust/rule.adoc new file mode 100644 index 0000000000..d9735824c1 --- /dev/null +++ b/rules/S7417/rust/rule.adoc @@ -0,0 +1,59 @@ + +== 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 { + 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 { + 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