Skip to content

Commit d66e640

Browse files
committed
Create rule S7125
1 parent 0445ff0 commit d66e640

File tree

2 files changed

+102
-25
lines changed

2 files changed

+102
-25
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: 99 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,123 @@
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
11+
12+
Depending on the use-case, there are different strategies to fix this problem
1413

1514
=== Code examples
1615

16+
**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.
17+
1718
==== Noncompliant code example
1819

1920
[source,java,diff-id=1,diff-type=noncompliant]
2021
----
21-
FIXME
22+
@NonNull String title = null;
2223
----
2324

2425
==== Compliant solution
2526

2627
[source,java,diff-id=1,diff-type=compliant]
2728
----
28-
FIXME
29+
String title = null;
30+
----
31+
32+
==== Noncompliant code example
33+
34+
[source,java,diff-id=2,diff-type=noncompliant]
35+
----
36+
@NullMarked
37+
class Collector {
38+
void collectData(List<Entity> entities) {
39+
// ...
40+
}
41+
}
42+
43+
void process() {
44+
collector.collectData(null);
45+
}
2946
----
3047

31-
//=== How does this work?
48+
==== Compliant solution
3249

33-
//=== Pitfalls
50+
[source,java,diff-id=2,diff-type=compliant]
51+
----
52+
class Collector {
53+
void collectData(List<Entity> entities) {
54+
// ...
55+
}
56+
}
3457
35-
//=== Going the extra mile
58+
void process() {
59+
collector.collectData(null);
60+
}
61+
----
3662

63+
**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.
3764

38-
//== Resources
39-
//=== Documentation
40-
//=== Articles & blog posts
41-
//=== Conference presentations
42-
//=== Standards
43-
//=== External coding guidelines
44-
//=== Benchmarks
65+
==== Noncompliant code example
66+
67+
[source,java,diff-id=3,diff-type=noncompliant]
68+
----
69+
@NullMarked
70+
class Collector {
71+
void collectData(List<Entity> entities) {
72+
// ...
73+
}
74+
}
75+
76+
void process() {
77+
collector.collectData(null);
78+
}
79+
----
80+
81+
==== Compliant solution
82+
83+
[source,java,diff-id=3,diff-type=compliant]
84+
----
85+
@NullMarked
86+
class Collector {
87+
void collectData(List<Entity> entities) {
88+
// ...
89+
}
90+
}
91+
92+
void process() {
93+
collector.collectData(List.of());
94+
}
95+
----
96+
97+
**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.
98+
99+
==== Noncompliant code example
100+
101+
[source,java,diff-id=4,diff-type=noncompliant]
102+
----
103+
@NonNull State getNextState() {
104+
return switch (state) {
105+
case State.PENDING -> State.PROCESSING;
106+
case State.PROCESSING -> State.PENDING;
107+
default -> null;
108+
};
109+
}
110+
----
111+
112+
==== Compliant solution
113+
114+
[source,java,diff-id=4,diff-type=compliant]
115+
----
116+
@NonNull State getNextState() {
117+
return switch (state) {
118+
case State.PENDING -> State.PROCESSING;
119+
case State.PROCESSING -> State.PENDING;
120+
default -> throw new IllegalStateException();
121+
};
122+
}
123+
----

0 commit comments

Comments
 (0)