C#: Update nullness qltest

This commit is contained in:
Anders Schack-Mulligen
2025-10-02 13:54:49 +02:00
parent 64810f6fb5
commit df6172b1f3
6 changed files with 149 additions and 1049 deletions

View File

@@ -14,7 +14,7 @@ public class D
public void Caller()
{
Callee1(new object());
Callee1(null); // $ Source[cs/dereferenced-value-may-be-null]
Callee1(null);
Callee2(new object());
}
@@ -23,7 +23,7 @@ public class D
param.ToString(); // $ Alert[cs/dereferenced-value-may-be-null]
}
public void Callee2(object param) // $ Source[cs/dereferenced-value-may-be-null]
public void Callee2(object param)
{
if (param != null)
{
@@ -55,24 +55,24 @@ public class D
if ((2 > 1 && o4 != null) != false)
o4.ToString(); // GOOD
var o5 = (o4 != null) ? "" : null; // $ Source[cs/dereferenced-value-may-be-null]
var o5 = (o4 != null) ? "" : null;
if (o5 != null)
o4.ToString(); // GOOD
if (o4 != null)
o5.ToString(); // $ SPURIOUS (false positive): Alert[cs/dereferenced-value-may-be-null]
o5.ToString(); // GOOD
var o6 = maybe ? null : "";
if (!CustomIsNull(o6))
o6.ToString(); // GOOD
var o7 = maybe ? null : ""; // $ Source[cs/dereferenced-value-may-be-null]
var o7 = maybe ? null : "";
var ok = o7 != null && 2 > 1;
if (ok)
o7.ToString(); // GOOD
else
o7.ToString(); // $ Alert[cs/dereferenced-value-may-be-null]
var o8 = maybe ? null : ""; // $ Source[cs/dereferenced-value-may-be-null]
var o8 = maybe ? null : "";
int track = o8 == null ? 42 : 1 + 1;
if (track == 2)
o8.ToString(); // GOOD
@@ -86,7 +86,7 @@ public class D
public void Deref(int i)
{
int[] xs = maybe ? null : new int[2]; // $ Source[cs/dereferenced-value-may-be-null]
int[] xs = maybe ? null : new int[2];
if (i > 1)
xs[0] = 5; // $ Alert[cs/dereferenced-value-may-be-null]
@@ -122,7 +122,7 @@ public class D
x.ToString(); // GOOD
}
public void LengthGuard(int[] a, int[] b) // $ Source[cs/dereferenced-value-may-be-null]
public void LengthGuard(int[] a, int[] b)
{
int alen = a == null ? 0 : a.Length; // GOOD
int blen = b == null ? 0 : b.Length; // GOOD
@@ -146,7 +146,7 @@ public class D
}
}
public void MissedGuard(object obj) // $ Source[cs/dereferenced-value-may-be-null]
public void MissedGuard(object obj)
{
obj.ToString(); // $ Alert[cs/dereferenced-value-may-be-null]
var x = obj != null ? 1 : 0;
@@ -160,7 +160,7 @@ public class D
public void Exceptions()
{
object obj = null; // $ Source[cs/dereferenced-value-may-be-null]
object obj = null;
try
{
obj = MkMaybe();
@@ -237,16 +237,16 @@ public class D
if (flag)
o.ToString(); // GOOD
o = null; // $ Source[cs/dereferenced-value-may-be-null]
o = null;
var other = maybe ? null : "";
if (other == null)
o = "";
if (other != null)
o.ToString(); // $ Alert[cs/dereferenced-value-may-be-null] (always - but reported as maybe)
else
o.ToString(); // $ SPURIOUS (false positive): Alert[cs/dereferenced-value-may-be-null]
o.ToString(); // GOOD
var o2 = (num < 0) ? null : ""; // $ Source[cs/dereferenced-value-may-be-null]
var o2 = (num < 0) ? null : "";
if (num < 0)
o2 = "";
else
@@ -255,7 +255,7 @@ public class D
public void TrackingVariable(int[] a)
{
object o = null; // $ Source[cs/dereferenced-value-may-be-null]
object o = null;
object other = null;
if (maybe)
{
@@ -264,9 +264,9 @@ public class D
}
if (other is string)
o.ToString(); // $ SPURIOUS (false positive): Alert[cs/dereferenced-value-may-be-null]
o.ToString(); // GOOD
o = null; // $ Source[cs/dereferenced-value-may-be-null]
o = null;
int count = 0;
var found = false;
for (var i = 0; i < a.Length; i++)
@@ -280,7 +280,7 @@ public class D
}
if (a[i] > 10000)
{
o = null; // $ Source[cs/dereferenced-value-may-be-null]
o = null;
count = 0;
if (2 > i) { }
found = false;
@@ -291,17 +291,17 @@ public class D
o.ToString(); // $ SPURIOUS (false positive): Alert[cs/dereferenced-value-may-be-null]
if (found)
o.ToString(); // $ SPURIOUS (false positive): Alert[cs/dereferenced-value-may-be-null]
o.ToString(); // GOOD
object prev = null; // $ Source[cs/dereferenced-value-may-be-null]
object prev = null;
for (var i = 0; i < a.Length; ++i)
{
if (i != 0)
prev.ToString(); // $ SPURIOUS (false positive): Alert[cs/dereferenced-value-may-be-null]
prev.ToString(); // GOOD
prev = a[i];
}
string s = null; // $ Source[cs/dereferenced-value-may-be-null]
string s = null;
{
var s_null = true;
foreach (var i in a)
@@ -310,10 +310,10 @@ public class D
s = "" + a;
}
if (!s_null)
s.ToString(); // $ SPURIOUS (false positive): Alert[cs/dereferenced-value-may-be-null]
s.ToString(); // GOOD
}
object r = null; // $ Source[cs/dereferenced-value-may-be-null]
object r = null;
var stat = MyStatus.INIT;
while (stat == MyStatus.INIT && stat != MyStatus.READY)
{
@@ -321,7 +321,7 @@ public class D
if (stat == MyStatus.INIT)
stat = MyStatus.READY;
}
r.ToString(); // $ SPURIOUS (false positive): Alert[cs/dereferenced-value-may-be-null]
r.ToString(); // GOOD
}
public enum MyStatus
@@ -348,7 +348,7 @@ public class D
public void LoopCorr(int iters)
{
int[] a = null; // $ Source[cs/dereferenced-value-may-be-null]
int[] a = null;
if (iters > 0)
a = new int[iters];
@@ -357,13 +357,13 @@ public class D
if (iters > 0)
{
string last = null; // $ Source[cs/dereferenced-value-may-be-null]
string last = null;
for (var i = 0; i < iters; i++)
last = "abc";
last.ToString(); // $ SPURIOUS (false positive): Alert[cs/dereferenced-value-may-be-null]
}
int[] b = maybe ? null : new int[iters]; // $ Source[cs/dereferenced-value-may-be-null]
int[] b = maybe ? null : new int[iters];
if (iters > 0 && (b == null || b.Length < iters))
throw new Exception();
@@ -385,7 +385,7 @@ public class D
ioe.ToString(); // $ Alert[cs/dereferenced-value-is-always-null]
}
public void LengthGuard2(int[] a, int[] b) // $ Source[cs/dereferenced-value-may-be-null]
public void LengthGuard2(int[] a, int[] b)
{
int alen = a == null ? 0 : a.Length; // GOOD
int sum = 0;
@@ -402,13 +402,13 @@ public class D
i = -3;
}
public void CorrConds2(object x, object y) // $ Source[cs/dereferenced-value-may-be-null]
public void CorrConds2(object x, object y)
{
if ((x != null && y == null) || (x == null && y != null))
return;
if (x != null)
y.ToString(); // $ SPURIOUS (false positive): Alert[cs/dereferenced-value-may-be-null]
y.ToString(); // GOOD
if (y != null)
x.ToString(); // $ SPURIOUS (false positive): Alert[cs/dereferenced-value-may-be-null]
x.ToString(); // GOOD
}
}

View File

@@ -6,9 +6,9 @@ public class E
{
public void Ex1(long[][][] a1, int ix, int len)
{
long[][] a2 = null; // $ Source[cs/dereferenced-value-may-be-null]
long[][] a2 = null;
var haveA2 = ix < len && (a2 = a1[ix]) != null;
long[] a3 = null; // $ Source[cs/dereferenced-value-may-be-null]
long[] a3 = null;
var haveA3 = haveA2 && (a3 = a2[ix]) != null; // $ SPURIOUS (false positive): Alert[cs/dereferenced-value-may-be-null]
if (haveA3)
a3[0] = 0; // $ SPURIOUS (false positive): Alert[cs/dereferenced-value-may-be-null]
@@ -20,7 +20,7 @@ public class E
var s2 = (s1 == null) ? null : "";
if (s2 == null)
{
s1 = y ? null : ""; // $ Source[cs/dereferenced-value-may-be-null]
s1 = y ? null : "";
s2 = (s1 == null) ? null : "";
}
if (s2 != null)
@@ -32,7 +32,7 @@ public class E
string last = null;
foreach (var s in new string[] { "aa", "bb" })
last = s;
last.ToString(); // GOOD
last.ToString(); // $ SPURIOUS (false positive): Alert[cs/dereferenced-value-may-be-null]
last = null;
if (ss.Any())
@@ -40,7 +40,7 @@ public class E
foreach (var s in ss)
last = s;
last.ToString(); // GOOD
last.ToString(); // $ SPURIOUS (false positive): Alert[cs/dereferenced-value-may-be-null]
}
}
@@ -48,7 +48,7 @@ public class E
{
int index = 0;
var result = new List<List<string>>();
List<string> slice = null; // $ Source[cs/dereferenced-value-may-be-null]
List<string> slice = null;
var iter = list.GetEnumerator();
while (iter.MoveNext())
{
@@ -63,7 +63,7 @@ public class E
}
}
public void Ex5(bool hasArr, int[] arr) // $ Source[cs/dereferenced-value-may-be-null]
public void Ex5(bool hasArr, int[] arr)
{
int arrLen = 0;
if (hasArr)
@@ -104,7 +104,7 @@ public class E
public void Ex7(int[] arr1)
{
int[] arr2 = null; // $ Source[cs/dereferenced-value-may-be-null]
int[] arr2 = null;
if (arr1.Length > 0)
arr2 = new int[arr1.Length];
@@ -122,7 +122,7 @@ public class E
int j = 0;
while (!stop && j < lim)
{
int step = (j * obj.GetHashCode()) % 10; // $ SPURIOUS (false positive): Alert[cs/dereferenced-value-may-be-null]
int step = (j * obj.GetHashCode()) % 10; // GOOD
if (step == 0)
{
obj.ToString(); // GOOD
@@ -134,7 +134,7 @@ public class E
}
else
{
obj = null; // $ Source[cs/dereferenced-value-may-be-null]
obj = null;
}
continue;
}
@@ -149,17 +149,17 @@ public class E
{
return;
}
object obj2 = obj1; // $ Source[cs/dereferenced-value-may-be-null]
object obj2 = obj1;
if (obj2 != null && obj2.GetHashCode() % 5 > 2)
{
obj2.ToString(); // GOOD
cond = true;
}
if (cond)
obj2.ToString(); // $ SPURIOUS (false positive): Alert[cs/dereferenced-value-may-be-null]
obj2.ToString(); // GOOD
}
public void Ex10(int[] a) // $ Source[cs/dereferenced-value-may-be-null]
public void Ex10(int[] a)
{
int n = a == null ? 0 : a.Length;
for (var i = 0; i < n; i++)
@@ -170,12 +170,12 @@ public class E
}
}
public void Ex11(object obj, bool b1) // $ Source[cs/dereferenced-value-may-be-null]
public void Ex11(object obj, bool b1)
{
bool b2 = obj == null ? false : b1;
if (b2 == null)
{
obj.ToString(); // $ SPURIOUS (false positive): Alert[cs/dereferenced-value-may-be-null]
obj.ToString(); // GOOD
}
if (obj == null)
{
@@ -183,11 +183,11 @@ public class E
}
if (b1 == null)
{
obj.ToString(); // $ SPURIOUS (false positive): Alert[cs/dereferenced-value-may-be-null]
obj.ToString(); // GOOD
}
}
public void Ex12(object o) // $ Source[cs/dereferenced-value-may-be-null]
public void Ex12(object o)
{
var i = o.GetHashCode(); // $ Alert[cs/dereferenced-value-may-be-null]
var s = o?.ToString();
@@ -195,12 +195,12 @@ public class E
public void Ex13(bool b)
{
var o = b ? null : ""; // $ Source[cs/dereferenced-value-may-be-null]
o.M1(); // GOOD
var o = b ? null : "";
o.M1(); // GOOD (because M1 doesn't deref o)
if (b)
o.M2(); // $ Alert[cs/dereferenced-value-may-be-null]
else
o.Select(x => x); // $ Alert[cs/dereferenced-value-may-be-null]
o.Select(x => x); // GOOD
}
public int Ex14(string s)
@@ -214,28 +214,28 @@ public class E
{
var x = "";
if (b)
x = null; // $ Source[cs/dereferenced-value-may-be-null]
x = null;
x.ToString(); // $ Alert[cs/dereferenced-value-may-be-null]
if (b)
x.ToString(); // $ Alert[cs/dereferenced-value-is-always-null]
x.ToString(); // dominated by prior deref, i.e. not reported
}
public void Ex16(bool b)
{
var x = "";
if (b)
x = null; // $ Source[cs/dereferenced-value-may-be-null]
x = null;
if (b)
x.ToString(); // $ Alert[cs/dereferenced-value-is-always-null]
x.ToString(); // $ Alert[cs/dereferenced-value-may-be-null]
x.ToString(); // $ Alert[cs/dereferenced-value-may-be-null]
x.ToString(); // "dominated" by prior deref, i.e. not reported
}
public int Ex17(int? i) // $ Source[cs/dereferenced-value-may-be-null]
public int Ex17(int? i)
{
return i.Value; // $ Alert[cs/dereferenced-value-may-be-null]
}
public int Ex18(int? i) // $ Source[cs/dereferenced-value-may-be-null]
public int Ex18(int? i)
{
return (int)i; // $ Alert[cs/dereferenced-value-may-be-null]
}
@@ -280,7 +280,7 @@ public class E
{
if (b)
b.ToString();
var o = Make(); // $ Source[cs/dereferenced-value-may-be-null]
var o = Make();
o?.ToString();
o.ToString(); // $ Alert[cs/dereferenced-value-may-be-null]
if (b)
@@ -298,7 +298,7 @@ public class E
public void Ex25(object o)
{
var s = o as string; // $ Source[cs/dereferenced-value-may-be-null]
var s = o as string;
s.ToString(); // $ Alert[cs/dereferenced-value-may-be-null]
}
@@ -339,13 +339,13 @@ public class E
static void Ex30(string s, object o)
{
var x = s ?? o as string; // $ Source[cs/dereferenced-value-may-be-null]
var x = s ?? o as string;
x.ToString(); // $ Alert[cs/dereferenced-value-may-be-null]
}
static void Ex31(string s, object o)
{
dynamic x = s ?? o as string; // $ Source[cs/dereferenced-value-may-be-null]
dynamic x = s ?? o as string;
x.ToString(); // $ Alert[cs/dereferenced-value-may-be-null]
}
@@ -371,19 +371,19 @@ public class E
{
if (o is string)
{
var s = o as string; // $ Source[cs/dereferenced-value-may-be-null]
var s = o as string;
return s.Length; // $ SPURIOUS (false positive): Alert[cs/dereferenced-value-may-be-null]
}
return -1;
}
static bool Ex37(E e1, E e2) // $ Source[cs/dereferenced-value-may-be-null]
static bool Ex37(E e1, E e2)
{
if ((e1 == null && e2 != null) || (e1 != null && e2 == null))
return false;
if (e1 == null && e2 == null)
return true;
return e1.Long == e2.Long; // $ SPURIOUS (false positive): Alert[cs/dereferenced-value-may-be-null]
return e1.Long == e2.Long; // GOOD
}
int Ex38(int? i)
@@ -432,24 +432,24 @@ public class E
return @is.Any();
}
static void Ex45(string s) // $ Source[cs/dereferenced-value-may-be-null]
static void Ex45(string s, int i)
{
if (s is null)
if (i == 0 && s is null)
{
s.ToString(); // $ Alert[cs/dereferenced-value-is-always-null]
}
if (s is not not null)
if (i == 1 && s is not not null)
{
s.ToString(); // $ Alert[cs/dereferenced-value-may-be-null] MISSING: Alert[cs/dereferenced-value-is-always-null]
}
if (s is not null)
if (i == 2 && s is not null)
{
s.ToString(); // GOOD
}
if (s is object)
if (i == 3 && s is object)
{
s.ToString(); // GOOD
}

View File

@@ -244,8 +244,16 @@
| E.cs:423:33:423:44 | ... == ... | true | E.cs:423:38:423:44 | access to property Value | E.cs:423:33:423:33 | access to parameter j |
| E.cs:430:34:430:45 | ... == ... | true | E.cs:430:34:430:34 | access to parameter j | E.cs:430:39:430:45 | access to property Value |
| E.cs:430:34:430:45 | ... == ... | true | E.cs:430:39:430:45 | access to property Value | E.cs:430:34:430:34 | access to parameter j |
| E.cs:437:13:437:21 | ... is ... | true | E.cs:437:13:437:13 | access to parameter s | E.cs:437:18:437:21 | null |
| E.cs:437:13:437:21 | ... is ... | true | E.cs:437:18:437:21 | null | E.cs:437:13:437:13 | access to parameter s |
| E.cs:437:13:437:18 | ... == ... | true | E.cs:437:13:437:13 | access to parameter i | E.cs:437:18:437:18 | 0 |
| E.cs:437:13:437:18 | ... == ... | true | E.cs:437:18:437:18 | 0 | E.cs:437:13:437:13 | access to parameter i |
| E.cs:437:23:437:31 | ... is ... | true | E.cs:437:23:437:23 | access to parameter s | E.cs:437:28:437:31 | null |
| E.cs:437:23:437:31 | ... is ... | true | E.cs:437:28:437:31 | null | E.cs:437:23:437:23 | access to parameter s |
| E.cs:442:13:442:18 | ... == ... | true | E.cs:442:13:442:13 | access to parameter i | E.cs:442:18:442:18 | 1 |
| E.cs:442:13:442:18 | ... == ... | true | E.cs:442:18:442:18 | 1 | E.cs:442:13:442:13 | access to parameter i |
| E.cs:447:13:447:18 | ... == ... | true | E.cs:447:13:447:13 | access to parameter i | E.cs:447:18:447:18 | 2 |
| E.cs:447:13:447:18 | ... == ... | true | E.cs:447:18:447:18 | 2 | E.cs:447:13:447:13 | access to parameter i |
| E.cs:452:13:452:18 | ... == ... | true | E.cs:452:13:452:13 | access to parameter i | E.cs:452:18:452:18 | 3 |
| E.cs:452:13:452:18 | ... == ... | true | E.cs:452:18:452:18 | 3 | E.cs:452:13:452:13 | access to parameter i |
| Forwarding.cs:59:13:59:21 | ... == ... | true | Forwarding.cs:59:13:59:13 | access to parameter o | Forwarding.cs:59:18:59:21 | null |
| Forwarding.cs:59:13:59:21 | ... == ... | true | Forwarding.cs:59:18:59:21 | null | Forwarding.cs:59:13:59:13 | access to parameter o |
| Forwarding.cs:78:16:78:39 | call to method ReferenceEquals | true | Forwarding.cs:78:32:78:32 | access to parameter o | Forwarding.cs:78:35:78:38 | null |

View File

@@ -31,8 +31,6 @@
| D.cs:222:13:222:14 | access to local variable o4 | Variable $@ is always null at this dereference. | D.cs:220:13:220:14 | o4 | o4 |
| D.cs:385:13:385:15 | access to local variable ioe | Variable $@ is always null at this dereference. | D.cs:378:19:378:21 | ioe | ioe |
| E.cs:210:16:210:16 | access to parameter s | Variable $@ is always null at this dereference. | E.cs:206:28:206:28 | s | s |
| E.cs:220:13:220:13 | access to local variable x | Variable $@ is always null at this dereference. | E.cs:215:13:215:13 | x | x |
| E.cs:229:13:229:13 | access to local variable x | Variable $@ is always null at this dereference. | E.cs:225:13:225:13 | x | x |
| E.cs:323:13:323:14 | access to parameter s1 | Variable $@ is always null at this dereference. | E.cs:319:29:319:30 | s1 | s1 |
| E.cs:324:13:324:14 | access to parameter s2 | Variable $@ is always null at this dereference. | E.cs:319:40:319:41 | s2 | s2 |
| E.cs:331:9:331:9 | access to local variable x | Variable $@ is always null at this dereference. | E.cs:330:13:330:13 | x | x |

View File

@@ -298,11 +298,11 @@
| E.cs:422:13:422:22 | access to property HasValue | E.cs:422:13:422:13 | access to parameter i | true | false |
| E.cs:429:13:429:22 | access to property HasValue | E.cs:429:13:429:13 | access to parameter i | false | true |
| E.cs:429:13:429:22 | access to property HasValue | E.cs:429:13:429:13 | access to parameter i | true | false |
| E.cs:437:13:437:21 | ... is ... | E.cs:437:13:437:13 | access to parameter s | false | false |
| E.cs:437:13:437:21 | ... is ... | E.cs:437:13:437:13 | access to parameter s | true | true |
| E.cs:442:13:442:29 | ... is ... | E.cs:442:13:442:13 | access to parameter s | false | false |
| E.cs:447:13:447:25 | ... is ... | E.cs:447:13:447:13 | access to parameter s | true | false |
| E.cs:452:13:452:23 | ... is ... | E.cs:452:13:452:13 | access to parameter s | true | false |
| E.cs:437:23:437:31 | ... is ... | E.cs:437:23:437:23 | access to parameter s | false | false |
| E.cs:437:23:437:31 | ... is ... | E.cs:437:23:437:23 | access to parameter s | true | true |
| E.cs:442:23:442:39 | ... is ... | E.cs:442:23:442:23 | access to parameter s | false | false |
| E.cs:447:23:447:35 | ... is ... | E.cs:447:23:447:23 | access to parameter s | true | false |
| E.cs:452:23:452:33 | ... is ... | E.cs:452:23:452:23 | access to parameter s | true | false |
| E.cs:457:13:457:27 | ... is ... | E.cs:457:13:457:13 | access to parameter s | false | false |
| Forwarding.cs:9:14:9:30 | call to method IsNullOrEmpty | Forwarding.cs:9:14:9:14 | access to local variable s | false | false |
| Forwarding.cs:14:13:14:32 | call to method IsNotNullOrEmpty | Forwarding.cs:14:13:14:13 | access to local variable s | true | false |

File diff suppressed because it is too large Load Diff