Skip to content

Commit 038c23d

Browse files
committed
Create rule S7125
1 parent 0445ff0 commit 038c23d

File tree

2 files changed

+103
-28
lines changed

2 files changed

+103
-28
lines changed

rules/S7125/java/metadata.json

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"title": "FIXME",
2+
"title": "Null values should not be used in non-nullable input positions",
33
"type": "CODE_SMELL",
44
"status": "ready",
55
"remediation": {
@@ -11,14 +11,12 @@
1111
"defaultSeverity": "Major",
1212
"ruleSpecification": "RSPEC-7125",
1313
"sqKey": "S7125",
14-
"scope": "All",
14+
"scope": "Main",
1515
"defaultQualityProfiles": ["Sonar way"],
1616
"quickfix": "unknown",
1717
"code": {
1818
"impacts": {
19-
"MAINTAINABILITY": "HIGH",
20-
"RELIABILITY": "MEDIUM",
21-
"SECURITY": "LOW"
19+
"RELIABILITY": "HIGH"
2220
},
2321
"attribute": "CONVENTIONAL"
2422
}

rules/S7125/java/rule.adoc

Lines changed: 100 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,121 @@
1-
FIXME: add a description
2-
3-
// If you want to factorize the description uncomment the following line and create the file.
4-
//include::../description.adoc[]
5-
61
== Why is this an issue?
72

8-
FIXME: remove the unused optional headers (that are commented out)
3+
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.
94

10-
//=== What is the potential impact?
5+
Formally, non-nullable and nullable versions of a type are distinct, with different domains.
6+
The domain of a non-nullable type is _D_, while the domain of a nullable type is _D ∪ null_, a superset of _D_.
7+
Thus, a non-null value can be used wherever a nullable type is expected, but not vice versa.
8+
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.
119

1210
== How to fix it
13-
//== How to fix it in FRAMEWORK NAME
1411

15-
=== Code examples
12+
Depending on the use-case, there are different strategies to fix this problem:
1613

17-
==== Noncompliant code example
14+
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.
15+
16+
=== Noncompliant code example
1817

1918
[source,java,diff-id=1,diff-type=noncompliant]
2019
----
21-
FIXME
20+
@NonNull String title = null;
2221
----
2322

24-
==== Compliant solution
23+
=== Compliant solution
2524

2625
[source,java,diff-id=1,diff-type=compliant]
2726
----
28-
FIXME
27+
String title = null;
28+
----
29+
30+
=== Noncompliant code example
31+
32+
[source,java,diff-id=2,diff-type=noncompliant]
33+
----
34+
@NullMarked
35+
class Collector {
36+
void collectData(List<Entity> entities) {
37+
// ...
38+
}
39+
}
40+
41+
void process() {
42+
collector.collectData(null);
43+
}
44+
----
45+
46+
=== Compliant solution
47+
48+
[source,java,diff-id=2,diff-type=compliant]
49+
----
50+
class Collector {
51+
void collectData(List<Entity> entities) {
52+
// ...
53+
}
54+
}
55+
56+
void process() {
57+
collector.collectData(null);
58+
}
59+
----
60+
61+
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.
62+
63+
=== Noncompliant code example
64+
65+
[source,java,diff-id=3,diff-type=noncompliant]
66+
----
67+
@NullMarked
68+
class Collector {
69+
void collectData(List<Entity> entities) {
70+
// ...
71+
}
72+
}
73+
74+
void process() {
75+
collector.collectData(null);
76+
}
77+
----
78+
79+
=== Compliant solution
80+
81+
[source,java,diff-id=3,diff-type=compliant]
2982
----
83+
@NullMarked
84+
class Collector {
85+
void collectData(List<Entity> entities) {
86+
// ...
87+
}
88+
}
3089
31-
//=== How does this work?
90+
void process() {
91+
collector.collectData(List.of());
92+
}
93+
----
3294

33-
//=== Pitfalls
95+
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.
3496

35-
//=== Going the extra mile
97+
=== Noncompliant code example
3698

99+
[source,java,diff-id=4,diff-type=noncompliant]
100+
----
101+
@NonNull State getNextState() {
102+
return switch (state) {
103+
case State.PENDING -> State.PROCESSING;
104+
case State.PROCESSING -> State.PENDING;
105+
default -> null;
106+
};
107+
}
108+
----
37109

38-
//== Resources
39-
//=== Documentation
40-
//=== Articles & blog posts
41-
//=== Conference presentations
42-
//=== Standards
43-
//=== External coding guidelines
44-
//=== Benchmarks
110+
=== Compliant solution
111+
112+
[source,java,diff-id=4,diff-type=compliant]
113+
----
114+
@NonNull State getNextState() {
115+
return switch (state) {
116+
case State.PENDING -> State.PROCESSING;
117+
case State.PROCESSING -> State.PENDING;
118+
default -> throw new IllegalStateException();
119+
};
120+
}
121+
----

0 commit comments

Comments
 (0)