What Happens
Calling LtUnlintNonExistingDefect.defects() on an EO file where +unlint uses a range pattern (name:line-line) and the referenced lint did not fire crashes with NullPointerException:
java.lang.NullPointerException:
Cannot invoke "java.util.List.stream()" because "lines" is null
at org.eolang.lints.DefectMissing.apply(DefectMissing.java:47)
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:178)
at java.base/java.util.stream.DistinctOps$1$2.accept(DistinctOps.java:174)
...
at org.eolang.lints.LtUnlintNonExistingDefect.defects(LtUnlintNonExistingDefect.java:86)
What Should Happen
Returns a non-empty collection reporting that the +unlint annotation references a non-existing defect — consistent with how non-range +unlint nonexistent behaves (works correctly).
Steps to Reproduce
new LtUnlintNonExistingDefect(
new ListOf<>(new LtAsciiOnly()),
new ListOf<>()
).defects(
new EoSyntax(
String.join(
"\n",
"+unlint ascii-only:1-5",
"[] > main",
" QQ.io.stdout > @",
" \"Hello\""
)
).parsed()
);
// throws NullPointerException instead of returning defects
The EO file has +unlint ascii-only:1-5 (range pattern), but ascii-only does not fire because there are no non-ASCII characters — so "ascii-only" is absent from the defects map.
Root Cause
DefectMissing.java:45 — this.defects.get(name) returns null when the lint name is absent from the map. Line 47 enters the range branch without a null-check and calls lines.stream():
final List<Integer> lines = this.defects.get(name); // null if name absent
if (unlint.matches(String.format("%s:\\d+-\\d+", name))) {
missing = !lines.stream().allMatch(new UnlintInRange(unlint)); // NPE
}
The existing tests in DefectMissingTest and LtUnlintNonExistingDefectTest only cover cases where the lint name exists in the defects map. The missing-key + range case has no coverage.
What Happens
Calling
LtUnlintNonExistingDefect.defects()on an EO file where+unlintuses a range pattern (name:line-line) and the referenced lint did not fire crashes withNullPointerException:What Should Happen
Returns a non-empty collection reporting that the
+unlintannotation references a non-existing defect — consistent with how non-range+unlint nonexistentbehaves (works correctly).Steps to Reproduce
The EO file has
+unlint ascii-only:1-5(range pattern), butascii-onlydoes not fire because there are no non-ASCII characters — so"ascii-only"is absent from the defects map.Root Cause
DefectMissing.java:45—this.defects.get(name)returnsnullwhen the lint name is absent from the map. Line 47 enters the range branch without a null-check and callslines.stream():The existing tests in
DefectMissingTestandLtUnlintNonExistingDefectTestonly cover cases where the lint name exists in the defects map. The missing-key + range case has no coverage.