Create rule S7125
This commit is contained in:
parent
0445ff0a80
commit
d66e6407d5
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"title": "FIXME",
|
"title": "Null values should not be used in non-nullable input positions",
|
||||||
"type": "CODE_SMELL",
|
"type": "CODE_SMELL",
|
||||||
"status": "ready",
|
"status": "ready",
|
||||||
"remediation": {
|
"remediation": {
|
||||||
@ -11,14 +11,12 @@
|
|||||||
"defaultSeverity": "Major",
|
"defaultSeverity": "Major",
|
||||||
"ruleSpecification": "RSPEC-7125",
|
"ruleSpecification": "RSPEC-7125",
|
||||||
"sqKey": "S7125",
|
"sqKey": "S7125",
|
||||||
"scope": "All",
|
"scope": "Main",
|
||||||
"defaultQualityProfiles": ["Sonar way"],
|
"defaultQualityProfiles": ["Sonar way"],
|
||||||
"quickfix": "unknown",
|
"quickfix": "unknown",
|
||||||
"code": {
|
"code": {
|
||||||
"impacts": {
|
"impacts": {
|
||||||
"MAINTAINABILITY": "HIGH",
|
"RELIABILITY": "HIGH"
|
||||||
"RELIABILITY": "MEDIUM",
|
|
||||||
"SECURITY": "LOW"
|
|
||||||
},
|
},
|
||||||
"attribute": "CONVENTIONAL"
|
"attribute": "CONVENTIONAL"
|
||||||
}
|
}
|
||||||
|
@ -1,44 +1,123 @@
|
|||||||
FIXME: add a description
|
|
||||||
|
|
||||||
// If you want to factorize the description uncomment the following line and create the file.
|
|
||||||
//include::../description.adoc[]
|
|
||||||
|
|
||||||
== Why is this an issue?
|
== Why is this an issue?
|
||||||
|
|
||||||
FIXME: remove the unused optional headers (that are commented out)
|
Using `null` in a non-nullable input position (e.g., as the right-hand side of an assignment, a function call argument, or a return statement argument) can lead to a NullPointerException (NPE) at runtime. This occurs because the receiving code typically assumes the value is non-null and omits null checks.
|
||||||
|
|
||||||
//=== What is the potential impact?
|
Formally, non-nullable and nullable versions of a type are distinct, with different domains.
|
||||||
|
The domain of a non-nullable type is _D_, while the domain of a nullable type is _D ∪ null_, a superset of _D_.
|
||||||
|
Thus, a non-null value can be used wherever a nullable type is expected, but not vice versa.
|
||||||
|
The only reason it's allowed by the compiler is that null-safety is not a built-in Java language feature, and it's therefore handled via nullability annotations by external tools bypassing the regular typing system.
|
||||||
|
|
||||||
== How to fix it
|
== How to fix it
|
||||||
//== How to fix it in FRAMEWORK NAME
|
|
||||||
|
Depending on the use-case, there are different strategies to fix this problem
|
||||||
|
|
||||||
=== Code examples
|
=== Code examples
|
||||||
|
|
||||||
|
**1. Change the input position type from non-nullable to nullable:** This resolves the issue at the reported location but may propagate it elsewhere. Note: you should avoid declaring everything nullable; only do so where it aligns with your data and state models. Otherwise, consider the other approaches.
|
||||||
|
|
||||||
==== Noncompliant code example
|
==== Noncompliant code example
|
||||||
|
|
||||||
[source,java,diff-id=1,diff-type=noncompliant]
|
[source,java,diff-id=1,diff-type=noncompliant]
|
||||||
----
|
----
|
||||||
FIXME
|
@NonNull String title = null;
|
||||||
----
|
----
|
||||||
|
|
||||||
==== Compliant solution
|
==== Compliant solution
|
||||||
|
|
||||||
[source,java,diff-id=1,diff-type=compliant]
|
[source,java,diff-id=1,diff-type=compliant]
|
||||||
----
|
----
|
||||||
FIXME
|
String title = null;
|
||||||
----
|
----
|
||||||
|
|
||||||
//=== How does this work?
|
==== Noncompliant code example
|
||||||
|
|
||||||
//=== Pitfalls
|
[source,java,diff-id=2,diff-type=noncompliant]
|
||||||
|
----
|
||||||
|
@NullMarked
|
||||||
|
class Collector {
|
||||||
|
void collectData(List<Entity> entities) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//=== Going the extra mile
|
void process() {
|
||||||
|
collector.collectData(null);
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
==== Compliant solution
|
||||||
|
|
||||||
//== Resources
|
[source,java,diff-id=2,diff-type=compliant]
|
||||||
//=== Documentation
|
----
|
||||||
//=== Articles & blog posts
|
class Collector {
|
||||||
//=== Conference presentations
|
void collectData(List<Entity> entities) {
|
||||||
//=== Standards
|
// ...
|
||||||
//=== External coding guidelines
|
}
|
||||||
//=== Benchmarks
|
}
|
||||||
|
|
||||||
|
void process() {
|
||||||
|
collector.collectData(null);
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
**2. Replace `null` with a Guard Element:** This is particularly effective for array and collection types, where `null` can easily be replaced with an empty array or collection instance.
|
||||||
|
|
||||||
|
==== Noncompliant code example
|
||||||
|
|
||||||
|
[source,java,diff-id=3,diff-type=noncompliant]
|
||||||
|
----
|
||||||
|
@NullMarked
|
||||||
|
class Collector {
|
||||||
|
void collectData(List<Entity> entities) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void process() {
|
||||||
|
collector.collectData(null);
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
==== Compliant solution
|
||||||
|
|
||||||
|
[source,java,diff-id=3,diff-type=compliant]
|
||||||
|
----
|
||||||
|
@NullMarked
|
||||||
|
class Collector {
|
||||||
|
void collectData(List<Entity> entities) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void process() {
|
||||||
|
collector.collectData(List.of());
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
**3. Throw an Exception:** For unexpected or uninitialized values or unspecified behavior, throw an exception instead of returning `null`. This reports the issue at its origin, not somewhere else in the source code where the unexpected `null` value suddenly becomes a problem. This makes debugging easier.
|
||||||
|
|
||||||
|
==== Noncompliant code example
|
||||||
|
|
||||||
|
[source,java,diff-id=4,diff-type=noncompliant]
|
||||||
|
----
|
||||||
|
@NonNull State getNextState() {
|
||||||
|
return switch (state) {
|
||||||
|
case State.PENDING -> State.PROCESSING;
|
||||||
|
case State.PROCESSING -> State.PENDING;
|
||||||
|
default -> null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
==== Compliant solution
|
||||||
|
|
||||||
|
[source,java,diff-id=4,diff-type=compliant]
|
||||||
|
----
|
||||||
|
@NonNull State getNextState() {
|
||||||
|
return switch (state) {
|
||||||
|
case State.PENDING -> State.PROCESSING;
|
||||||
|
case State.PROCESSING -> State.PENDING;
|
||||||
|
default -> throw new IllegalStateException();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
----
|
||||||
|
Loading…
x
Reference in New Issue
Block a user